Registry problem - deleting key/values with C++ - c++

The following piece of code seems to unreliably execute and after and undeterministic time it will fail with error code 234 at the RegEnumValue function.
I have not written this code, I am merely trying to debug it. I know there is an issue with doing RegEnumValue and then deleting keys in the while loop.
I am trying to figure out first, why it is throwing this 234 error at seemingly random points, as in, it is never after a consistent number of loop iterations or anything like that.
From what I have seen it fails to fill its name buffer, but this buffer is by no means too small for its purpose, so I don't understand how it could fail??
Could someone please advice on getting rid of this 234 error thrown by the RegEnumValue funciton?
HKEY key;
DWORD dw;
int idx;
char name[8192];
DWORD namesize=4096;
std::string m_path = "SOFTWARE\\Company\\Server 4.0";
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,m_path.c_str(),0,KEY_ALL_ACCESS,&key) == ERROR_SUCCESS)
{
bool error=false;
idx=0;
long result;
long delresult;
while (true)
{
result = RegEnumValue(key,idx,(char*)name,&namesize,NULL,NULL,NULL,NULL);
if (result == ERROR_SUCCESS && !error){
delresult = RegDeleteValue(key,name);
if (delresult != ERROR_SUCCESS)
error = true;
idx++;
}
else
{
break;
}
}
RegCloseKey(key);
}

There are some errors in your code:
The 4-th parameter of RegEnumValue (the namesize) is in-out parameter. So you have to reset namesize to sizeof(name)/sizeof(name[0]) (in case of the usage char type it is just sizeof(name)) inside the while loop before every call of RegEnumValue. It's the main error in your program.
If you don't want to have ERROR_MORE_DATA error any time you have the buffer having 32,767 characters. It is the maximum size of name the the regitry value (see documentation of RegEnumValue).
It is not good to use KEY_ALL_ACCESS in the RegOpenKeyEx. I'll recomend you to change it to KEY_QUERY_VALUE | KEY_SET_VALUE. It is not a real error, but depends on your environment it could be.
It if better to use UNICODE version of all this functions to speed-up a little the code.
UPDATED: Only small comment about the usage of the UNICODE version. Intern Windows work with UNICODE characters. So usage of non-Unicode version of RegEnumValue si more slow because at the evry call a new UICODE memeory block will be allocated and converted to ANSI/Multi-byte. Moreover if you will has a value name written in a language which can't be converted in you Windows ANSI code page (Chinese, Japanese and so on) and some characters will be replaced to '?' (see WC_DEFAULTCHAR flag of WideCharToMultiByte), then it can be that the function RegDeleteValue will fail with the error code like "the value with the name is not exist".

just change the value of your fourth parameter i.e namesize from 4096 to 8192 .Always MakeSure that it should be always equal to buffer size.

The answer is at the bottom of that page:
http://msdn.microsoft.com/en-us/library/ms724865(VS.85).aspx
Please read the answer of "ERROR_MORE_DATA: lpData too small, or lpValueName too small?" question.

Related

Is SourceAddress relative to SourceProcess in MmCopyVirtualMemory?

