RegSetValueEx does not set in unicode project build - c++

I'm trying to write data to registry, but it always writes foreigner language instead because the setvalue is "MyApp"
CStringA temp(setvalue);//setvalue is CString type
const BYTE* pData = (const BYTE*)(LPCSTR)temp;
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)pData, sizeof(pData));
RegCloseKey(hKey);
if(lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
return true;
else
return false;
thanks.

The way you are converting CString to BYTE* is causing the problem. No need of using CStringA.
Try this conversion of CString to TCHAR. This should work
LPTSTR lpszData = new TCHAR[setvalue.GetLength()+1]; // setvalue is CString type...
_tcscpy(lpszData , csTemp);
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)lpszData, setvalue.GetLength()+1);
delete[] lpszData;// don't forget to do this.

Try RegSetValueExA(). You are calling a function which is expecting unicode strings. the A() function takes ANSI args

Any Win32 API function that accepts TCHAR, LPTSTR or LPCTSTR parameters will accept either Ansi or Unicode data depending on whether the UNICODE conditional is defined during compiling (RTL functions like _tcscpy use the _UNICODE conditional instead). So what's really happening in this case is that when you call RegSetValueEx() in your code, it gets resolved by the compiler to either calling RegSetValueExA() (Ansi) or RegSetValueExW() (Unicode) depending on the UNICODE conditional.
The CStringA class is for Ansi data only. You have to convert its data to Unicode when calling RegSetValueExW().
To do what you are attempting, you need to either:
1) call RegSetValueExA() explicitally instead of RegSetValueEx() generically if you contiinue using the CStringA class:
CStringA temp(setvalue);
lResult = RegSetValueExA(hKey, path, NULL, REG_SZ, (LPBYTE)(LPSTR)temp, (temp.GetLength() + 1) * sizeof(CHAR));
2) Use the CString class instead of the CStringA class. CString is based on TCHAR, so it is also influenced by the UNICODE conditional, and thus matches the format that RegSetValuEx() is expecting:
CString temp(setvalue);
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)(LPTSTR)temp, (temp.GetLength() + 1) * sizeof(TCHAR));
In the latter case, if your setvalue variable is already a CString, then just use it as-is, no need to create a temp copy of it:
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)(LPTSTR)setvalue, (setvalue.GetLength() + 1) * sizeof(TCHAR));

Related

C++ RegSetValueEx is giving problems

I'm using RegSetValueEx to set a Registry key. The problem is that it only writes the first 2 characters. I can get the RegSetValueExA (ANSI version) to work, but my Project is set to Unicode in properties so I would like to use either RegSetValueEx or RegSetValueExW.
#include <iostream>
#include <Windows.h>
HKEY hKey;
int main()
{
RegCreateKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\stuff", 0, NULL, NULL, KEY_ALL_ACCESS, NULL, &hKey, NULL);
RegSetValueEx(hKey, L"Test", 0, REG_SZ, (const BYTE*)L"test", strlen("test"));
system("PAUSE");
return 0;
}
Output in registry is "te" instead of "test".
The final parameter to RegSetValueEx has to be the size in bytes of the value, including the terminating null. You're giving the length in characters (and each character needs two bytes) and not including the null.
sizeof(L"test") would work, I think, or you could use (strlen("test")+1) * sizeof(wchar_t)
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx

LPCTSTR to LPCSTR conversion

I am trying to get information of existing file using GetFileInformationByHandle(). My function that performs the required task receives LPCTSTR Filename as argument. Here is the code:
getfileinfo(LPCTSTR Filename)
{
OFSTRUCT oo;
BY_HANDLE_FILE_INFORMATION lpFileInformation;
HFILE hfile=OpenFile((LPCSTR)Filename,&oo,OF_READ);
int err=GetLastError();
GetFileInfomationByHandle((HANDLE)hfile,&lpFileInformation);
}
Above code works fine if I declare Filename as LPCSTR but as per requirement of my function I receive the filename in LPCTSTR so if I use typecasting then openfile() cannot find the specified file and returns -1.
Can anyone tell me how to get file information if filename is LPCTSTR? Or how to convert LPCTSTR to LPCSTR.
Why is this typecasting not working? I believe this should work.
Just casting the pointer doesn't change the actual data (ie filename) that is being pointed to into eight-bit characters.
Reading the docs at MSDN suggests using CreateFile instead, which handles LPCTSTR filenames.
The solution to your immediate problem is to replace OpenFile() with CreateFile(), just like the OpenFile() documentation says to do:
Note This function has limited capabilities and is not recommended. For new application development, use the CreateFile function.
For example:
getfileinfo(LPCTSTR Filename)
{
HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
BY_HANDLE_FILE_INFORMATION FileInfo = {0};
BOOL ok = GetFileInformationByHandle(hFile, &FileInfo);
int err = GetLastError();
CloseHandle(hFile);
if (!ok)
{
// handle error as needed ...
}
else
{
// use FileInfo as needed...
}
}
}
That being said, a better solution is to not open the file at all. Most of the information that GetFileInformationByHandle() returns can be obtained using FindFirstFile() instead:
getfileinfo(LPCTSTR Filename)
{
WIN32_FIND_DATA FileData = {0};
HANDLE hFile = FindFirstFile(Filename, &FileData);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
FindClose(hFile);
// use FileData as needed ...
}
}
Have a look at Project Properties/Configuration Properties/General/Character Set. This is normally set to UNICODE. It can be changed to MBCS.
If it is set to MBCS, then the code does not need to be modified.
If it is set to Unicode, which I suspect it is otherwise you won't be asking this question, use widechartomultibyte to convert it from LPCTSTR (const wchar_t*) to LPSTR (const char*).

