Hi,
I'm going nuts over this!!! Insert mad/exploding smilie here.
It seems I can read the port fine. No problems there. The problem is when I write to the port.
I've got a function set up as follows, but it doesn't always return from GetOverlappedResult (particularly when writing more than 1 byte per call to WriteFile).
I'm very close to re-writing the whole thing, but want to avoid that if possible. Some of the code in the following is me trying to figure out just what is going on.
I'm running this on XP SP3. Your behavior/results may be different on Vista/Win 7 as MS screwed up the functions.
OL = pointer to overlapped structure
Len = length of data to write (bytes)
Buffer = pointer to the data to send
Port = the handle to the port to write to (must be opened in async mode)
AsyncWritePort proc Port:DWORD,Buffer:DWORD,Len:DWORD,OL:DWORD
push 0
push 0
push 1 ; manual reset
push 0
call CreateEvent
mov hAsyncEvent,eax
mov ecx,hAsyncEvent
mov eax,OL
assume eax:ptr _OVERLAPPED
mov [eax].hEvent,ecx
assume eax:nothing
push OL ; overlapped IO
lea eax,BytesWritten
push eax
push Len ; bytes to write
push Buffer
push Port
call WriteFile
print "WriteFile called...",13,10
@@:
push 1 ; TRUE (wait until finished before returning)
lea eax,BytesWritten
push eax
push OL
push Port
call GetOverlappedResult
print "GetOverlappedResult returned",13,10
call GetLastError
cmp eax,997 ; ERROR_IO_PENDING
jz @F
print str$(eax),13,10
push eax
call GetErrorCode
push 5000
call Sleep
jmp @B
@@:
push hAsyncEvent
call ResetEvent
print "Leaving AsyncWritePort. Bytes Written: "
print str$(BytesWritten),13,10
ret 16
AsyncWritePort endp
Best regards,
Robin.
It's been a while, but as I recall you have to check the status of the WriteFile first. If it failed, you then check the GetLastError() for ERROR_IO_PENDING, and if it is you then GetOverlappedResult(). If THAT fails, then you can GetLastError() a second time to get the actual fault code.
If WriteFile succeeds the process has ALREADY completed (in memory, cache, or quickly). If WriteFile fails, GetLastError() will have the error already or ERROR_IO_PENDING.
I would also reset the Offset and OffsetHigh members of OVERLAPPED
Create the event once, when you create the file, and use it repeatedly. ie hFile and hEvent
Destroy the event when you close the file.
You are resetting the event, but not destroying it. This will cause a resource leak. No need to reset it.
Pseudo code in C, I haven't tested it vigorously, it is built after a DeviceIoControl method I created a long time ago (in a galaxy far far away..).
I did evaluate a 123, 1, 123, 61 write sequence that seemed to work without problems.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
BOOLEAN WriteFileAsync(HANDLE hFile, HANDLE hEvent, BYTE *Buffer, DWORD Length, DWORD *dwWrite, DWORD *dwError)
{
BOOLEAN Status;
DWORD Error;
OVERLAPPED Overlapped;
Overlapped.Offset = 0;
Overlapped.OffsetHigh = 0;
Overlapped.hEvent = hEvent;
Status = WriteFile(hFile, Buffer, Length, dwWrite, &Overlapped);
if (Status == 0)
{
Error = GetLastError();
if (Error == ERROR_IO_PENDING)
{
Status = GetOverlappedResult(hFile, &Overlapped, dwWrite, TRUE);
if (Status == 0)
Error = GetLastError();
}
}
if ((Status == 0) && (dwError != NULL))
*dwError = Error;
return(Status);
}
int main(int argc, char **argv)
{
HANDLE hFile;
HANDLE hEvent;
DWORD dwWrite;
DWORD dwError;
BYTE Buffer[123];
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
hFile = CreateFile(
"FOO.BAR",
GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS,
FILE_FLAG_OVERLAPPED, NULL);
if ((hEvent != INVALID_HANDLE_VALUE) && (hFile != INVALID_HANDLE_VALUE))
{
if (WriteFileAsync(hFile, hEvent, (BYTE *)&Buffer, sizeof(Buffer), &dwWrite, &dwError) == 0) // Failed
{
printf("Failed, error %d\n", dwError);
}
else
{
printf("Success, wrote %d bytes\n", dwWrite);
}
}
if (hEvent != INVALID_HANDLE_VALUE)
CloseHandle(hEvent);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return(0);
}
Hi,
Been busy doing other things. I hadn't forgotten your reply! Thankyou. I'll study it later.
I've since found that XP, Vista and Win 7 all handle this differently. It was broken in Vista, then hacked around to make it work both ways in 7. :dazzled:
Best regards,
Robin.