passing structure to a function in C - c

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.

Related

Why is my serial read on Windows COM port limited to 8192 bytes?

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?

How to get buffer into CompletionROUTINE as apart of WSARecvFrom call?

I'm working on a UDP server, and am trying to use overlapped IO. I've been trying to use MSDN examples and documentation for research but haven't found use of the lpCompletionRoutine argument of the function.
I notice you pass a PWSAOVERLAPPED to WSARecvFrom, and it contains a LPVOID Pointer member. Would I create my own user-data structure that contains a reference to the buffer and pass it as a pointer inside this Pointer member of PWSAOVERLAPPED?
I thought it was a bit redundant though that the received bytes were available in two places:
WSARecvFrom's lpNumberOfBytesRecvd argument, and lpCompletionRoutine's cbTransferred parameter.
Example of my current completion routine:
void CALLBACK CompletionROUTINE(
DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags
) {
UNREFERENCED_PARAMETER(dwError);
UNREFERENCED_PARAMETER(lpOverlapped);
UNREFERENCED_PARAMETER(dwFlags);
/* Best way to get the bytes read here? */
Printf(L"Recieved %d bytes\n", cbTransferred);
}
and my call to WSARecvFrom:
iResult = WSARecvFrom(
listenSocket,
&wsaBuffer,
1,
&dwBytesRecieved,
&dwFlags,
(PSOCKADDR)&sender,
&senderAddrSize,
&wsaOverlapped,
CompletionROUTINE
);
From the WSAOVERLAPPED structure documentation:
hEvent Type: HANDLE
If an overlapped I/O operation is issued without an I/O completion routine (the operation's lpCompletionRoutine parameter is
set to null), then this parameter should either contain a valid handle
to a WSAEVENT object or be null. If the lpCompletionRoutine parameter
of the call is non-null then applications are free to use this
parameter as necessary.
So since I am providing a lpCompletionRoutine parameter, I can use WSAEvent as a pointer to my user defined data.
Thank you to the commenter that lead me to this finding.

C - RegQueryValueEx sometimes in Release build

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.

lpNumberOfBytesRead and lpNumberOfBytesWritten using Sockets

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.

PeekNamedPipe always returns 0 for totalBytesAvailable

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.

Resources