I try to use the following code from kernel mode in a driver:
NTSTATUS NTAPI MmCopyVirtualMemory
(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TargetProcess,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
I use it in the following way:
PEPROCESS process;
NTSTATUS status;
unsigned int readValue;
// get notepad.exe process -> Notepad is opened already and this is the ID from Task Mgr
status = PsLookupProcessByProcessId((HANDLE)7252, &process);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## Lookup By Id failed. ##\n\n");
if (status == STATUS_INVALID_CID)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## Id could not be found. ##\n\n");
}
goto Exit;
}
SIZE_T cbBytesReturned;
status = MmCopyVirtualMemory(process, 0x00, PsGetCurrentProcess(), &readValue, sizeof(unsigned int), KernelMode, &cbBytesReturned);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## MemCopy failed. ##\n\n");
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## MemCopy DONE ##\n\n");
}
ObfDereferenceObject(process);
Currently this fails. I assumed that 0x00 points to the first byte of memory of the process I am reading from. A I wrong or is that relative which means process + 0x00 is the first memory location ?
I am not sure why you think your code is going to work, your input values for MmCopyVirtualMemory are not correct.
You're passing a NULL pointer for the second parameter. How is the Windows Kernel supposed to know where the memory you'd like to copy from the SourceProcess is present if you don't give it a valid address?
You're passing the pointer address to a local variable as the fourth parameter, yet the fourth parameter is supposed to be a pointer address which is valid under the process you're targeting (the third parameter). The pointer address used for the fourth parameter is supposed to be where you'd like to put the memory copied from the SourceAddress (within the virtual memory of SourceProcess) within the TargetProcess.
For the fifth parameter, you're passing the size of an unsigned int? This is also incorrect.
I believe the fifth parameter (BufferSize) should be the length of how much memory you'd like to copy from SourceAddress into TargetAddress. If this is the case, make sure that there is enough room at TargetAddress - take this with a grain of salt.
I suggest you take a look at the function prototype which you shared in your original post and re-check your code, and try again, taking on-board my comments here and after some more research on the routine.
Remember though, MmCopyVirtualMemory is not officially documented and you'll be taking a risk by using it in any production-level source code. I recommend strongly that you re-consider your options if this isn't just an educational experiment, because stable and documented code is generally an important thing.

InternetReadFile filling buffer, but returning zero bytes read

I'm having a very strange problem whilst trying to download a file from the internet inside a C++ application written for Windows Compact 2013.
BOOL WWW::Read(char* buffer, DWORD buffer_size)
{
memset(buffer, 0, buffer_size);
m_dwBytesRead = 0;
BOOL bResult = InternetReadFile(m_handle, buffer, buffer_size, &m_dwBytesRead);
if (!bResult)
{
DWORD dwLastError = GetLastError();
TCHAR *err;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwLastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPTSTR)&err, 0, NULL))
{
LOGMSG(1, (TEXT("InternetReadFile failed at - (%u) %s\r\n"), dwLastError, err));
LocalFree(err);
}
}
// FUDGE
if (m_dwBytesRead == 0)
{
DWORD dwZeros = countZeros(buffer, buffer_size);
if (dwZeros < buffer_size)
{
m_dwBytesRead = buffer_size;
}
}
// END OF FUDGE
return bResult;
}
I repeatedly call the above function from another member function as follows
DWORD dwWritten;
while (!(Read(buffer, DOWNLOAD_BUFFER_SIZE) && m_dwBytesRead == 0))
{
WriteFile(m_hDownload, buffer, m_dwBytesRead, &dwWritten, NULL);
m_dwActualSize += dwWritten;
++m_dwChunks;
if (m_dwBytesRead > 0)
m_dwInactivity = 0;
else if (++m_dwInactivity > INACTIVITY_LIMIT)
return WDS_INACTIVITY;
}
Without the FUDGE, this function fails the first time through, and works correctly on subsequent calls. The error that I get on the first pass through this function call is
InternetReadFile failed at - (112) There is not enough space on the disk.
I don't understand why I should be getting a "not enough space on disk" error during a READ operation. I have checked that that the buffer is allocated, and available, and matches the expected size. In fact when I inspect the contents of the buffer, I find that it HAS been filled with the expected number of bytes, however the contents of the m_dwBytesRead variable is still set to 0.
As you can see, I have tried to code around this specific case by inspecting the contents of the buffer to see if it has been filled, and then fudging the m_dwBytesRead variable, but this is only a temporary work around to get me past this error, I really need to understand why this problem is occurring.
The consequences of this error (without my fudge), is that the data is thrown away, and I end up with a file that is missing the first block but otherwise fully correct. Consequently MD5 checks fail, and I am missing the first part of the file.
I just happen to know that the file will always be larger than the block size that I am using, so my fudge will work, but I don't like having these horrible workarounds in the code when they shouldn't be needed.
If anyone can shed any light upon what is causing the problem, it would be greatly appreciated.
I'm using Visual Studio 2013 C++ (native Windows app, not MFC), the target is 32-bit and Unicode, running on Windows Compact 2013.
Many thanks,
Andrew
Is the machine actually running out of disk space? InternetReadFile will write to disk behind your back by default:
To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero. This is especially important if the requested data is written to the cache, because otherwise the cache will not be properly updated and the file downloaded will not be committed to the cache. Note that caching happens automatically unless the original request to open the data stream set the INTERNET_FLAG_NO_CACHE_WRITE flag.

