WINAPI C - CreateFileMapping fails with error 8 - ERROR_NOT_ENOUGH_MEMORY - c

I'm working with file mappings on Windows but having some troubles with them.
First off, I have the necessity to partially map a file and setting the start and the end of it dynamically.
My code is the following:
long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
long start = (i)*fiveMB;
long end = (i + 1)*fiveMB;
long realEnd = end;
if (roundedDim<realEnd)
realEnd = dim;
long chunkDim = realEnd - start;
LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
long offset = start - fileMapStart.QuadPart;
HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);
if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
printf("Error mapping file: %d\n",GetLastError());
CloseHandle(fileH);
return 1;
}
char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
if ((LPVOID)mapView == NULL) {
printf("Error mapView: %d\n", GetLastError());
CloseHandle(fileMappingH);
CloseHandle(file);
return 1;
}
mapView += offset;
/* doing all the stuff */
UnmapViewOfFile((LPVOID)mapView);
CloseHandle(fileMappingH);
}
As far as I know, only MapViewOfFile requires the starting byte to be aligned with the system granularity, so I didn't bother to fix the maximum file mapping size for that.
I tried this code on a 1448 KB file (printing out dim I get 1482159 bytes) while calculating the available memory via GlobalMemoryStatusEx(&memstatus) and memstatus.ullAvailVirtual I get 2092208128 bytes but still stuck on having the CreateFileMapping call failed and with error code 8, ERROR_NOT_ENOUGH_MEMORY.
I also tried calling CreateFileMapping(fileH, NULL, PAGE_READONLY, 0, 0, NULL) to memory map the whole file, but instead there were problems on MapViewOfFile, error 5, ERROR_ACCESS_DENIED.
I don't understand what I'm doing wrong here, since I successfully did it with mmap on a Linux version of the same project.
Thanks anyone who may help.
EDITS:
c was a leftover, I actually meant i
added UnmapViewOfFile and CloseHandle calls

As far as I know, MapViewOfFile only requires the starting byte to be
aligned with the system granularity, so I didn't bother to fix the
maximum file mapping size for that.
this is root of error - really from MapViewOfFile
dwNumberOfBytesToMap [in]
The number of bytes of a file mapping to map to the view. All bytes
must be within the maximum size specified by CreateFileMapping. If
this parameter is 0 (zero), the mapping extends from the specified
offset to the end of the file mapping.
if we use 0 as MaximumSize in CreateFileMapping the maximum size of the file mapping object is equal to the current size of the file. and :
if an application specifies a size for the file mapping object that is
larger than the size of the actual named file on disk and if the
page protection allows write access (that is, the flProtect
parameter specifies PAGE_READWRITE or PAGE_EXECUTE_READWRITE),
then the file on disk is increased to match the specified size of the
file mapping object.
and about GetLastError and win32 errors at all. the errors in most case returned from kernel as NTSTATUS code. the win32 layer converts the specified NTSTATUS code to its equivalent system error code via RtlNtStatusToDosError. unfortunately this conversion not injective - the many different NTSTATUS code can convert to same win32 error and we lost sensitive info here.
so in some case much more better call RtlGetLastNtStatus() instead of GetlastError() - this give to as much more info about error.
CreateFileMapping call failed and with error code
ERROR_NOT_ENOUGH_MEMORY.
based on error ERROR_NOT_ENOUGH_MEMORY we can think that not enough memory in system (STATUS_NO_MEMORY). but also another status - STATUS_SECTION_TOO_BIG converted to the ERROR_NOT_ENOUGH_MEMORY. the CreateFileMapping is thin shell over ZwCreateSection the STATUS_SECTION_TOO_BIG returned when:
The value of MaximumSize is too big. This occurs when either
MaximumSize is greater than the system-defined maximum for sections, or if MaximumSize is greater than the specified file and the
section is not writable.
and this is exactly your case: you use PAGE_READONLY in call CreateFileMapping - so section is not writable and fileMapSize is greater than the specified file (size for the file mapping object that is larger than the size of the actual file on disk)
MapViewOfFile return ERROR_ACCESS_DENIED.
again GetLastError() plays here with us a cruel joke. the initial status is not STATUS_ACCESS_DENIED how we can wait, but STATUS_INVALID_VIEW_SIZE. this status also converted to ERROR_ACCESS_DENIED. the MapViewOfFile got it when not all bytes within the maximum size specified by CreateFileMapping
and call CreateFileMapping multiple time in loop - this is design error - need call this api only once, before loop. in loop only exist sense call MapViewOfFile. the test code can be:
void TestMap(PCWSTR lpFileName, ULONG dwChunkSize)
{
HANDLE hFile = CreateFileW(lpFileName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
FILE_STANDARD_INFO fsi;
if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
{
if (HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0))
{
if (ULONG n = (ULONG)((fsi.EndOfFile.QuadPart + (dwChunkSize - 1)) / dwChunkSize))
{
LARGE_INTEGER ofs = {};
do
{
if (PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, ofs.HighPart, ofs.LowPart, --n ? dwChunkSize : 0))
{
UnmapViewOfFile(pv);
}
else
{
RtlGetLastNtStatus();
}
} while (ofs.QuadPart += dwChunkSize, n);
}
CloseHandle(hSection);
}
else
{
RtlGetLastNtStatus();
}
}
CloseHandle(hFile);
}
else
{
RtlGetLastNtStatus();
}
}

