OVERLAPPED结构与GetOverlappedResult函数

幽沉谢世事,俯默窥唐虞。这篇文章主要讲述OVERLAPPED结构与GetOverlappedResult函数相关的知识,希望能为你提供帮助。
【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_CODE\WIN2K\PRIVATE\windows\base\client\error.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了。:)



















































































    推荐阅读