C++ String reaches over several NUL Bytes

I hate to ask this because I think this must be very trivial. But as someone who is used to high-level-languages this is a real problem.
I got a C++ program which uses PDFium to generate an Image to a PDF. And i have a C# program which communicates with the C++ program via Named Pipes. The PDF file (Which is saved as a byte-array) gets transmitted by the pipe. And here is my Problem.
On the 374th Position of the stream is a NUL byte (00) and im too stupid to somehow reach the data after it.
Here is my Code:
LPTSTR lpszPipename2 = TEXT("\\\\.\\pipe\\myNamedPipe2");
hPipe2=CreateFile(lpszPipename2, GENERIC_READ, 0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
if(ReadFile( hPipe2, chBuf, dwBytesToRead, &cbRead, NULL))
{
PDFData = chBuf;
}
dwBytes to read is the size of the file and cbRead shows the correct number. But PDFData only contains the first 373 bytes. I checked that the data beyond the 373th position is there with the Immediate Window i just don't know how to process it.
I gotta put the Data into a char-array.
As I already said, i think this is very trivial. But although i know where the problem comes from, i have simply no idea how to fix it.
Many Thanks and Regards
Michael
Edit: The C#-Code. Its everything but perfect. But i'm very sure this Problem is on the C++ side.
public void SendRawData(byte[] data)
{
while (clientse == null || clientse.stream == null)
{ }
if (clientse.stream.CanWrite)
{
clientse.stream.Write(data, 0, data.Length);
clientse.stream.Flush();
}
}
private void ListenForClients()
{
while (true)
{
clientHandle = CreateNamedPipe(this.pipeName, DUPLEX | FILE_FLAG_OVERLAPPED, 0, 255, BUFFER_SIZE, BUFFER_SIZE, 0, IntPtr.Zero);
//could not create named pipe
if (clientHandle.IsInvalid)
return;
int success = ConnectNamedPipe(clientHandle, IntPtr.Zero);
//could not connect client
if (success == 0)
return;
clientse = new Client();
clientse.handle = clientHandle;
clientse.stream = new FileStream(clientse.handle, FileAccess.ReadWrite, BUFFER_SIZE, true);
if (ClientType == 0)
{
Thread readThread = new Thread(new ThreadStart(Read));
readThread.Start();
}
}
}
"Solution":
Actually this never was a real problem. I just got my wires crossed. While chBuf seemed after copying it into PDFData or when i read its value is VS to only have those 373 bytes. All ~20 kilobytes were copied to that position.
I knew that, but i didn't understand how the PDFium sources should know that if the string terminates after 373 chars.
Well... the PDFium-sources know it cause i have to pass the length. Which was determined by
size_t len = PDFData.length();
and was therefore of course only 373 bytes.
The null character '\0' is used by C/C++ to terminate char* strings. So any library function (i.e. strlen(), strncpy(), etc) will use the null character as an implicit end-of-string indicator. Your code is obviously doing this somewhere. Instead, use something more like memcpy() or a std::vector<char> with an explicit data length.
Have a look at string:assign (http://www.cplusplus.com/reference/string/string/assign/)
String assignment operator from char * uses the C-style end-of-string convention. You need the "buffer" assign call:
string& assign (const char* s, size_t n);
This will include any NULs.
That being said, vector of bytes may indeed be a better choice.
Actually this never was a real problem. I just got my wires crossed. While chBuf seemed after copying it into PDFData or when i read its value is VS to only have those 373 bytes. All ~20 kilobytes were copied to that position. I knew that, but i didn't understand how the PDFium sources should know that if the string terminates after 373 chars.
Well... the PDFium-sources know it cause i have to pass the length. Which was determined by
size_t len = PDFData.length();
and was therefore of course only 373 bytes.
I'm sorry that i bothered you with that stuff

RegOpenKeyEx and RegSetValueEx fail, but I dont know why

As a starting C++ programmer I want to set a value in the windows registry. I created this textbook implementation to accomplish this, but I always get error 998 back. I guess I am missing something very simple and straightforward, but I can't figure out what it is.
Running this code as a regular user or administrator makes no difference.
#define LEDPORT 3
#define SUBKEY "SOFTWARE\\PATH\\OTHERPATH\\"
HKEY key;
if(RegCreateKey(HKEY_LOCAL_MACHINE, TEXT(SUBKEY), &key) == ERROR_SUCCESS)
{
HKEY createKey;
DWORD value = LEDPORT;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(SUBKEY), NULL, KEY_ALL_ACCESS, &createKey) == ERROR_SUCCESS){
// retVal returns error 998 and the value isn't set
int retVal = RegSetValueEx(createKey, TEXT("PortNumber"), NULL, REG_DWORD, (BYTE *)value, sizeof(value));
RegCloseKey(createKey);
}
}
In effect this creates the mentioned key at LocalMachine\Software\Path\OtherPath but the DWORD value "PortNumber" isnt.
Again, I think it is something straightforward, but I spend a couple of hours of thinking what it could be and I can't figure it out.
Error code 998 converted into human-readable is Invalid access to memory location. The reason is your cast (BYTE*)value, reinterpreting the value 3 (LEDPORT) as an address. (BYTE*)&value fixes your immediate problem.

