Reputation: 2315
The docs for FILE_FLAG_OVERLAPPED on WriteFile()
say you must provide OVERLAP and recommend NULL for lpNumberOfBytesWritten
because value is misleading. However docs for GetOverlappedResult()
say to only call if WriteFile()
returned FALSE with ERROR_IO_PENDING. So that leaves the case where ReadFile()
/ WriteFile()
complete in the API call itself. How are you supposed to get the number of bytes read/written? Do you presume it's the number requested? But WriteFile()
says "When writing to a non-blocking, byte-mode pipe handle with insufficient buffer space, WriteFile returns TRUE with * lpNumberOfBytesWritten < nNumberOfBytesToWrite".
TIA!!
Upvotes: 1
Views: 7958
Reputation: 33744
If hFile was opened with
FILE_FLAG_OVERLAPPED
ThelpNumberOfBytesWritten
parameter should be set to NULL.
this is not true (mistake or lie). the lpNumberOfBytesWritten can be set to NULL, but not should. if I/O request complete synchronous with success in *lpNumberOfBytesWritten
will be valid number of bytes.
note also that lpNumberOfBytes
must not point to location which will be valid until operation is complete (like lpOverlapped
) - it can point to local variable in function for example and you can exit from function before I/O is complete - and this is will be ok too. system simply copy InternalHigh
from OVERLAPPED
to *lpNumberOfBytes
. so in pseudo code :
if (lpNumberOfBytes) *lpNumberOfBytes = (ULONG)lpOverlapped->InternalHigh;
obvivous correct value in *lpNumberOfBytes
will be only if I/O already completed with success. so and can use it only in this case. system doesn't remember value of lpNumberOfBytes
- because this it must be valid only during [Write|Read]File
call but not during I/O active (which can be longer in case asynchronous I/O)
GetOverlappedResult
we can call if I/O request complete synchronous with success (in case ReadFile
or WriteFile
, if thay return TRUE
) of if pending returned. this api can not be called only in case I/O request just fail (ReadFile
or WriteFile
return FALSE
and GetLastError() != ERROR_IO_PENDING
)
so the best always pass not 0 lpNumberOfBytes to api and use it, if api complete just with success. otherwise use GetOverlappedResult
or if say you use BindIoCompletionCallback
- you direct got dwNumberOfBytesTransfered
in callback.
so in conceptually can use next code:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
HANDLE hFile = CreateFile(*, FILE_GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
UCHAR buf[0x200];
OVERLAPPED ov = {};
ULONG NumberOfBytesRead;
ULONG dwError = BOOL_TO_ERROR(ReadFile(hFile, buf, sizeof(buf), &NumberOfBytesRead, &ov));
switch (dwError)
{
case ERROR_IO_PENDING:
dwError = BOOL_TO_ERROR(GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE));
if (dwError != NOERROR) goto __default;
[[fallthrough]];
case NOERROR:
DbgPrint("NumberOfBytesRead=%x\n", NumberOfBytesRead);
// use GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE) here also possible
break;
__default:
default:
DbgPrint("dwError = %u\n", dwError);
}
CloseHandle(hFile);
}
Upvotes: 3