std::string to LPBYTE and RegEnumValueA - c++

What is the proper way to cast std::string to LPBYTE to make this code work?
string Name;
string Value;
RegEnumValueA(hKey, 0, const_cast<char*>(Name.c_str()), &dwSize, NULL, NULL, (LPBYTE)const_cast<char*>(Value.c_str()), &dwSize2);
When I try to user this code everythins is okey with the string name, but there's a bad pointer error in the string value

The proper way od getting std::string with data you want
//alloc buffers on stack
char buff1[1024];
char buff2[1024];
//prepare size variables
DWORD size1=sizeof(buff1);
DWORD size2=sizeof(buff2);
//call
RegEnumValueA(hKey, 0, buff1, &size1, NULL, NULL, (LPBYTE)buff2, &size2);
//"cast" to std::string
std::string Name(buff1);
std::string Value(buff2);

The pointer parameters should point to valid buffers that will be modified by a function. The c_str() of an unitialized string does not point to anything valid.
Use char buffers instead of a strings. This is a very good case of const_cast<> being totally uncalled for.
char Name[200], Value[200]; //Sizes are arbitrary
DWORD dwSize = sizeof(Name), dwSize2 = sizeof(Value);
RegEnumValueA(hKey, 0, Name, &dwSize, NULL, NULL, (LPBYTE)Value, &dwSize2);

If you really want to "cast" std::string as you said, you could consider the following piece of code. It should work on any std::string implementation I know, but still it is a bit "hacky" and I'd not recommend it.
string Name(1024, ' ');
string Value(1024, ' ');
DWORD dwSize=Name.size();
DWORD dwSize2=Value.size();
RegEnumValueA(hKey, 0, const_cast<char*>(&Name[0]), &dwSize, NULL, NULL, (LPBYTE)const_cast<char*>(&Value[0]), &dwSize2);

Related

WriteConsole access violation in function call but not from main()

I am trying to use WriteConsole(..) in a function call but I get access violation. When I un-comment the code in main, it prints my text to the screen with no problem in the main function. When I try to print the string in the function call I get access violation even though it does print the text to the console.
void print(char *_charArray);
int _tmain(int argc, _TCHAR* argv[])
{
HWND hConsole;
// HANDLE hFile;
char myText[] = "This is my text";
char *pMyText = myText;
LPDWORD charsWriten;
// hFile = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ, NULL,
// OPEN_EXISTING, 0, NULL);
print(pMyText);
// WriteConsole(hFile, myText, sizeof(myText), charsWriten, NULL);
getch();
return 0;
}
void print(char *text)
{
LPDWORD charsWriten;
HANDLE hFile;
hFile = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
unsigned int strn = strlen(text) + 1;
if(!WriteConsole(hFile, text, (strlen(text) + 1), charsWriten,NULL))
{
printf("Write Failed\n");
}
}
This declaration is wrong:
LPDWORD charsWriten;
The CreateFile function expects the fourth parameter to be a pointer to a variable it can write into. You don't actually allocate memory, though; you just declare a pointer—an uninitialized one at that. That won't work. You need to do:
DWORD charsWritten;
...
WriteConsole(hFile, text, (strlen(text) + 1), &charsWritten, NULL)
That will fix the access violation problem, but it doesn't explain why you are writing one character past the end of your string. You don't need to add 1 to strlen; the terminating NUL doesn't need to be written.
LPDWORD charsWriten;
LPDWORD is DWORD*. So what you have there is an uninitialized pointer. You then pass this pointer to WriteConsole, which writes to the invalid location pointed to. Instead, declare charsWritten as type DWORD, and pass its address to WriteConsole with &charsWritten.
DWORD charsWritten;
WriteConsole(hFile, text, (strlen(text) + 1), &charsWritten, NULL);
If, as you say, it works as you have it in main. That is simply bad luck. It's undefined behavior, which doesn't always have predictable results.

Creating a file with the same name as registry

I want to create a text file with the same name as a registry.
Say, I get the variable valueName, and I want it's value to be the name of a .txt file in C:\ How can I do that?
Almost final code:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{BOOL bErrorFlag = FALSE;
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{//pregatesc calea
char* val = new char[strlen(valueName)];
sprintf(val, "C:\\%s.txt", valueName);
printf("S-a creat fisierul: %s\n", val);
//creez/suprascriu fisierul
HANDLE hFile;
hFile=CreateFile(val,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{ printf("Eroare la creat fisierul %s!\n",val);
}
//sciru in fisier
char str[] = "Example text testing WriteFile";
DWORD bytesWritten=0;
DWORD dwBytesToWrite = (DWORD)strlen(str);
bErrorFlag=WriteFile(hFile, str, dwBytesToWrite, &bytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Eroare la scriere in fisier\n");
}
//inchid fisierul
CloseHandle(hFile);
}
//eroare regenumv
else printf("\nError RegEnumValue");
}
}
The fundamental problem is that you seem to want to convert a registry key, HKEY into a path. And there's no API to do that. You will need to keep track of the path and pass it to the function in the question, along with the HKEY.
You are passing uninitialized values to RegEnumValue, specifically dataSize. Since you don't care about the data, don't ask for it. Pass NULL for the data pointer, and zero for data size.
Your call to new is not allocating enough memory. You need space for the directory name, the file extension, and the null-terminator.
These problems are exacerbated by your complete neglect for error checking. That might sound harsh, but frankly you need some shock treatment. In order to be able to fail gracefully you need to check for errors. More pressing for you, in order to be able to debug code, you need to check for errors.
You've tagged the code C++ but write as if it were C. If you really are using C++ then you can use standard containers, std::string, avoid raw memory allocation and the result leaks. Yes, you code leaks as it stands.
first of all your program is more C like than C++, but if you want to solve this in C++ you can use stringstream in the following way:
std::stringstream stream;
stream << "C:\\";
stream << valueName;
stream << ".txt";
std::string filename(stream.str());
HANDLE hFile=CreateFile(filename.c_str() ,GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_NEW , FILE_ATTRIBUTE_NORMAL,NULL);
Also you need a include:
#include <sstream>

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)
{
//...
}

WinAPI File In-/Output with std::strings instead of char arrays?

due to performance reasons I didn't feel like using fstream for just one time. Seems like a very bad idea to use WinAPI functions with a std::string instead of a plain char array. All in all I would like you to tell me why the following snippet just won't work (empty stBuffer stays empty) and what I'd need to do to get it fixed.
Thanks in advance!
std::size_t Get(const std::string &stFileName, std::string &stBuffer)
{
HANDLE hFile = ::CreateFileA(stFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwBytesRead = 0;
if(hFile != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize = ::GetFileSize(hFile, NULL);
stBuffer.reserve(dwFileSize + 1);
::ReadFile(hFile, &stBuffer[0], dwFileSize, &dwBytesRead, NULL);
stBuffer[dwFileSize] = '\0';
::CloseHandle(hFile);
}
return dwBytesRead;
}
Because a std::string can contain embedded '\0' characters, it has to keep track of its own length in a separate way.
Your problem is that std::string::reserve() does not change the length of the string. It just pre-allocates some memory for the string to grow into. The solution is to use std::string::resize() and let the WinAPI function overwrite the string contents.
As a side-note: Currently, it is not guaranteed that std::string uses a contiguous buffer, but to my knowledge, all current implementations do use a contiguous buffer and it will be a requirement in the next standard.
Consider difference between reserve() and resize() members. So the solution would be:
stBuffer.resize(dwFileSize + 1);