Reading double from dialog edit control

I'm currently working on a program (for fun, this is not an assignment) that has multiple functions. I have never used Win32 prior to yesterday and so I am rather new. I used TheForger's tutorials to get started. Right now, I have a dialog form with four edit boxes on it, charge1, charge2, charge3, and distance between particles. I am getting this information and plugging it into the formula to solve for the amount of force between the particles.
When I get to the part where I am getting the data from the edit box, I am receiving 0.
Here is my current code:
case ID_SOLVE:
{
ZeroMemory(coulombDisplay, sizeof(coulombDisplay));
GetDlgItemText(g_hCoulombs, IDC_DISTANCE, value1, 10);
coulombsDistance = atof(value1);
GetDlgItemText(g_hCoulombs, IDC_CHARGE1, value2, 10);
coulombsStrength1Base = atof(value2);
GetDlgItemText(g_hCoulombs, IDC_CHARGE2, value3, 10);
coulombsStrength2Base = atof(value3);
if(coulombsDistance == 0.0)
{
MessageBox(NULL, "WHAT", "WHAT", MB_OK | MB_ICONEXCLAMATION);
DestroyWindow(g_hCoulombs);
}
coulombsResult = (coulombsStrength1Base * coulombsStrength2Base);
coulombsResult /= (pow(coulombsDistance, 2));
coulombsResult *= kConstant;
sprintf(coulombDisplay, "%g", coulombsResult);
SendDlgItemMessage(g_hCoulombs, IDC_FORCE, WM_SETTEXT, 0, (LPARAM)(LPCSTR)coulombDisplay);
}
break;
value1, value2, value3, and coulombDisplay are all char[] that have been zero'd
coulombsResult, coulombsDistance, coulombsStrength1Base, coulombsStrength2Base are all doubles
The MessageBox stating "WHAT" is popping up each and every time that I run the program. I am using the multi-byte character set of VC++ 2010.
Any help would be greatly appreciated.
STATUS_ACCESS_DENIED has a good point. If you look at the documentation for atof you'll see that a error condition will result in 0.0 being returned. I'd recommend writing to a log file or something to see what the data is going into the atof function. I'm wondering if your allocated char buffer is big enough.
Try GetDlgItemTextA instead of GetDlgItemText to make sure you're getting back 8-bit characters and not 16-bit characters. A 16-bit character will usually have a zero in the upper half, and will be interpreted as an empty 8-bit string.