Windows RegQueryValueEx odd return results - windows

I am getting odd results when using RegQueryValueEx and I cannot figure out why.
This is what I had set up before making the RegQueryValueEx
DWORD dataSize;
TCHAR data[256];
The first time I call
LONG ret = RegQueryValueEx( hKey, dataKey, NULL, NULL, (LPBYTE)data, &dataSize);
ret is equal to 234 (ERROR_MORE_DATA)
But when I call the same thing on the next line
LONG ret2 = RegQueryValueEx( hKey, dataKey, NULL, NULL, (LPBYTE)data, &dataSize);
ret2 is equal to 0 (ERROR_SUCCESS)
Why would this function return ERROR_MORE_DATA the first time I call it, then return ERROR_SUCESS on the same call on the very next line?
I attempted to change TCHAR data[1024] but I got the exact same results. Any ideas?
Complete code:
for( int i=0; i<NUM_HISTORY; i++){
CString dataKey = getDataKey(i);
DWORD dataSize = 1024;
TCHAR data[1024];
LONG ret = RegQueryValueEx( hKey, dataKey, NULL, NULL, (LPBYTE)data, &dataSize);
LONG ret2 = RegQueryValueEx( hKey, dataKey, NULL, NULL, (LPBYTE)data, &dataSize);
// Breakpoint to see what ret and ret2 are equal to
int j = 0;
}

This is by design. The first call failed because you specified as size that was too small. But what you didn't count on is that it also updated your dataSize variable. To tell you how much memory to allocate so the call can succeed.
So the second call succeeded since you now specify a size that's exactly correct. But without doing the other thing you needed to do, actually make the buffer bigger. Nothing much good can happen when the call then causes a buffer overflow and corrupt your stack frame, be sure to use the /RTC compile option so you'll get a runtime error from that.
You avoided this problem by increasing the buffer size from 256 to 1024. But your code is still incorrect, your program will fail miserably if the registry value ever gets larger than 1024 bytes. Don't use a local array, use the new operator or malloc() to allocate the buffer so it can never fail like this. Or simply fail the call and declare "bad data".
Also note another bug, the dataSize is in bytes but the buffer is TCHAR, not a byte. Which is probably why you didn't corrupt the stack frame, the buffer was big enough by accident. You don't want to rely on accidents like this. Consider a helper class like CRegKey to avoid these kind of mistakes.

Related

GetRegionData() not working for stack allocated buffer

I am using the win32 function GetRegionData(...) to extract the exact rectangles which make up the invalidated paint region in response to a WM_PAINT message.
The following code works correctly and the second call to GetRegionData succeeds.
DWORD uRegionSize = GetRegionData(hRgn, sizeof(RGNDATA), NULL); // Send NULL request to get the storage size
RGNDATA* pData = (RGNDATA*)(new char[uRegionSize]); // Allocate space for the region data
pData->rdh.dwSize = uRegionSize;
DWORD uSizeCheck = GetRegionData(hRgn, uRegionSize, pData);
if (uSizeCheck != uRegionSize) {
// FAIL!
delete[] pData;
return;
}
...
do stuff with rectangles
...
But when I tried to move the data buffer to a member variable allocated on the stack, GetRegionData fails every time returning 0.
In my header:
char UpdateRegionData[LOTS_MORE_BYTES_THAN_NEEDED];
In my cpp:
DWORD uRegionSize = GetRegionData(hRgn, sizeof(RGNDATA), NULL); // Send NULL request to get the storage size
RGNDATA* pData2 = (RGNDATA*)UpdateRegionData;
pData2->rdh.dwSize = uRegionSize;
DWORD uSizeCheck = GetRegionData(hRgn, uRegionSize, pData2);
if (uSizeCheck != uRegionSize) {
// FAIL!
return;
}
The only thing different between the 2 versions is the memory allocation, but the second one fails. GetLastError() returns code 183 which is ERROR_ALREADY_EXISTS which doesn't seem to make much sense.
Thanks to Raymond for pointing out the size error - that was indeed an error, but it was not cause of the issue. The actual cause was byte alignment. The project I am working on has its byte alignment set to a default of 1. When I specified 4 byte alignment for the buffer using __declspec(align(4)) then the problem was solved.