Related

FFMPEG remux sample without writing to file

Let's consider this very nice and easy to use remux sample by horgh.
I'd like to achieve the same task: convert an RTSP H264 encoded stream to a fragmented MP4 stream.
This code does exactly this task.
However I don't want to write the mp4 onto disk at all, but I need to get a byte buffer or array in C with the contents that would normally written to disk.
How is that achievable?
This sample uses vs_open_output to define the output format and this function needs an output url.
If I would get rid of outputting the contents to disk, how shall I modify this code?
Or there might be better alternatives as well, those are also welcomed.
Update:
As szatmary recommended, I have checked his example link.
However as I stated in the question I need the output as buffer instead of a file.
This example demonstrates nicely how can I read my custom source and give it to ffmpeg.
What I need is how can open the input as standard (with avformat_open_input) then do my custom modification with the packets and then instead writing to file, write to a buffer.
What have I tried?
Based on szatmary's example I created some buffers and initialization:
uint8_t *buffer;
buffer = (uint8_t *)av_malloc(4096);
format_ctx = avformat_alloc_context();
format_ctx->pb = avio_alloc_context(
buffer, 4096, // internal buffer and its size
1, // write flag (1=true, 0=false)
opaque, // user data, will be passed to our callback functions
0, // no read
&IOWriteFunc,
&IOSeekFunc
);
format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
AVOutputFormat * const output_format = av_guess_format("mp4", NULL, NULL);
format_ctx->oformat = output_format;
avformat_alloc_output_context2(&format_ctx, output_format,
NULL, NULL)
Then of course I have created 'IOWriteFunc' and 'IOSeekFunc':
static int IOWriteFunc(void *opaque, uint8_t *buf, int buf_size) {
printf("Bytes read: %d\n", buf_size);
int len = buf_size;
return (int)len;
}
static int64_t IOSeekFunc (void *opaque, int64_t offset, int whence) {
switch(whence){
case SEEK_SET:
return 1;
break;
case SEEK_CUR:
return 1;
break;
case SEEK_END:
return 1;
break;
case AVSEEK_SIZE:
return 4096;
break;
default:
return -1;
}
return 1;
}
Then I need to write the header to the output buffer, and the expected behaviour here is to print "Bytes read: x":
AVDictionary * opts = NULL;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
av_dict_set_int(&opts, "flush_packets", 1, 0);
avformat_write_header(output->format_ctx, &opts)
In the last line during execution, it always runs into segfault, here is the backtrace:
#0 0x00007ffff7a6ee30 in () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
#1 0x00007ffff7a98189 in avformat_init_output () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
#2 0x00007ffff7a98ca5 in avformat_write_header () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
...
The hard thing for me with the example is that it uses avformat_open_input.
However there is no such thing for the output (no avformat_open_ouput).
Update2:
I have found another example for reading: doc/examples/avio_reading.c.
There are mentions of a similar example for writing (avio_writing.c), but ffmpeg does not have this available (at least in my google search).
Is this task really this hard to solve? standard rtsp input to custom avio?
Fortunately ffmpeg.org is down. Great.
It was a silly mistake:
In the initialization part I called this:
avformat_alloc_output_context2(&format_ctx, output_format,
NULL, NULL)
However before this I already put the avio buffers into format_ctx:
format_ctx->pb = ...
Also, this line is unnecessary:
format_ctx = avformat_alloc_context();
Correct order:
AVOutputFormat * const output_format = av_guess_format("mp4", NULL, NULL);
avformat_alloc_output_context2(&format_ctx, output_format,
NULL, NULL)
format_ctx->pb = avio_alloc_context(
buffer, 4096, // internal buffer and its size
1, // write flag (1=true, 0=false)
opaque, // user data, will be passed to our callback functions
0, // no read
&IOWriteFunc,
&IOSeekFunc
);
format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
format_ctx->oformat = output_format; //might be unncessary too
Segfault is gone now.
You need to write a AVIOContext implementation.

