This is driving me crazy. I'm compiling my project on Visual Studio 2012. I want to read a REG_BINARY registry entry using RegOpenKeyEx and RegQueryValueEx calls. In Debug (Multi-Threaded Debug) mode, everything works perfectly. However, in Release (Multi-Threaded) mode, RegQueryValueEx will VERY often fail with error code ERROR_MORE_DATA. Here is the code I am using:
HKEY keyHandle;
TCHAR lpData[1024];
DWORD lpcbData;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle) != ERROR_SUCCESS){
MessageBox(NULL, L"fail", L"title", MB_OK);
return NULL;
} else if (RegQueryValueEx(keyHandle, L"DigitalProductId", NULL, NULL, (LPBYTE)lpData, &lpcbData) != ERROR_SUCCESS){
MessageBox(NULL, L"fail!", L"title", MB_OK);
return NULL;
}
MessageBox(NULL, L"success", L"title", MB_OK);
By the definition of RegQueryValueEx, lpcbData is both an In and Out parameter. That is, RegQueryValueEx both reads it and writes to it. It complains because you are passing it without initializing it first with the size of the buffer, which in your case is 1024 (also I recommend that you change TCHAR to BYTE as required by the API; You can convert it to a Unicode string later on).
Try setting it to 1024 before calling the function. If then it fails with ERROR_MORE_DATA, then your buffer is not big enough - in other words, the registry key string is too long - you can either define it to contain more characters, or, better yet, call the function first with a NULL parameter instead of the buffer, and you will get back in lpcbData the required size of the buffer. You can then allocate the required buffer on the heap. Hope this helps!
You are not initializing lpcbData before calling RegQueryValueEx(). You have to tell it how large lpData is, in bytes, so it knows how many bytes it can retreive.
DWORD lpcbData = sizeof(lpData);
Read the documentation:
lpcbData [in, out, optional]
A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes. When the function returns, this variable contains the size of the data copied to lpData.
A better option is to ask the Registry how large the data is, then (re)allocate the buffer as needed. The example in the documentation shows you how to do that.
You should set the lpcbData to size of your buffer before passing it to RegQueryValueEx().
Sample code:
HKEY keyHandle;
TCHAR lpData[1024];
DWORD lpcbData= sizeof(lpData); //set size.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &keyHandle) != ERROR_SUCCESS){
MessageBox(NULL, L"fail", L"title", MB_OK);
return NULL;
} else if (RegQueryValueEx(keyHandle, L"DigitalProductId", NULL, NULL, (LPBYTE)lpData, &lpcbData) != ERROR_SUCCESS){
MessageBox(NULL, L"fail!", L"title", MB_OK);
return NULL;
}
Its working by chance so that lpcData contains some random value which is higher than the actual size of data. And probably your data is not more than 1024.
Moreover, if you get ERROR_MORE_DATA error, the lpcData will indicate how much size is required to read the data. So you should update your buffer accordingly and retry.
Related
I'm trying to read 20100 bytes from my COM port in windows. The data is truncated to 8192 bytes. What gives? When I use TeraTerm, there is no truncation. My synchronous calls are:
CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
And (code snippet for non-overlapped read only)
DWORD dwEventMask, dwIncommingReadSize;
int dwSize=0;
char szBuf[10];
if(!SetCommMask((void *) fd, EV_RXCHAR)) {THIS_RTN_ERROR}
do {
if(ReadFile((void *) fd, szBuf, 1, &dwIncommingReadSize, NULL) != 0) {
if(dwIncommingReadSize > 0) {
for (k=0; k<dwIncommingReadSize; k++) {
*(line_buf+dwSize+k) = szBuf[k];
}
dwSize += dwIncommingReadSize;
}
}
else {THIS_RTN_ERROR;}
} while(dwIncommingReadSize > 0);
k = dwSize;
return(k);
This occurs immediately after a WriteFile. I iteratively call this code until I get all the data - except I only get 8192 bytes.
Have you explicitly specified 8192 as the dwInQueue parameter in the SetupComm function, or the device driver default value is 8192?
How about specifying the buffer size required by SetupComm?
SetupComm function
Initializes the communications parameters for a specified communications device.
Syntax C++
BOOL SetupComm(
HANDLE hFile,
DWORD dwInQueue,
DWORD dwOutQueue
);
Parameters
hFile
A handle to the communications device. The CreateFile function returns this handle.
dwInQueue
The recommended size of the device's internal input buffer, in bytes.
dwOutQueue
The recommended size of the device's internal output buffer, in bytes.
For .NET SerialPort, the default value is 4096, up to 2147483647 can be specified.
SerialPort.ReadBufferSize Property
Gets or sets the size of the SerialPort input buffer.
C#
[System.ComponentModel.Browsable(true)]
public int ReadBufferSize { get; set; }
Property Value
Int32
The buffer size, in bytes. The default value is 4096; the maximum value is that of a positive int, or 2147483647.
This is more of a comment than an answer. As per the accepted answer, increasing the buffer size will fix your problem 99.9% of the time.
But the the serial interface (like the socket) is just a stream of bytes. So one always has to deal with two opposing problems:
partial messages
multiple messages
Worse, you can get a complete message followed by a truncated message.
The standard way of handling this, in both Unix and Windows, is to use select. See, for example, https://beej.us/guide/bgnet/.
The resulting code is not long, but you need to know what you want to it do.
Edit: On Windows, select only works with sockets. Maybe Batch-File: Receive Data from the Serial-Port and write it into txt-File would help?
I came across this situation with WinAPI's MapViewOfFile function. An Internet search didn't turn up any apparent fixes, so I will share my problem and solution here.
Consider the following snippet:
const char *name = "Global\\Object_Name";
unsigned long size = get_object_size();
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
size,
name);
if (!handle || handle == INVALID_HANDLE_VALUE)
exit(GetLastError());
bool created = GetLastError() == 0;
void *block = MapViewOfFile( handle,
FILE_MAP_ALL_ACCESS,
0,
0,
size);
if (block == NULL)
exit(GetLastError());
In one particular case, CreateFileMapping was successfully returning a handle. GetLastError was returning ERROR_ALREADY_EXISTS, so created == false. Now, the call to MapViewOfFile, using the same size that I passed to CreateFileMapping, returns NULL and GetLastError returns 0x05: ERROR_ACCESS_DENIED. The process was running with administrator privileges.
The MSDN documentation doesn't really mention any reason why this situation would occur. So why does CreateFileMapping succeed, but MapViewOfFile fail?
After a lot of suffer, I finally found what was causing this error in my application, in case someone else is struggling with the same, the problem is not with the MapViewOfFile method, but with the CreateFileMapping, the size of the createFileMapping should be the size of the file, not the size of the element to read, if you don't know the size then it should be 0, this does not apply to the MapViewOfFile as the value to pass as size is the length of the block you want to read/write.
Your code working will look like this:
const char *name = "Global\\Object_Name";
unsigned long size = get_object_size();
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
0,
name);
if (!handle || handle == INVALID_HANDLE_VALUE)
exit(GetLastError());
bool created = GetLastError() == 0;
void *block = MapViewOfFile( handle,
FILE_MAP_ALL_ACCESS,
0,
0,
size);
if (block == NULL)
exit(GetLastError());
A just putting this here to document what I found, unfortunately is hard to search for this error when you don't know what is causing it. I hope this saves a couple of hours to someone else.
I'm sure there are many reasons why ERROR_ACCESS_DENIED could occur from a call to MapViewOfFile. In my particular situation, it was due to the size argument.
The hint is in the fact that created == false. It shows that the object "Global\\Object_Name" has already been created. For whatever reason, the creating call initialised the section with a smaller size. For what seems like an oversight, the second call to CreateFileMapping will happily give you a handle to the already-existing object, even if you asked for a bigger mapping.
The call to MapViewOfFile now fails, because it's requesting a view that is bigger than the actual section.
So, if you're in a similar situation where the second call to MapViewOfFile fails, check the size that you're trying to map to.
It could be that the second project is compiling with a different structure alignment, resulting in the sizeof() operator determining different values, or some other size-determining function is not behaving as expected.
I am learning C and I am wondering what I need to add for those values in my WriteFile and ReadFile methods
lpNumberOfBytesRead and lpNumberOfBytesWritten
WriteFile((HANDLE)sock, "\x05\x01\x00", 3, NULL, NULL);
ReadFile((HANDLE)sock, buf, 1024, NULL, NULL);
it says in the documentation one of the two NULL values can't be NULL as my friend pointed out...
Any ideas *cheers
Assuming that you are not going to use overlapped I/O, (and from your question, I get a strong feeling that you are not), you need to pass a pointer to a DWORD variable that will receive the values:
DWORD NumberOfBytesWritten;
WriteFile((HANDLE)sock, "\x05\x01\x00", 3, &NumberOfBytesWritten, NULL);
If the function returns successfully (and you should check its return value to determine that), NumberOfBytesWritten will be set to the number of bytes that were actually written to the file.
I have a structure :
PROCESSENTRY32 pe32;
I want to pass this structure to a function. The function will create a file and write the data in the structure to that file. Name of the function is takeinput(). I passed the structure to function :
errflag = takeinput (&pe32);
In takeinput(PROCESSENTRY32 *pe31), I created a file D:\File.txt by using createfile(). Now I have to write the date from into file.txt. I am using :
WriteFile(
hFile, // open file handle
DataBuffer, // start of data to write
dwBytesToWrite, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL); // no overlapped structure
Here hFile I know. Last three I know. but I am confused about the DataBuffer paramter. What to pass there ? There are many variables in structure pe31. Can anybody help me in this?
If there is another way to write the data of the structure to the file.txt, kindly explain me. Thanks in advance.
That's the buffer which holds your data. Your call will be:
takeinput (PROCESSENTRY32* ppe32)
{
WriteFile(
hFile, // open file handle
(void*)ppe2, // pointer to buffer to write
sizeof(PROCESSENTRY32), // number of bytes to write
&dwBytesWritten, // this will contain number of bytes actually written
NULL); // no overlapped structure
// some other stuff
}
After return dwBytesWritten should be equal to sizeof(PROCESSENTRY32).
WriteFile function signature is
BOOL WINAPI WriteFile(
__in HANDLE hFile,
__in LPCVOID lpBuffer,
__in DWORD nNumberOfBytesToWrite,
__out_opt LPDWORD lpNumberOfBytesWritten,
__inout_opt LPOVERLAPPED lpOverlapped
);
your DataBuffer is lpBuffer in the signature and lpBuffer is a pointer to the buffer containing the data to be written to the file or device. You should explicitly cast a pointer to your data (PROCESSENTRY32 pe31) to a pointer to void ( (void)pe31 ) and pass it to WriteFile.
Have you read the documentation for the WriteFile function? That might help you understand what each of the parameters that it takes are used for and what they mean.
BOOL WINAPI WriteFile(
__in HANDLE hFile,
__in LPCVOID lpBuffer,
__in DWORD nNumberOfBytesToWrite,
__out_opt LPDWORD lpNumberOfBytesWritten,
__inout_opt LPOVERLAPPED lpOverlapped
);
You say you're confused about the DataBuffer parameter. MSDN explains that this is:
A pointer to the buffer containing the data to be written to the file or device.
This buffer must remain valid for the duration of the write operation. The caller must not use this buffer until the write operation is completed.
So, in essence, the DataBuffer (lpBuffer) parameter is where you provide the data that you want to be written out to the text file.
There's a full example of how to open and write to a file here. You should be able to follow along with the code to see how to code this for your specific case.
PeekNamedPipe(
tmp_pipe, // __in HANDLE hNamedPipe,
NULL, // __out_opt LPVOID lpBuffer,
0, // __in DWORD nBufferSize,
NULL, // __out_opt LPDWORD lpBytesRead,
&totalBytesAvailable, // __out_opt LPDWORD lpTotalBytesAvail,
NULL // __out_opt LPDWORD lpBytesLeftThisMessage
);
I have written bytes to the pipe somewhere else,but totalBytesAvailable is always 0,why?
I have found that in Windows, if you call PeekNamedPipe before calling ReadFile, it will always return zero bytes, even if there are in fact bytes to be read. You have to call ReadFile, followed by PeekNamedPipe, and keep looping until PeekNamedPipe returns zero bytes.
I have noticed that even under these circumstances, sometimes PeekNamedPipe returns zero bytes even though there are bytes left to be gotten. Must be a timing thing. The sender is going to have to preface each message with a byte count. Sigh...
It's an old question but I haven't found the answer online so I figured I'd answer it anyway. You have to loop until the pipe reads, here's my working code:
DWORD bytesAvail = 0;
while(bytesAvail==0){
if( !PeekNamedPipe(pipeHandle, NULL, 0, NULL, &bytesAvail, NULL) ){
printf("PeekNamedPipe error %d.\n", GetLastError()); //error check
}
}
printf("Bytes available: %d\n", bytesAvail);
Of course, this only works if you are sure there is data waiting to be read, otherwise you will be stuck in an endless loop because there isn't actually data to be read, so it will always be 0.