News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

WriteFile - Async Write

Started by Astro, May 18, 2010, 04:08:38 PM

Previous topic - Next topic

Astro

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.

clive

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.
It could be a random act of randomness. Those happen a lot as well.

clive

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);
}
It could be a random act of randomness. Those happen a lot as well.

Astro

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.