OVERLAPPED结构与GetOverlappedResult函数

异步I/O调用时,我们会用到OVERLAPPED结构和函数GetOverlappedResult。以前一直对GetOverlappedResult比较困惑,这两天看书和代码才知道这个函数的主要作用不过是将Overlapped返回的结果进行一次简单的分析而已。

下面是OVERLAPPED的结构定义:
typedef struct _OVERLAPPED { 
    DWORD  Internal; 
    DWORD  InternalHigh; 
    DWORD  Offset; 
    DWORD  OffsetHigh; 
    HANDLE hEvent; 
} OVERLAPPED; 
这个结构中Internal和InternalHigh是两个返回值。写过驱动程序的人知道这两个值对应着irp的IO_STATUS_BLOCK结构:
typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

其中,Internal就是Status的值;InternalHigh就是Information的值。“Internal”这个单词表明当初MS将这个两个值就是内部使用的。
而普通调用者如何知道其含义呢?
1.当调用返回时(用ReadFile举例):
  若Internal=0时表明返回STATUS_SUCCESS,于是ReadFile返回TRUE,即成功返回;InternalHigh的值保存在lpNumberOfBytesTransferred中。
  若Internal!=0表示出现错误或PENDING,于是ReadFile返回FALSE, GetLastError值就是Internal值。

2.当1中返回ERROR_IO_PENDING时:
这个时候就需要用到GetOverlappedResult了。
  若Internal=0时表明返回STATUS_SUCCESS,于是GetOverlappedResult返回TRUE,即成功返回;InternalHigh的值保存在lpNumberOfBytesTransferred中。
  若Internal!=0表示出现错误,于是GetOverlappedResult返回FALSE, GetLastError值就是Internal值。


附源码:
WINDOWS_2000_SOURCE_CODEWIN2KPRIVATEwindowsaseclienterror.c

BOOL
WINAPI
GetOverlappedResult(
    HANDLE hFile,
    LPOVERLAPPED lpOverlapped,
    LPDWORD lpNumberOfBytesTransferred,
    BOOL bWait
    )

/*++

Routine Description:

    The GetOverlappedResult function returns the result of the last
    operation that used lpOverlapped and returned ERROR_IO_PENDING.

Arguments:

    hFile - Supplies the open handle to the file that the overlapped
        structure lpOverlapped was supplied to ReadFile, WriteFile,
        ConnectNamedPipe, WaitNamedPipe or TransactNamedPipe.

    lpOverlapped - Points to an OVERLAPPED structure previously supplied to
        ReadFile, WriteFile, ConnectNamedPipe, WaitNamedPipe or
        TransactNamedPipe.
        //这个地址就是当初调用ReadFile是传递的参数的值,一定记住不能错。

    lpNumberOfBytesTransferred - Returns the number of bytes transferred
        by the operation.

    bWait -  A boolean value that affects the behavior when the operation
        is still in progress. If TRUE and the operation is still in progress,
        GetOverlappedResult will wait for the operation to complete before
        returning. If FALSE and the operation is incomplete,
        GetOverlappedResult will return FALSE. In this case the extended
        error information available from the GetLastError function will be
        set to ERROR_IO_INCOMPLETE.
        //若当前还是ERROR_IO_PENDING则判断是否需要无限期的等待。

Return Value:

    TRUE -- The operation was successful, the pipe is in the
        connected state.

    FALSE -- The operation failed. Extended error status is available using
        GetLastError.

--*/

[html] view plain copy
 
 print?
  1. {  
  2.     DWORD WaitReturn;  
  3.   
  4.     //  
  5.     // Did caller specify an event to the original operation or was the  
  6.     // default (file handle) used?  
  7.     //  
  8.   
  9.     if (lpOverlapped->Internal == (DWORD)STATUS_PENDING ) {  
  10.         if ( bWait ) {  
  11.             //  
  12.             //现在还是PENDING,且还需要等待,则无限期等待。  
  13.             //很多人会自己调用WaitForSingleObject后再调用GetOverlappedResult,其实看起来  
  14.             //没多少必要。  
  15.             //  
  16.             WaitReturn = WaitForSingleObject(  
  17.                             ( lpOverlapped->hEvent != NULL ) ?  
  18.                                 lpOverlapped->hEvent : hFile,  
  19.                             INFINITE  
  20.                             );  
  21.             }  
  22.         else {  
  23.             WaitReturn = WAIT_TIMEOUT;  
  24.             }  
  25.   
  26.         if ( WaitReturn == WAIT_TIMEOUT ) {  
  27.             //  !bWait and event in not signalled state  
  28.             SetLastError( ERROR_IO_INCOMPLETE );  
  29.             return FALSE;  
  30.             }  
  31.   
  32.         if ( WaitReturn != 0 ) {  
  33.              return FALSE;    // WaitForSingleObject calls BaseSetLastError  
  34.              }  
  35.         }  
  36.   
  37.     *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;  
  38.   
  39.     if ( NT_SUCCESS((NTSTATUS)lpOverlapped->Internal) ){  
  40.         return TRUE;  
  41.         }  
  42.     else {  
  43.         BaseSetLastNTError( (NTSTATUS)lpOverlapped->Internal );  
  44.         return FALSE;  
  45.         }  
  46. }  


补充:(2009-10-8)

《windows核心编程》(5th版),p293.

---------------

Internal成员:这个成员用来保存已处理的I/O请求的错误码.

InternalHigh成员:当异步I/O请求完成的时候,这个成员用来保存已传输的字节数。

在当初设计OVERLAPPED结构的时候,Microsoft决定不公开Internal和InternalHigh成员(名副其实)。随着时间的推移,Microsoft认识到这些成员包含的信息会对开发人员有用,因此把它们公开了。但是,Microsoft没有改变这些成员的名字,这是因为操作系统的源代码频繁地用到它们,而Microsoft并不想为此修改源代码。

-------

由于Microsoft公开了这些成员,所以我们看到并不一定需要GetOverLappedResult了。:)

原文地址:https://www.cnblogs.com/Little-Star/p/7413199.html