ReadFile on volume fails with ERROR_INVALID_PARAMETER after FSCTL_ALLOW_EXTENDED_DASD_IO

I'm reading a volume (logical drive) with ReadFile. I'm using DeviceIoControl with FSCTL_ALLOW_EXTENDED_DASD_IO code, because I want to have access to all (including the last) bytes and had an issue trying to read last 512 bytes (ReadFile successed, but reported 0 bytes read) and saw advice to use it. Unfortunately, ReadFile fails being called after that DeviceIoControl called.
In code it looks like this (all success checks are omitted for the brevity):
HANDLE fd;
DWORD junk;
int lenToBeRead = 0x1000;
DWORD nread;
char* alignedBuf = new char[lenToBeRead];
fd = CreateFile("path to volume", FILE_READ_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL)) //success
DeviceIoControl(fd, FSCTL_ALLOW_EXTENDED_DASD_IO,
NULL, 0, NULL, 0, &junk, (LPOVERLAPPED) NULL) //success
ReadFile(fd, alignedBuf, (DWORD) lenToBeRead, &nread, NULL)
// fails with 0x57 code, ERROR_INVALID_PARAMETER
All work with fd handle is synchronous.
EDIT. I solved the problem. I was trying to read last bytes. So my volume was of length L = 0x...200 and I had my handle on position pos = L - 0x200. What I had done before I did the FSCTL_ALLOW_EXTENDED_DASD_IO thing - I cut lenToBeRead to fit in remaining space (so, if it was 0x1000, it would change to 0x200), because I had found that ReadFile did not guarantee read all the bytes to the EOF in case of lenToBeRead is greater than amount of bytes remained from current handle position. This did not help, ReadFilewas still returning with success and 0 bytes read. I deleted that fix and then used FSCTL_ALLOW_EXTENDED_DASD_IO, which deliver me then ReadFile failing with ERROR_INVALID_PARAMETER on lenToBeRead = 0x1000. I totally forgot about the first fix and remembered now and now it works.
I found the solution and add it to the question body.
What one has to keep in mind when working with ReadFile is to control arguments (length) to not cross the boundary of the file.
I had tried it as a fix before doing the FSCTL_ALLOW_EXTENDED_DASD_IO thing and it did not help. But combination of the FSCTL_ALLOW_EXTENDED_DASD_IO thing and the boundary check gave me wanted result - I could read that last bytes.

In Win32, how can a text file be successfully read into memory?

