WinInet 编程中如何使用异步

    技术2022-05-19  25

    WinInet 编程中如何使用异步

    在WinInet编程中,同步的使用方法如下: InternetOpen->InternetOpenUrl->HttpQueryInfo->InternetReadFile->InternetCloseHandle; 在InternetOpenUrl和InternetReadFile时会导致程序阻塞,知道操作完成,同步的好处就是比较简单,调试方便。 异步 的使用方法如下: 1)InternetOpen,需指定是异步; 2)InternetSetStatusCallback,设置回调; 3)InternetOpenUrl, 需指定回调参数; 4)WaitForSingObject或WaitForMultipleObjects,接收信号量; 5)HttpQueryInfo; 6)InternetReadFileEx, 需指定回调参数; 7)WaitForSingObject或WaitForMultipleObjects,接收信号量; 8)InternetSetStatusCallback, 卸载回调; 9)InternetCloseHandle。 异步比同步要复杂了不少,重点在于回调函数。在回调中,系统会及时返回各种系统 定义的HTTP消息,我们根据这些消息来设置某些信号量。在WaitForSingObject或WaitForMultipleObjects里,等待 这些信号(当然也可以等待用户的取消动作)。当有正确的信号返回时,继续往下的操作。下面一个例子代码:上面的理论和代码同样适用与wince或 windows mobile平台

    #include < windows.h > #include < wininet.h > #include < iostream.h > DWORD dwNumKSent; DWORD dwNumKToSend; DWORD dwNumBytesComplete  =   0 ; char  lpOutBuf[ 1024 ]; HANDLE hConnectedEvent, hRequestCompleteEvent; HINTERNET hInstance, hConnect, hRequest; char   * lpszUrl,  * lpszServer; BOOL bAllDone  =  FALSE; void  __stdcall Callback(HINTERNET hInternet,               DWORD dwContext,               DWORD dwInternetStatus,               LPVOID lpStatusInfo,               DWORD dwStatusInfoLen); void  main( int  argc,  char   * argv[]) {      if  (argc  !=   4 )     {         cout  <<   " Usage: sendreqexasync <server> <url> <size in kilobytes> "   <<  endl;         cout  <<   "    Example: sendreqexasync www.foo.com /postfolder/upload.exe 256 "   <<  endl;          return ;     }     lpszServer  =  argv[ 1 ];     lpszUrl  =  argv[ 2 ];     dwNumKToSend  =  atoi(argv[ 3 ]);     FillMemory(lpOutBuf,  1024 ' A ' );     hConnectedEvent  =  CreateEvent(NULL, FALSE, FALSE, NULL);     hRequestCompleteEvent  =  CreateEvent(NULL, FALSE, FALSE, NULL);     hInstance  =  InternetOpen( " sendreqexasync " ,                                         INTERNET_OPEN_TYPE_PRECONFIG,                                        NULL,                                        NULL,                                        INTERNET_FLAG_ASYNC);      if  (hInstance  ==  NULL)     {         cout  <<   " InternetOpen failed, error  "   <<  GetLastError();          return ;     }      if  (InternetSetStatusCallback(hInstance,                                   (INTERNET_STATUS_CALLBACK) & Callback)  ==  INTERNET_INVALID_STATUS_CALLBACK)     {         cout  <<   " InternetSetStatusCallback failed, error  "   <<  GetLastError();          return ;     }     hConnect  =  InternetConnect(hInstance,                                 lpszServer,                                 INTERNET_DEFAULT_HTTP_PORT,                                NULL,                                NULL,                                INTERNET_SERVICE_HTTP,                                 0 ,                                 1 );      if  (hConnect  ==  NULL)     {          if  (GetLastError()  !=  ERROR_IO_PENDING)         {             cout  <<   " InternetConnect failed, error  "   <<  GetLastError();              return ;         }         WaitForSingleObject(hConnectedEvent, INFINITE);     }     hRequest  =  HttpOpenRequest(hConnect,                                  " POST " ,                                 lpszUrl,                                NULL,                                NULL,                                NULL,                                INTERNET_FLAG_RELOAD  |  INTERNET_FLAG_NO_CACHE_WRITE,                                 2 );      if  (hRequest  ==  NULL)     {          if  (GetLastError()  !=  ERROR_IO_PENDING)         {             cout  <<   " HttpOpenRequest failed, error  "   <<  GetLastError();              return ;         }         WaitForSingleObject(hRequestCompleteEvent, INFINITE);     }     INTERNET_BUFFERS IntBuff;     FillMemory( & IntBuff,  sizeof (IntBuff),  0 );     IntBuff.dwStructSize =   sizeof (IntBuff);     IntBuff.dwBufferTotal  =   1024 * dwNumKToSend;     IntBuff.lpcszHeader  =   " Content-Type: text/text/r/n " ;     IntBuff.dwHeadersLength  =  lstrlen(IntBuff.lpcszHeader);      if  ( ! HttpSendRequestEx(hRequest,                              & IntBuff,                             NULL,                              0 ,                             2 ))     {          if  (GetLastError()  !=  ERROR_IO_PENDING)         {             cout  <<   " HttpSendRequestEx failed, error  "   <<  GetLastError();              return ;         }         cout  <<   " HttpSendRequestEx called successfully "   <<  endl;         cout.flush();         WaitForSingleObject(hRequestCompleteEvent, INFINITE);     }      for  (dwNumKSent  =   0 ; dwNumKSent  <  dwNumKToSend; dwNumKSent ++ )     {         DWORD dwBytesWritten;          if ( ! InternetWriteFile(hRequest,                                lpOutBuf,                                 1024 ,                                 & dwBytesWritten))         {              if  (GetLastError()  !=  ERROR_IO_PENDING)             {                 cout  <<   " InternetWriteFile failed, error  "   <<  GetLastError();                  return ;             }              else             {                 cout  <<   " InternetWriteFile completing asynchronously "   <<  endl;                 cout.flush();                 WaitForSingleObject(hRequestCompleteEvent, INFINITE);             }         }     }     cout  <<   " Calling HttpEndRequest "   <<  endl;     cout.flush();      if  ( ! HttpEndRequest(hRequest, NULL, HSR_INITIATE,  2 ))     {          if  (GetLastError()  ==  ERROR_IO_PENDING)         {             cout  <<   " HttpEndRequest called "   <<  endl;             cout.flush();             WaitForSingleObject(hRequestCompleteEvent, INFINITE);         }          else         {             cout  <<   " HttpEndRequest failed, error  "   <<  GetLastError()  <<  endl;              return ;         }     }     cout  <<   " ------------------- Read the response ------------------- "   <<  endl;      char  lpReadBuff[ 256 ];      do     {         INTERNET_BUFFERS InetBuff;         FillMemory( & InetBuff,  sizeof (InetBuff),  0 );         InetBuff.dwStructSize  =   sizeof (InetBuff);         InetBuff.lpvBuffer  =  lpReadBuff;         InetBuff.dwBufferLength  =   sizeof (lpReadBuff)  -   1 ;                  cout  <<   " Calling InternetReadFileEx "   <<  endl;         cout.flush();          if  ( ! InternetReadFileEx(hRequest,                                & InetBuff,                                0 2 ))         {              if  (GetLastError()  ==  ERROR_IO_PENDING)             {                 cout  <<   " Waiting for InternetReadFile to complete "   <<  endl;                 cout.flush();                 WaitForSingleObject(hRequestCompleteEvent, INFINITE);             }              else             {                 cout  <<   " InternetReadFileEx failed, error  "   <<  GetLastError();                 cout.flush();                  return ;             }         }         lpReadBuff[InetBuff.dwBufferLength]  =   0 ;         cout  <<  lpReadBuff;         cout.flush();          if  (InetBuff.dwBufferLength  ==   0 )              bAllDone  =  TRUE;     }  while  (bAllDone  ==  FALSE);     cout  <<  endl  <<  endl  <<   " ------------------- Request Complete ---------------- "   <<  endl; } void  __stdcall Callback(HINTERNET hInternet,               DWORD dwContext,               DWORD dwInternetStatus,               LPVOID lpStatusInfo,               DWORD dwStatusInfoLen) {     cout  <<   " Callback dwInternetStatus:  "   <<  dwInternetStatus  <<   "  Context:  "   <<  dwContext  <<  endl;     cout.flush();      switch (dwContext)     {      case   1 //  Connection handle          if  (dwInternetStatus  ==  INTERNET_STATUS_HANDLE_CREATED)         {             INTERNET_ASYNC_RESULT  * pRes  =  (INTERNET_ASYNC_RESULT  * )lpStatusInfo;             hConnect  =  (HINTERNET)pRes -> dwResult;             cout  <<   " Connect handle created "   <<  endl;             cout.flush();             SetEvent(hConnectedEvent);         }          break ;      case   2 //  Request handle          switch (dwInternetStatus)         {          case  INTERNET_STATUS_HANDLE_CREATED:             {                 INTERNET_ASYNC_RESULT  * pRes  =  (INTERNET_ASYNC_RESULT  * )lpStatusInfo;                 hRequest  =  (HINTERNET)pRes -> dwResult;                 cout  <<   " Request handle created "   <<  endl;                 cout.flush();             }              break ;          case  INTERNET_STATUS_REQUEST_SENT:             {                 DWORD  * lpBytesSent  =  (DWORD * )lpStatusInfo;                 cout  <<   " Bytes Sent:  "   <<   * lpBytesSent  <<  endl;                 dwNumBytesComplete  +=   * lpBytesSent;             }              break ;          case  INTERNET_STATUS_REQUEST_COMPLETE:             {                 INTERNET_ASYNC_RESULT  * pAsyncRes  =  (INTERNET_ASYNC_RESULT  * )lpStatusInfo;                 cout  <<   " Function call finished "   <<  endl;                 cout  <<   " dwResult:  "   <<  pAsyncRes -> dwResult  <<  endl;                 cout  <<   " dwError:   "   <<  pAsyncRes -> dwError  <<  endl;                 cout.flush();                 SetEvent(hRequestCompleteEvent);             }              break ;          case  INTERNET_STATUS_RECEIVING_RESPONSE:             cout  <<   " Receiving Response "   <<  endl;             cout.flush();              break ;          case  INTERNET_STATUS_RESPONSE_RECEIVED:             {                 DWORD  * dwBytesReceived  =  (DWORD * )lpStatusInfo;                 cout  <<   " Received  "   <<   * dwBytesReceived  <<  endl;                 cout.flush();             }         }     } }

    参考的异步类:

     1   include  < wininet.h >  2   #include  < mmsystem.h >  3    4   class  AsyncWinINet  5   {  6   public :  7      typedef  void  ( * notify_fp)( const  StringMap & );  8       9       class  thread_info 10      { 11       public : 12       thread_info( const  String &  _url,      // 请求下载的地址 (in) 13         const  StringMap &  _request_headrs,    // 请求头request_headrs(in) 14         const  notify_fp &  _pfp,       // 下载进度通知回调函 数指针 15         const  StringMap &  _pfp_param, 16        String &  _response_headrs,      // 返回头response_headrs(out)   17         const  String &  _saved_filename,     // 下载内容保存文件名(in) 18        String &  _response_content,      // 返回内容(out) 19        size_t _read_content_size)      // 控制保存在response_content中内容的长度(in)) :  20        : request_headrs(_request_headrs), pfp(_pfp), 21        pfp_param(_pfp_param),       // pfp函数传回参数 22        response_headrs(_response_headrs), saved_filename(_saved_filename), 23        response_content(_response_content), read_content_size(_read_content_size)  24       { 25         this -> response_headrs.clear(); 26         this -> response_content.clear(); 27         this -> url  =  StringUtil::EncodeURIComponent(_url); 28         for ( int  i  =   0 ; i  <   3 ++ i) 29        { 30          this -> hEvent[i]  =  CreateEvent(NULL,TRUE,FALSE,NULL); 31        } 32       } 33   34       HANDLE hThread; 35       DWORD dwThreadID; 36       HANDLE hCallbackThread; 37       DWORD dwCallbackThreadID; 38       HANDLE hEvent[ 3 ]; 39       LPVOID hInternet; 40       LPVOID hFile; 41       DWORD dwStatusCode; 42       DWORD dwContentLength; 43   44       String url;          // 请求下载的地址(in) 45        const  StringMap &  request_headrs;    // 请求头request_headrs(in) 46        const  notify_fp &  pfp;       // 下载进度通知回调函数指针 47        const  StringMap &  pfp_param;      // pfp函数传回参数 48   49       String &  response_headrs;      // 返回头response_headrs(out)   50        const  String &  saved_filename;     // 下载内容保存文件名(in) 51       String &  response_content;      // 返回内容(out) 52       size_t read_content_size;      // 控制保存在 response_content中内容的长度(in) 53      }; 54   55       /* ****************************************************************************** 56      * 函数:download 57      * 功能:下载,返回 WinINet_ERR_CODE值 58      *   说明:关于notify_fp 类型说明: 函数的参数为 StringMap类型,传回的变量名与变量值 59      * 2007-12 60      ****************************************************************************** */ 61       static  DWORD download( const  String &  url,  // 请求下载的地址(in) 62        const  StringMap &  request_headrs,    // 请求头request_headrs(in) 63        const  notify_fp &  pfp,       // 下载进度通知回调函数指针 64        const  StringMap &  pfp_param,      // pfp函数传回参数 65       String &  response_headrs,      // 返回头response_headrs(out)   66        const  String &  saved_filename,     // 下载内容保存文件名(in) 67       String &  response_content,      // 返回内容(out) 68       size_t read_content_size  =   0 );     // 控制保存在response_content中内容的长度(in) 69   70   protected : 71       static  BOOL WaitExitEvent(thread_info  * p); 72       static  DWORD WINAPI AsyncThread(LPVOID lpParameter); 73       static  DWORD WINAPI AsyncCallbackThread(LPVOID lpParameter); 74       static  VOID CALLBACK AsyncInternetCallback(HINTERNET hInternet, 75       DWORD dwContext, 76       DWORD dwInternetStatus, 77       LPVOID lpvStatusInformation, 78       DWORD dwStatusInformationLength); 79   80   }; 81  

      1  #include  " AsyncWinINet.h "   2     3  #include  " stdafx.h "   4     5  #pragma comment(lib,  " Winmm.lib " )   6  #pragma comment(lib,  " Wininet.lib " )   7     8  DWORD AsyncWinINet::download( const  Fagex::String  & url,  const  Fagex::StringMap  & request_headrs,    9      const  Fagex::AsyncWinINet::notify_fp  & pfp,  const  Fagex::StringMap  & pfp_param, Fagex::String  & response_headrs,   10      const  Fagex::String  & saved_filename, Fagex::String  & response_content, size_t read_content_size)  11  {  12     thread_info info(url, request_headrs, pfp,  13      pfp_param, response_headrs, saved_filename,  14      response_content, read_content_size);  15    16     info.hThread  =  CreateThread(NULL,   17       0 ,  18      AsyncWinINet::AsyncThread,  19       & info,  20      NULL,  21       & info.dwThreadID);  22    23     WaitForSingleObject(info.hThread, INFINITE);  // 等待子线程安全退出  24     CloseHandle(info.hThread); // 关闭线程句柄  25    26      return  TRUE;  27  }  28    29  // ---------------------------------------------------------------------  30  DWORD WINAPI AsyncWinINet::AsyncThread(LPVOID lpParameter)  31  {  32     thread_info *  p  =  (thread_info * )lpParameter;  33    34      // a. 使用标 记 INTERNET_FLAG_ASYNC 初始化 InternetOpen  35     String user_agent( " Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler ; .NET CLR 2.0.50727) " );  36     StringMap iheadrs(p -> request_headrs.begin(), p -> request_headrs.end());  37     StringMap::iterator it  =  iheadrs.find( " User-Agent " );  38      if (it  ==  iheadrs.end()) iheadrs[ " User-Agent " =  user_agent;  39      else  user_agent  =  it -> second;  40    41     p -> hInternet  =  InternetOpen(user_agent.c_str(),  42      INTERNET_OPEN_TYPE_PRECONFIG,  43      NULL,  44      NULL,  45      INTERNET_FLAG_ASYNC);  46    47      // ResetEvent(p->hEvent[0]);  48      // p->hCallbackThread = CreateThread(NULL,  49      //  0,  50      //  AsyncWinINet::AsyncCallbackThread,  51      //  p,  52      //  NULL,  53      //  &p->dwCallbackThreadID);  54      // WaitForSingleObject(p->hEvent[0], INFINITE); // 等待回调函数设置成功事件  55     InternetSetStatusCallback(p -> hInternet, AsyncWinINet::AsyncInternetCallback);  56    57     String sheadrs;  58      for (it  =  iheadrs.begin(); it  !=  iheadrs.end();  ++ it)  59     {  60      sheadrs  +=  it -> first  +   " : "   +  it -> second;  61       if (it -> second.find(StringUtil::enter)  ==  String::npos) { sheadrs  +=  StringUtil::enter; }  62     }  63     sheadrs  +=  StringUtil::enter;  64      65     DWORD start_time  =  timeGetTime();  66     ResetEvent(p -> hEvent[ 0 ]);  // 重置句柄被创建事件  67     p -> hFile  =  InternetOpenUrl(p -> hInternet, p -> url.c_str(), sheadrs.c_str(), sheadrs.length(),   68      INTERNET_FLAG_DONT_CACHE  |  INTERNET_FLAG_RELOAD, (DWORD)p);  69    70     FILE  * fp  =  fopen(p -> saved_filename.c_str(),  " w+ " );  71      while ( true )  72     {  73       if  (NULL  ==  p -> hFile)  74      {  75       DWORD dwError  =  ::GetLastError();  76        if  (ERROR_IO_PENDING  ==  dwError  ||  ERROR_SUCCESS  ==  dwError)  77       {  78         if  (WaitExitEvent(p)) {  break ; }  79       }  80        else   break ;  81      }  82    83       // 读取返回文件头  84      DWORD dwLength  =   0 ;  85      LPVOID lpOutBuffer  =  NULL;  86       while ( true // 读取response_headrs数据  87      {  88        if ( ! HttpQueryInfo(p -> hFile, HTTP_QUERY_RAW_HEADERS_CRLF,  89          lpOutBuffer,  & dwLength, NULL))  90       {  91        DWORD err_code  =  GetLastError();  92         if  (err_code  ==  ERROR_HTTP_HEADER_NOT_FOUND)  break  93         else   if (err_code  ==  ERROR_INSUFFICIENT_BUFFER)  94        {  95         lpOutBuffer  =   new   char [dwLength];  96          continue  97        }  98         else   break ;  99       } 100        break ; 101      } 102       if (lpOutBuffer  !=  NULL) 103      { 104       p -> response_headrs.append(( char * )lpOutBuffer,dwLength); 105       delete [] lpOutBuffer; 106      } 107   108       // e. 使 用 HttpQueryInfo 分析头信息 HttpQueryInfo 使用非阻塞方式,所以不用等待 109      DWORD dwStatusSize  =   sizeof (p -> dwStatusCode); 110       if  (FALSE  ==  HttpQueryInfo(p -> hFile,  // 获取返回状态码 111       HTTP_QUERY_STATUS_CODE  |  HTTP_QUERY_FLAG_NUMBER, 112        & p -> dwStatusCode,  & dwStatusSize, NULL)) {  break ; } 113      114       // 判断状态码是不是 200 115       if  (HTTP_STATUS_OK  !=  p -> dwStatusCode)  break ; 116      117      StringMap msgMap(p -> pfp_param.begin(), p -> pfp_param.end()); 118      msgMap[ " url " =  p -> url; 119   120       // 获取返回的Content-Length 121       // DWORD dwLengthSize = sizeof(p->dwContentLength);  122       // if (FALSE == HttpQueryInfo(p->hFile, 123       // HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, 124       // &p->dwContentLength, &dwLengthSize, NULL)) { p->dwContentLength = 0; } 125   126       // f. 使用标 记 IRF_ASYNC 读数据 InternetReadFileEx 127       // 为了向主线程报告进度,我们设置每次读数据最多 1024 字节 128   129       char  lpvBuffer[ 1024 ]; 130      p -> dwContentLength  =   0 // Content-Length: 202749 131       while ( true ) 132      { 133       INTERNET_BUFFERS i_buf  =  { 0 }; 134       i_buf.dwStructSize  =   sizeof (INTERNET_BUFFERS); 135       i_buf.lpvBuffer  =  lpvBuffer; 136       i_buf.dwBufferLength  =   1024 ; 137          138        // 重置读数据事件 139       ResetEvent(p -> hEvent[ 0 ]); 140        if  (FALSE  ==  InternetReadFileEx(p -> hFile,  & i_buf, IRF_ASYNC, (DWORD)p)) 141       { 142         if  (ERROR_IO_PENDING  ==  ::GetLastError()) 143        { 144          if  (WaitExitEvent(p))  break 145        } 146         else   break 147       } 148        else 149       { 150         // 在网络传输速度快,步长较小的情况 下,InternetReadFileEx 经常会直接返回成功, 151         // 因此要判断是否发生了用户要求终止子线程事件。 152         if  (WAIT_OBJECT_0  ==  WaitForSingleObject(p -> hEvent[ 2 ],  0 )) 153        { 154         ResetEvent(p -> hEvent[ 2 ]); 155          break ; 156        } 157       } 158   159        if (i_buf.dwBufferLength  ==   0 160       { 161        DWORD time  =  timeGetTime()  -  start_time; 162         if (time  !=   0 ) 163        { 164         Real speed  =  (Real)p -> dwContentLength; 165         speed  /=  ((Real)time) / 1000.0f ; 166         speed  /=   1024.0f ; 167         msgMap[ " speed " =  StringUtil::toString((DWORD)speed); 168        } 169         if (p -> pfp) p -> pfp(msgMap); 170         break ; 171       } 172        if (fp) 173       { 174        fwrite(i_buf.lpvBuffer,  sizeof ( char ), i_buf.dwBufferLength, fp); 175       } 176        if (p -> read_content_size  >  p -> response_content.size()) 177       { 178        p -> response_content.append(( char * )i_buf.lpvBuffer, i_buf.dwBufferLength); 179       } 180       p -> dwContentLength  +=  i_buf.dwBufferLength; 181      } 182       break ; 183     } 184     185      if (fp) 186     { 187      fflush(fp); fclose(fp); fp  =  NULL; 188     } 189   190      if (p -> hFile) 191     { 192      InternetCloseHandle(p -> hFile); // 关闭 m_hFile 193       while  ( ! WaitExitEvent(p))  // 等待句柄被关闭事件或者要求子线程退出事件 194      { 195       ResetEvent(p -> hEvent[ 0 ]); 196      } 197     } 198   199      // 设置子线程退出事件,通知回调线程退出 200     SetEvent(p -> hEvent[ 2 ]); 201     202      // 等待回调线程安全退出 203      // WaitForSingleObject(p->hCallbackThread, INFINITE); 204      // CloseHandle(p->hCallbackThread); 205     206      // 注销回调函数 207     InternetSetStatusCallback(p -> hInternet, NULL); 208     InternetCloseHandle(p -> hInternet); 209   210      return  TRUE; 211  } 212   213  // ------------------------------------------------------------------------------------ 214  DWORD WINAPI AsyncWinINet::AsyncCallbackThread(LPVOID lpParameter) 215  { 216     thread_info  * =  (thread_info * )lpParameter; 217     InternetSetStatusCallback(p -> hInternet, AsyncWinINet::AsyncInternetCallback); 218   219      // 通知子线程回调函数设置成功,子线程可以继续 工作 220     SetEvent(p -> hEvent[ 0 ]); 221   222      // 等待用户终止事件或者子线程结束事件 223      // 子线程结束前需要设置子线程结束事件,并等待回调线程结束 224     WaitForSingleObject(p -> hEvent[ 2 ], INFINITE); 225   226      return   0 ; 227  } 228   229  // ---------------------------------------------------------------------------- 230  VOID CALLBACK AsyncWinINet::AsyncInternetCallback(HINTERNET hInternet, 231      DWORD dwContext, 232      DWORD dwInternetStatus, 233      LPVOID lpvStatusInformation, 234      DWORD dwStatusInformationLength) 235  { 236     thread_info *  p  =  (thread_info * )dwContext; 237     238      // 在我们的应用中,我们只关心下面三个状态 239      switch (dwInternetStatus) 240     { 241      // 句柄被创建 242      case  INTERNET_STATUS_HANDLE_CREATED: 243      p -> hFile  =  (HINTERNET)(((LPINTERNET_ASYNC_RESULT) 244       (lpvStatusInformation)) -> dwResult); 245       break ; 246     247      // 句柄被关闭 248      case  INTERNET_STATUS_HANDLE_CLOSING: 249      SetEvent(p -> hEvent[ 1 ]); 250       break ; 251   252      // 一个请求完成,比如一次句柄创建的请求,或者一次读数据的请求 253      case  INTERNET_STATUS_REQUEST_COMPLETE: 254       if  (ERROR_SUCCESS  ==  ((LPINTERNET_ASYNC_RESULT) 255       (lpvStatusInformation)) -> dwError) 256      {  257        // 设置句柄被创建事件或者读数据成功 完成事件 258       SetEvent(p -> hEvent[ 0 ]); 259      } 260       else 261      {  262        // 如果发生错误,则设置子线程退出事件 这里也是一个陷阱,经常会忽视处理这个错误, 263       SetEvent(p -> hEvent[ 2 ]); 264      } 265       break ; 266   267      case  INTERNET_STATUS_CONNECTION_CLOSED: 268      SetEvent(p -> hEvent[ 2 ]); 269       break ; 270   271     } 272  } 273   274  // -------------------------------------------------------------------- 275  BOOL AsyncWinINet::WaitExitEvent(thread_info  * p) 276  { 277     DWORD dwRet  =  WaitForMultipleObjects( 3 , p -> hEvent, FALSE, INFINITE); 278     279      switch  (dwRet) 280     { 281      case  WAIT_OBJECT_0: // 句柄被创建事件或者 读数据请求成功完成事件 282      case  WAIT_OBJECT_0 + 1 : // 句柄被关闭事件 283      case  WAIT_OBJECT_0 + 2 : // 用户要求终止子线程事件或者发生错误事件 284       break ; 285     } 286      return  WAIT_OBJECT_0  !=  dwRet; 287  } 288


    最新回复(0)