3

I tried to open registry and modify it. This is how I open the registry:

HKEY hKey;
LPCTSTR subKey = TEXT("a registry subkey to be opened");
RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_ALL_ACCESS , &hKey);

But here is a problem, I want to use a QString to change the subkey pragmatically. And put the QString like this:

QString subKeyString = QString("%1").arg(subKeyName);
LPCTSTR subKey = TEXT(subKeyString); //but it's not working here

I thought it's because I did not change the QString to LPCTSTR, I tried this solution, but still I can't figure out a way to put a custom QString into the TEXT macro. I am not quite sure the WinApi under the hood, I just tried what I could possibly do.

Is there a way I can fix this problem?

Edit:
Here is how I convert QString to LPCTSTR:

QString testString = "converting QString to LPCSTR";
QByteArray testStringArr = testString.toLocal8Bit();
LPCSTR lp = LPCSTR(testStringArr.constData()); //the QString is converted to LPCTSTR
//but when I put the LPCSTR to the TEXT macro, the error is still there, like the next line below will not complie
LPCSTR lp = TEXT(LPCSTR(testStringArr.constData())); //This line will not work
Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
Theodore Tang
  • 831
  • 2
  • 21
  • 42
  • Look at https://stackoverflow.com/questions/28090577/how-to-convert-qstring-in-qt5-to-lpcstr-in-visual-studio-2013 – infixed Jun 25 '18 at 15:47
  • @infixed I did see some solutions like that, but I think that just convert `QString` to `LPCTSTR`, the problem for me is still there. I will edit my question, so you will know more clearly what error I encountered. – Theodore Tang Jun 25 '18 at 15:52
  • 2
    FYI the [QSettings](http://doc.qt.io/qt-5/qsettings.html) class offers some integration between Qt and the Windows Registry, though it may be applicable to your situation. – walkingTarget Jun 25 '18 at 15:55
  • @walkingTarget I tried using `QSettings` to modify the registry to what I need, but not working, except I use the native WinApi. So when I used the windows api, I met this problem. I edited my question, any solution? – Theodore Tang Jun 25 '18 at 16:02
  • `TEXT` is like `QStringLiteral`... the are to be used in the same circumstances: when you're passing in a string literal. – Kuba hasn't forgotten Monica Jun 25 '18 at 19:40

3 Answers3

6

The TEXT() macro only works with compile-time literals, not with runtime data. TCHAR and related APIs were designed to help people migrate their code from ANSI-based Win9x/ME to Unicode-based WinNT 4+, by mapping literals between char and wchar_t, and mapping function names between A and W variants. But those days are LONG gone.

The correct solution in this situation is to ignore TCHAR altogether and focus only on Unicode. A QString is a wrapper for a Unicode string. So use the Unicode-based Registry API functions only and pretend TCHAR doesn't exist.

On Windows, Unicode-based APIs expect UTF-16 encoded wchar_t strings. Use the QString::toStdWString() method to get a std::wstring, which is a C++ wrapper for a wchar_t string:

QString subKeyString = QString("%1").arg(subKeyName);
std::wstring subKey = subKeyString.toStdWString();
HKEY hKey;
RegOpenKeyExW(HKEY_LOCAL_MACHINE, subKey.c_str(), 0, KEY_ALL_ACCESS, &hKey);

Alternatively, you can use the QString::utf16() method. However, it returns a const ushort* pointer, so you will have to type-cast it to const wchar_t*:

QString subKeyString = QString("%1").arg(subKeyName);
LPCWSTR subKey = reinterpret_cast<LPCWSTR>(subKeyString.utf16());
HKEY hKey;
RegOpenKeyExW(HKEY_LOCAL_MACHINE, subKey, 0, KEY_ALL_ACCESS, &hKey);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Doesn't Paul's answer avoid the need to construct a `std::wstring`? (In the specific case of wanting to call a Windows API, certainly, here might be other reasons why you would want a `std::wstring`). – Paul Sanders Jun 25 '18 at 16:27
  • @PaulSanders Win32 Unicode APIs expect `wchar_t*` strings. `std::wstring` is a `wchar_t*` string wrapper, so it "just works". `utf16()` will also work, only because the Win32 API uses `wchar_t*` for UTF-16 on Windows. – Remy Lebeau Jun 25 '18 at 16:40
  • Sure, but still. Anyway, posted my own modest contribution. – Paul Sanders Jun 25 '18 at 19:46
4

TEXT macro was supposed to help maintaining both non-Unicode and Unicode versions of the app. Depending on whether _UNICODE (or UNICODE, don't remember already) is defined. TEXT("foo") would expand to either L"foo" or just "foo". Similarly, CreateWindow will be either CreateWindowW that takes WCHAR* parameters or CreateWindowA that takes CHAR* parameters.

Considering it is 2018 now, I suggest you forget about TEXT macro and non-Unicode versions of the app. QString::utf16() will return UTF16 strings that WinAPI expects. If you compile with "Native wchar_t" compiler setting, you will need to cast what utf16() returns to WCHAR*. If "Native wchar_t` is turned off, it will work as is.

Paul
  • 13,042
  • 3
  • 41
  • 59
  • 1
    The Win32 API uses `UNICODE`, `TCHAR`, and `TEXT()`. The C runtime library uses `_UNICODE`, `_TCHAR`, and `_T()`, respectively. – Remy Lebeau Jun 25 '18 at 16:36
  • @Remy I'm not sure I undersand that. As Paul says, all you need to do (depending on your compiler (flags) is to cast the pointer returned by `QString::utf16()` to a `WCHAR *`. Then you can pass it to any Win32 API call as you yourself show in your edit (and I would cast to `WCHAR *` rather than `wchar_t *` since that is how those API's are declared, although it doesn't actually matter in practice). – Paul Sanders Jun 25 '18 at 16:57
  • @PaulSanders that comment was in relation to the "Depending on whether `_UNICODE` (or `UNICODE`, don't remember already) is defined" portion of Paul's answer about the `TEXT` macro. That comment has nothing to do with Qt. Regarding Qt, if you use `QString::utf16()`, you have to type cast the returned pointer, as it is returned as a `const ushort*` instead of a `const wchar_t*`, which is what the Win32 API is expecting. Though both types are suitable for UTF-16 on Windows. – Remy Lebeau Jun 25 '18 at 19:25
  • @PaulSanders as for "Native wchar_t", Paul is referring to MSVC's [`/Zc:wchar_t` parameter](https://learn.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type). `QString::utf16()` returns a `const ushort*` pointer. If `/Zc:wchar_t` is enabled, `wchar_t` is a distinct data type, so you have to type-cast the `const ushort*` to `const wchar_t*` to use it with the Win32 API. But if `/Zc:wchar_t` is disabled, `wchar_t` is just an alias for `ushort`, so you can use the `const ushort*` as-is with the Win32 API. – Remy Lebeau Jun 25 '18 at 19:30
  • @Remy Oh right, sorry. I thought your first comment was addressed to me but clearly, it isn't. I will post a couple of utility functions which would take the pain out of the type casts. – Paul Sanders Jun 25 '18 at 19:33
2

I'm a bit late to the party perhaps, but to build on the other two answers, something as simple as this would oil the wheels:

inline const WCHAR *QStoWCHAR (const QString& qs)
{
    return (const WCHAR *) qs.utf16 ();
}

And then you can do (for example):

RegOpenKeyExW (HKEY_LOCAL_MACHINE, QStoWCHAR (my_qstring), 0, KEY_ALL_ACCESS, &hKey);
Paul Sanders
  • 24,133
  • 4
  • 26
  • 48