I am trying to get simple file IO working in Win32. So far the writing is working fine, but the reading is not: although it successfully reads the contents, additional "garbage" is appended to the string. The code I have so far is below. The program has UNICODE defined.
For writing:
DWORD dwTextSize = GetWindowTextLength(hWndTextBox);
WCHAR *lpszText = new WCHAR[dwTextSize];
GetWindowText(hWndTextBox, lpszText, dwTextSize + 1);
hTextFile = CreateFile(lpszTextFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwBytesWritten;
WriteFile(hTextFile, lpszText, 2 * dwTextSize, &dwBytesWritten, NULL); // x2 for 2 bytes per Unicode character
CloseHandle(hTextFile);
DeleteObject(hTextFile);
For this example, Hello, World! is saved successfully as Hello, World!.
For reading:
lpszTextFileName = L"text.txt"; // LPCTSTR Variable
hTextFile = CreateFile(lpszTextFileName, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSize = GetFileSize(hTextFile, &dwFileSize);
DWORD dwBytesRead;
WCHAR *lpszText = new WCHAR[dwFileSize / 2];
ReadFile(hTextFile, lpszText, dwFileSize, &dwBytesRead, NULL);
CloseHandle(hTextFile);
The string is then used to set the text of an EDIT control:
SendMessage(hWndTextBox, WM_SETTEXT, NULL, (LPARAM)lpszText); // SetWindowText() also possible
When Hello, World! is read back in, it reads back in as Hello, World!﷽﷽ꮫꮫꮫꮫﻮ or a visual variation upon this, but basically "garbage"!
I have probably missed something rather obvious, but I cannot see where! Is there a solution to this problem and if so, what is it?
Ok I started this with a comment, but its getting out of control.
For Writing
This:
WCHAR *lpszText = new WCHAR[dwTextSize];
should be:
WCHAR *lpszText = new WCHAR[dwTextSize+1];
This:
DeleteObject(hTextFile);
should not be there at all.. Get rid of it.
I'm assuming you delete [] lpszText; somewhere when you're done with it. if not, do so.
For Reading
The second parameter to GetFileSize() should not be the same variable as your return value. It is the HIGH 32bit of a 64-bit value for large file sizes. If you know you're file size is smaller than 4gB, you can leave it NULL, so change this:
DWORD dwFileSize = GetFileSize(hTextFile, &dwFileSize);
to this:
DWORD dwFileSize = GetFileSize(hTextFile, NULL);
You must account for the null terminator of your file buffer, so this:
WCHAR *lpszText = new WCHAR[dwFileSize / 2];
should be changed to this:
WCHAR *lpszText = new WCHAR[dwFileSize / 2 + 1];
lpszText[dwFileSize / 2] = 0;
and the rest should work as you're hoping it would. No error checking, which is not good, but I've seen worse. And as before, I'm assuming you delete [] lpszText; somewhere when you're done with it. if not, do so.

Confusing ReturnLength from Windows GetLogicalProcessorInformationEx function

I'm trying to use the (fairly new) GetLogicalProcessorInformationEx function in Windows. The ReturnLength it gives isn't making sense.
The older GetLogicalProcessorInformation gives reasonable results...
ReturnLength = 0;
Result = GetLogicalProcessorInformation(NULL, &ReturnLength);
printf("GLPI (%d): %d %d\n",
Result,
sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION),
ReturnLength);
Here's the output (2-core, 64-bit, Win7 box): GLPI (0): 32 416
In other words, the function will populate the buffer I pass with 416/32=13 SYSTEM_LOGICAL_PROCESSOR_INFORMATION structures.
For GetLogicalProcessorInformationEx, here's my call...
ReturnLength = 0;
Result = GetLogicalProcessorInformationEx(RelationProcessorCore,
NULL, &ReturnLength);
printf("GLPIX (%d): %d %d %d\n",
Result,
sizeof(PROCESSOR_RELATIONSHIP),
sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX),
ReturnLength);
Here's the output (2-core, 64-bit, Win7 box): GLPIX (0): 40 80 96
The Microsoft docs (http://msdn.microsoft.com/en-us/library/windows/desktop/dd405488(v=vs.85).aspx) indicate that the function will return either PROCESSOR_RELATIONSHIP or SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structures, depending on the value of the first argument. ReturnLength suggests it isn't going to return either, though - 96 isn't divisible by sizeof(PROCESSOR_RELATIONSHIP) or sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX).
I also tried RelationAll for the first argument, and that gave a ReturnLength of 768 - also not a multiple or 40 or 80.
Can anyone shed any light?
You'll need to trust what the function returns you. Necessarily so, the structures in the union have an unpredictable size. Particularly this member of PROCESSOR_RELATIONSHIP:
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
The ANYSIZE_ARRAY macro is the hint, that says that the size of the GroupMask array is variable and depends on the value of the GroupCount member. Using sizeof on the structure never gives you the correct size, it will be too low. Be sure to use the returned size to allocate the storage for the struct, like this:
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* buf =
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(ReturnLength);
This pattern is otherwise common in C and the winapi.

WriteProcessMemory/ReadProcessMemory fail

I tried using both ReadProcessMemory() and WriteProcessMemory() in my application,but in both cases I get one result - Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
Has anyone met that error code before? I'm using Vista SP2,I tried to run as admistrator,but I till get that erorcode.
Make sure you call VirtualProtectEx to set the correct protection level on the memory you want to read/write.
After thinking about it, it's probably not the problem since most memory has read access enabled, but to set the protection level do something like this (in C++)
(no error checking and just using a random memory address, but you should get the idea)
char buffer[256];
DWORD oldProtect = 0;
DWORD numRead = 0;
VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, PAGE_EXECUTE_READWRITE, &oldProtect );
ReadProcessMemory( hProc, (LPVOID)0x77810F34, buffer, 256, &numRead );
VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, oldProtect, NULL ); //restore the original protection when you're done

Resources