MmCopyVirtualMemory failing, code is correct

My situation is that MmCopyVirtualMemory almost always (%99 of the time) returns STATUS_PARTIAL_COPY.
(Im operating in a Ring0 Driver)
I've tried so many different things, like using different variables sizes and types, different addresses etc... It always returns STATUS_PARTIAL_COPY.
Nothing online has helped either, its not a really common error.
Error description:
{Partial Copy} Due to protection conflicts not all the requested bytes could be copied.
My way of reading a processes memory:
DWORD64 Read(DWORD64 SourceAddress, SIZE_T Size)
{
SIZE_T Bytes;
NTSTATUS Status = STATUS_SUCCESS;
DWORD64 TempRead;
DbgPrintEx(0, 0, "\nRead Address:%p\n", SourceAddress); // Always Prints Correct Address
DbgPrintEx(0, 0, "Read szAddress:%x\n", Size); // Prints Correct Size 8 bytes
Status = MmCopyVirtualMemory(Process, SourceAddress, PsGetCurrentProcess(), &TempRead, Size, KernelMode, &Bytes);
DbgPrintEx(0, 0, "Read Bytes:%x\n", Bytes); // Copied bytes - prints 0
DbgPrintEx(0, 0, "Read Output:%p\n", TempRead); // prints 0 as expected since it failed
if (!NT_SUCCESS(Status))
{
DbgPrintEx(0, 0, "Read Failed:%p\n", Status);
return NULL;
}
return TempRead;
}
Example of how I use it:
NetMan = Read(BaseAddr + NET_MAN, sizeof(DWORD64));
//BaseAddr is a DWORD64 and NetMan is also a DWORD64
I've tripped checked my code to many times, all of it appears to be right.
After investigating MiDoPoolCopy (MmCopyVirtualMemoy calls this) it seems that its failing during the move operation:
// MiDoPoolCopy function
// Probe to make sure that the specified buffer is accessible in
// the target process.
//Wont execute (supplied KernelMode)
if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
Probing = TRUE;
ProbeForRead (FromAddress, BufferSize, sizeof(CHAR));
Probing = FALSE;
}
//Failing either here, copying inside the target process's address space to the buffer
RtlCopyMemory (PoolArea, InVa, AmountToMove);
KeUnstackDetachProcess (&ApcState);
KeStackAttachProcess (&ToProcess->Pcb, &ApcState);
//
// Now operating in the context of the ToProcess.
//
//Wont execute (supplied KernelMode)
if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
Probing = TRUE;
ProbeForWrite (ToAddress, BufferSize, sizeof(CHAR));
Probing = FALSE;
}
Moving = TRUE;
//or failing here - moving from the Target Process to Source (target process->Kernel)
RtlCopyMemory (OutVa, PoolArea, AmountToMove);
Here's the SEH returning STATUS_PARTIAL_COPY (wrapped in try and except)
//(wrapped in try and except)
//
// If the failure occurred during the move operation, determine
// which move failed, and calculate the number of bytes
// actually moved.
//
*NumberOfBytesRead = BufferSize - LeftToMove;
if (Moving == TRUE) {
//
// The failure occurred writing the data.
//
if (ExceptionAddressConfirmed == TRUE) {
*NumberOfBytesRead = (SIZE_T)((ULONG_PTR)(BadVa - (ULONG_PTR)FromAddress));
}
}
return STATUS_PARTIAL_COPY;
MmCopyVirtualMemory (undocumented struct)
NTSTATUS NTAPI MmCopyVirtualMemory
(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TargetProcess,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
Here is the source for both MmCopyVirtualMemory and MiDoPoolCopy:
https://lacicloud.net/custom/open/leaks/Windows%20Leaked%20Source/wrk-v1.2/base/ntos/mm/readwrt.c
Any help would be greatly appreciated, I've been stuck on this for to long...
I know this is old, but because I had the same issue and fixed it, maybe someone else will stumble on this in the future.
Reading your code the issue is the target address you want to copy the data. You are using a single defined DWORD64, which is when running the function a simple variable (register or on stack) and not a memory region where you can write to.
The solution is to provide a correct buffer for which you allocated memory before with malloc.
Example (you want to read a DWORD64, based on your code with some adjustments):
DWORD64* buffer = malloc(sizeof(DWORD64))
Status = MmCopyVirtualMemory(Process, (void*)SourceAddress, PsGetCurrentProcess(), (void*)buffer, sizeof(DWORD64), UserMode, &Bytes);
Do not forget to free your buffer after using to prevent a memory leak.

SetupDiGetDeviceRegistryProperty: "The data area passed to a system call is too small" error

I have a code that enumerates USB devices on Windows XP using SetupAPI:
HDEVINFO hDevInfo = SetupDiGetClassDevs( &_DEVINTERFACE_USB_DEVICE, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
for (DWORD i = 0; ; ++i)
{
SP_DEVINFO_DATA devInfo;
devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL succ = SetupDiEnumDeviceInfo(hDevInfo, i, &devInfo);
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
if (!succ) continue;
DWORD devClassPropRequiredSize = 0;
succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfo, SPDRP_COMPATIBLEIDS, NULL, NULL, 0, &devClassPropRequiredSize);
if (!succ)
{
// This shouldn't happen!
continue;
}
}
It used to work for years, but now I get FALSE from SetupDiGetDeviceRegistryProperty, last error is "The data area passed to a system call is too small".
It seems that my call parameters correspond to the documentation for this function: http://msdn.microsoft.com/en-us/library/windows/hardware/ff551967(v=vs.85).aspx
Any ideas what's wrong?
Problem was in your original code: SetupDiGetDeviceRegistryProperty function may return FALSE (and set last error to ERROR_INSUFFICIENT_BUFFER) when required property doesn't exist (or when its data is not valid, yes they have been lazy to pick a proper error code) so you should always check for ERROR_INSUFFICIENT_BUFFER as a (not so) special case:
DWORD devClassPropRequiredSize = 0;
succ = SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfo,
SPDRP_COMPATIBLEIDS,
NULL,
NULL,
0,
&devClassPropRequiredSize);
if (!succ) {
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() {
// I may ignore this property or I may simply
// go on, required size has been set in devClassPropRequiredSize
// so next call should work as expected (or fail in a managed way).
} else {
continue; // Cannot read property size
}
}
Usually you may simply ignore this error when you're reading property size (if devClassPropRequiredSize is still zero you can default it to proper constant for maximum allowed length). If property can't be read then next call SetupDiGetDeviceRegistryProperty will fail (and you'll manage error there) but often you're able to read value and your code will work smoothly.

Using VirtualQueryEx to enumerate modules at remote process doesn't return all modules

I am trying to get a list of DLLs that a given process is using, I am trying to achieve that through VirtualQueryEx. My problem is that it return to me just a partial list of DLLs and not all of them (i can see the list using Process Explorer or using VirtualQuery on the given process).
Here's the code:
char szBuf[MAX_PATH * 100] = { 0 };
PBYTE pb = NULL;
MEMORY_BASIC_INFORMATION mbi;
HANDLE h_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, iPID);
while (VirtualQueryEx(h_process, pb, &mbi, sizeof(mbi)) == sizeof(mbi)) {
int nLen;
char szModName[MAX_PATH];
if (mbi.State == MEM_FREE)
mbi.AllocationBase = mbi.BaseAddress;
if ((mbi.AllocationBase == hInstDll) ||
(mbi.AllocationBase != mbi.BaseAddress) ||
(mbi.AllocationBase == NULL)) {
// Do not add the module name to the list
// if any of the following is true:
// 1. If this region contains this DLL
// 2. If this block is NOT the beginning of a region
// 3. If the address is NULL
nLen = 0;
} else {
nLen = GetModuleFileNameA((HINSTANCE) mbi.AllocationBase,
szModName, _countof(szModName));
}
if (nLen > 0) {
wsprintfA(strchr(szBuf, 0), "\n%p-%s",
mbi.AllocationBase, szModName);
}
pb += mbi.RegionSize;
}
I am getting the result on szBuf.
This function is part of a DLL file so that it is harder for me to debug.
Right now the DLL is compiled as x64 binary and i am using it against x64 processes.
P.S i know about EnumProcessModules and i am not using it with a reason (too long:).
GetModuleFileName() only gives you the name for modules loaded in your process, not the other process. It will give you a few hits by accident, the Windows operating system DLLs will get loaded at the same address and will thus have the same module handle value.
You will need to use GetModuleFileNameEx() so you can pass the process handle.
Do note the fundamental flaw with your code as posted, you are not doing anything to ensure that you can safely use VirtualQueryEx() on another process. Which requires that you suspend all its threads so it cannot allocate memory while you are iterating it, the kind of thing a debugger does. Also required for EnumProcessModules. The failure mode is nasty, it is random and it can easily get your loop stuck, iterating the same addresses over and over again. Which is why the CreateToolHelp32Snapshot() function exists, emphasis on "snapshot".

