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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值