c++ RegCreateKeyEx LPCWSTR from std::string

I'm writting few operations in registry and I got stuck for two days at this. Really don't know how to solve that. So, its my code:
HKEY hkey;
DWORD dwDisposition;
string address = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
QString qAddr= ui->networkCard->itemData(ui->networkCard->currentIndex()).toString();
address += qAddr.toStdString();
string sAddr = qAddr.toStdString();
cout << address; // here is the value I want to proceed as 2nd arg in RegCreateKeyEx
size_t size = address.size();
wchar_t szBuff[size];
swprintf(szBuff, size, L"%s", address.c_str());
cout << szBuff << endl; // but after conversion I get some hex data like 0x28d172 :(
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuff, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &dwDisposition) == ERROR_SUCCESS){
DWORD dwType, dwSize;
dwType = REG_DWORD;
....
RegCreateKeyEx requires a LPCWSTR arg, but I really don't know how to do it from a std::string. Can u help me fixing this? :)
Thank you!
RegCreateKeyEx requires LPCWSTR only if your project is set to unicode. If you want a unicode project then use std::wstring instead of std::string. If you don't want a unicode project then change the project Character Set setting to Multi-Byte Character Set, which will let you use std::string.

How to convert LPWSTR* (or WCHAR*) to LPWSTR

I'm having a difficulty in converting a value to LPWSTR. I'm getting a registry value, and trying to return the result as LPWSTR. It appears the registry call using RegQueryValueExW works with a variety of types going in to store the result, but I can't cast any of them back to LPWSTR.
LPWSTR value;
HKEY hKey;
long result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"RegEntry1", 0, ACCESS|KEY_WOW64_32KEY, &hKey);
if (result == ERROR_SUCCESS)
{
//WCHAR buffer[512];
//TCHAR buffer[512];
LPWSTR buffer[512];
DWORD bufferSize = sizeof(buffer);
ULONG queryVal = 0;
queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//Access violation error here; I need some type of conversion.
value = buffer;
}
}
No posts that I've read on here so far have led me to an answer. C++ is not my primary dev language.
UPDATE: None of the proposed answers worked for me. I found an alternative way to do what I needed.
You don't want a buffer of LPWSTR, you want a buffer of wchar_t. A pointer to that will be LPWSTR as it's a typedef for wchar_t *.
These two lines from WinNT.h are relevant:
typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
Edit: I suspect the problem is with the part of the code you haven't shown us. Are you returning value from a function? If so then the problem is that you're returning a pointer to a buffer that has gone out of scope and been destroyed. I would return a std::wstring or CString instead.
Your buffer variable is declaring an array of 512 wchar_t* pointers when it should be declaring an array of 512 wchar_t characters instead. The first commented-out line of code is the correct code to use:
WCHAR buffer[512];
DWORD bufferSize = sizeof(buffer);
ULONG queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//...
}
Keep in mind that the buffer will not be null-terminated if the Registry value was not stored with its own null-terminator, so you should allocate some extra space for your own null terminator, just in case:
WCHAR buffer[512+1];
DWORD bufferSize = (sizeof(buffer) - sizeof(WCHAR));
LONG queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
buffer[bufferSize / sizeof(WCHAR)] = 0;
//...
}
Alternatively, use RegGetValue() instead, which handles the null terminator for you:
WCHAR buffer[512+1];
DWORD bufferSize = sizeof(buffer);
LONG queryVal = RegGetValueW(hKey, NULL, L"Path", RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ, NULL, buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//...
}

strange characters with RegQueryValueEx

I'm creating a NPAPI dll file and I need to get some information from the registry, but when I use RegQueryValueEx, I get some strange characters.
For instance, my computer model is "N310", but I get "Nfb1fb1" or "N$(".
I'm pretty sure that it's a charset issue, but I'm new with C++ and I need some help.
I'm using Visual Studio 2010 and my project is using the UNICODE charset.
Here is my code:
char lszValue[255];
std::string cadena;
HKEY hKey;
LONG returnStatus;
DWORD dwType=REG_SZ;
DWORD dwSize=255;
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", NULL, KEY_READ, &hKey);
if (returnStatus == ERROR_SUCCESS) {
returnStatus = RegQueryValueEx(hKey, L"SystemProductName", NULL, &dwType,(LPBYTE)&lszValue, &dwSize);
lszValue[dwSize] = 0;
cadena.assign(lszValue, dwSize);
return cadena;
}
Thank you very much and thanks for advance.
If your project uses UNICODE charset, then probably all WINAPI functions are bound to unicode strings, that is, RegQueryValueEx is actually RegQueryValueExW that takes wchar_t array, not char array.
When using non-Unicode, single-byte projects, the function would be RegQueryValueExA and it would work with char[].
To make your project (non)unicode-safe, use TCHAR macro instead of char.
try this code:
DWORD const dwSize=255;
TCHAR lszValue[dwSize];
std::wstring cadena;
HKEY hKey;
LONG returnStatus;
DWORD dwType=REG_SZ;
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", NULL, KEY_READ, &hKey);
if (returnStatus == ERROR_SUCCESS)
{
returnStatus = RegQueryValueEx(hKey, L"SystemProductName", NULL, &dwType, (LPBYTE)&lszValue, &dwSize);
lszValue[dwSize] = 0;
cadena.assign(lszValue, dwSize);
return cadena;
}
I've changed just the types. There may be other errors/typos. Just remember that std::wstring is for wchar_t