asynchronous serial port communication in windows in c

I am getting an error when I try to run a c file which does some basic writes to a serial port. I am trying to run it asynchronously because the writes sometimes take a long time to transfer. My original version had it running synchronously with WriteFile() commands which worked fine. I am new to using OVERLAPPED and would appreciate and input concerning it.
The error I am getting is:
Debug Assertion Failed!
<path to dbgheap.c>
Line: 1317
Expression: _CrtIsValidHeapPointer(pUserData)
when the second write function is called.
In main:
{
//initialized port (with overlapped), DBC, and timeouts
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
}
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) {
//write completed. check for errors? if so throw an exception maybe?
printf("write completed--and made it to callback function\n");
}
int write_port(HANDLE hComm,BYTE* lpBuf) {
OVERLAPPED osWrite = {0};
// Create this write operation's OVERLAPPED structure's hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// error creating overlapped event handle
return 0;
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, 1, &osWrite, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
// Write is pending.
WaitForSingleObjectEx(osWrite.hEvent, 50, TRUE); //50 ms timeout
return -1; //pending
}
}
else {
return 1; //finished
}
}
That was not the full code, sorry. I was using an array of BYTEs as well, not constants. But system("pause")'s were causing my debug assertion failed errors, and after carefully looking through my code, when the WriteFileEx() was successful, it was never setting an alert/timeout on the event in the overlapped structure, so the callback function would never get called. I fixed these problems though.
I just need help with the handling/accessing a single BYTE in a structure which is allocated when a ReadFileEx() function is called (for storing the BYTE that is read so it can be handled). I need to know how to access that BYTE storage using an offset and make the overlapped structure null. Would making the overlapped structure null be as simple as setting the handle in it to INVALID_HANDLE_VALUE?
I think you have a couple of issues:
You are passing an integer as a pointer (your compiler should warn against this or preferably refuse to compile the code):
result = write_port(outPortHandle, 128);
Compare this to the definition of write_port:
int write_port(HANDLE hComm,BYTE* lpBuf) {
The above statements doesn't match. Later on you then pass a pointer to the lpBuf pointer to the WriteFileEx function by taking the address of the BYTE* -> "&lpBuf". This will not result in what you think it will do.
Even if you fix this, you will still have potential lifetime issues whenever the write is successfully queued but won't complete within the 50 ms timeout.
When using overlapped I/O, you need to make sure that the read/write buffer and the overlapped structure remain valid until the I/O is completed, cancelled or the associated device is closed. In your code above you use a pointer to an OVERLAPPED struct that lives on the stack in your call to WriteFileEx. If WriteFileEx does not complete within 50 ms, the pending I/O will have a reference to a non-existing OVERLAPPED struct and you will (hopefully) have an access violation (or worse, silently corrupted stack data somewhere in your app).
The canonical way of handling these lifetime issues (if performance is not a big issue), is to use a custom struct that includes an OVERLAPPED struct and some storage for the data to be read/written. Allocate the struct when posting the write and deallocate the struct from the I/O completion routine. Pass the address of the included OVERLAPPED struct to WriteFileEx, and use e.g. offsetof to get the address to the custom struct from the OVERLAPPED address in the completion routine.
Also note that WriteFileEx does not actually use the hEvent member, IIRC.
EDIT: Added code sample, please note:
I haven't actually tried to compile the code, there might be typos or other problems with the code.
It's not the most efficient way of sending data (allocating/deallocating a memory block for each byte that is sent). It should be easy to improve, though.
#include <stddef.h>
#include <assert.h>
#include <windows.h>
// ...
typedef struct _MYOVERLAPPED
{
OVERLAPPED ol;
BYTE buffer;
} MYOVERLAPPED, *LPMYOVERLAPPED;
// ...
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
if (NULL == lpOverlapped)
{
assert(!"Should never happen");
return;
}
LPBYTE pOlAsBytes = (LPBYTE)lpOverlapped;
LPBYTE pMyOlAsBytes = pOlAsBytes - offsetof(MYOVERLAPPED, ol);
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)pOlAsBytes;
if ((ERROR_SUCCESS == dwErrorCode) &&
(sizeof(BYTE) == dwNumberOfBytesTransfered))
{
printf("written %uc\n", pMyOl->buffer);
}
else
{
// handle error
}
free(pMyOl);
}
int write_port(HANDLE hComm, BYTE byte) {
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)malloc(sizeof(MYOVERLAPPED));
ZeroMemory(pMyOl, sizeof(MYOVERLAPPED));
pMyOl->buffer = byte;
// Issue write.
if (!WriteFileEx(hComm, &pMyOl->buffer, sizeof(BYTE), pMyOl, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
free(pMyOl);
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
return -1; //pending
}
}
else {
free(pMyOl);
return 1; //finished
}
}
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
The lpBuf argument have to be pointers to buffers, not constants.
e.g.
char buffer;
buffer = 128;
result = write_port(outPortHandle, &buffer);
buffer = 131;
result = write_port(outPortHandle, &buffer);
What you really want to do is also pass a buffer length.
e.g.
char buffer[] = { 128, 131 };
result = write_port(outPortHandle, &buffer, sizeof(buffer));
int write_port(HANDLE hComm,BYTE* lpBuf, size_t length) {
...
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, length, &osWrite, &write_compl )) {
...

Resources