关于WinInet的异步模式,微软给过很多例子,但我觉得下面这个是比较好理解的。
原文地址,代码贴出来,有些细节部分还要自己慢慢体会。
我在调试过程中,还参照了以下一些链接
关于GetLastError返回1201(ERROR_INTERNET_INCORRECT_HANDLE_STATE)9错误的解决办法请参见下面两个链接
http://support.genopro.com/Topic14017-59-1.aspx
http://support.microsoft.com/kb/177190
这是微软wininet的一个bug,仅当大 POST请求包要发送时,使用 HttpSendRequestEx。其他时候使用HttpSendRequest。防止12019错误
WinInet 错误代码可参照这里 http://support.microsoft.com/kb/193625
1#include<windows.h>
2#include<wininet.h>
3#include<iostream.h>
4
5HANDLE hConnectedEvent, hRequestOpenedEvent, hRequestCompleteEvent;
6HINTERNET hInstance, hConnect, hRequest;
7char *lpszUrl, *lpszServer;
8
9BOOL bAllDone = FALSE;
10BOOL bVerbose = FALSE;
11
12void __stdcall Callback(HINTERNET hInternet,
13 DWORD dwContext,
14 DWORD dwInternetStatus,
15 LPVOID lpStatusInfo,
16 DWORD dwStatusInfoLen);
17
18void main(int argc, char *argv[])
19{
20 if (argc != 3)
21 {
22 if ((argc == 4) && (argv[3][0] == 'v'))
23 bVerbose = TRUE;
24 else
25 {
26 cout << "Usage: asynchttp <server> <url> [v]" << endl;
27 cout << " <server> is the hostname of the http server" << endl;
28 cout << " <url> is the url of the object you are requesting (without the hostname)" << endl;
29 cout << " 'v' for verbose output" << endl << endl;
30 cout << " Example: asynchttp www.domain.com /docs/readme.htm v" << endl;
31 return;
32 }
33 }
34
35 lpszServer = argv[1];
36 lpszUrl = argv[2];
37
38 hConnectedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
39 hRequestOpenedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
40 hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
41
42 hInstance = InternetOpen("asynchttp",
43 INTERNET_OPEN_TYPE_PRECONFIG,
44 NULL,
45 NULL,
46 INTERNET_FLAG_ASYNC); // ASYNC Flag
47
48 if (hInstance == NULL)
49 {
50 cout << "InternetOpen failed, error " << GetLastError();
51 return;
52 }
53
54 // Setup callback function
55 if (InternetSetStatusCallback(hInstance,
56 (INTERNET_STATUS_CALLBACK)&Callback) == INTERNET_INVALID_STATUS_CALLBACK)
57 {
58 cout << "InternetSetStatusCallback failed, error " << GetLastError();
59 return;
60 }
61
62 // First call that will actually complete asynchronously even
63 // though there is no network traffic
64 hConnect = InternetConnect(hInstance,
65 lpszServer,
66 INTERNET_DEFAULT_HTTP_PORT,
67 NULL,
68 NULL,
69 INTERNET_SERVICE_HTTP,
70 0,
71 1); // Connection handle's Context
72 if (hConnect == NULL)
73 {
74 if (GetLastError() != ERROR_IO_PENDING)
75 {
76 cout << "InternetConnect failed, error " << GetLastError();
77 return;
78 }
79 // Wait until we get the connection handle
80 WaitForSingleObject(hConnectedEvent, INFINITE);
81 }
82
83
84 // Open the request
85 hRequest = HttpOpenRequest(hConnect,
86 "GET",
87 lpszUrl,
88 NULL,
89 NULL,
90 NULL,
91 INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
92 2); // Request handle's context
93 if (hRequest == NULL)
94 {
95 if (GetLastError() != ERROR_IO_PENDING)
96 {
97 cout << "HttpOpenRequest failed, error " << GetLastError();
98 return;
99 }
100 // Wait until we get the request handle
101 WaitForSingleObject(hRequestOpenedEvent, INFINITE);
102 }
103
104 if (!HttpSendRequest(hRequest,
105 NULL,
106 0,
107 NULL,
108 0))
109 {
110 if (GetLastError() != ERROR_IO_PENDING)
111 {
112 cout << "HttpSendRequest failed, error " << GetLastError();
113 return;
114 }
115 }
116
117 if (bVerbose)
118 {
119 cout << "HttpSendRequest called successfully" << endl;
120 cout.flush();
121 }
122
123 WaitForSingleObject(hRequestCompleteEvent, INFINITE);
124
125 cout << "------------------- Read the response -------------------" << endl;
126 char lpReadBuff[256];
127
128 do
129 {
130 INTERNET_BUFFERS InetBuff;
131 FillMemory(&InetBuff, sizeof(InetBuff), 0);
132 InetBuff.dwStructSize = sizeof(InetBuff);
133 InetBuff.lpvBuffer = lpReadBuff;
134 InetBuff.dwBufferLength = sizeof(lpReadBuff) - 1;
135
136 if (bVerbose)
137 {
138 cout << "Calling InternetReadFileEx" << endl;
139 cout.flush();
140 }
141
142 if (!InternetReadFileEx(hRequest,
143 &InetBuff,
144 0, 2))
145 {
146 if (GetLastError() == ERROR_IO_PENDING)
147 {
148 if (bVerbose)
149 {
150 cout << "Waiting for InternetReadFileEx to complete" << endl;
151 cout.flush();
152 }
153 WaitForSingleObject(hRequestCompleteEvent, INFINITE);
154 }
155 else
156 {
157 cout << "InternetReadFileEx failed, error " << GetLastError();
158 cout.flush();
159 return;
160 }
161 }
162
163 lpReadBuff[InetBuff.dwBufferLength] = 0;
164 cout << lpReadBuff;
165 cout.flush();
166
167 if (InetBuff.dwBufferLength == 0)
168 bAllDone = TRUE;
169
170 } while (bAllDone == FALSE);
171
172 cout << endl << endl << "------------------- Request Complete ----------------" << endl;
173
174}
175
176void __stdcall Callback(HINTERNET hInternet,
177 DWORD dwContext,
178 DWORD dwInternetStatus,
179 LPVOID lpStatusInfo,
180 DWORD dwStatusInfoLen)
181{
182 if (bVerbose)
183 {
184 cout << "Callback dwInternetStatus: " << dwInternetStatus << " Context: " << dwContext << endl;
185 cout.flush();
186 }
187
188 switch(dwContext)
189 {
190 case 1: // Connection handle
191 if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)
192 {
193 INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
194 hConnect = (HINTERNET)pRes->dwResult;
195 if (bVerbose)
196 {
197 cout << "Connect handle created" << endl;
198 cout.flush();
199 }
200 SetEvent(hConnectedEvent);
201 }
202 break;
203 case 2: // Request handle
204 switch(dwInternetStatus)
205 {
206 case INTERNET_STATUS_HANDLE_CREATED:
207 {
208 INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
209 hRequest = (HINTERNET)pRes->dwResult;
210 if (bVerbose)
211 {
212 cout << "Request handle created" << endl;
213 cout.flush();
214 }
215 SetEvent(hRequestOpenedEvent);
216 }
217 break;
218 case INTERNET_STATUS_REQUEST_SENT:
219 {
220 DWORD *lpBytesSent = (DWORD*)lpStatusInfo;
221 if (bVerbose)
222 {
223 cout << "Bytes Sent: " << *lpBytesSent << endl;
224 cout.flush();
225 }
226 }
227 break;
228 case INTERNET_STATUS_REQUEST_COMPLETE:
229 {
230 INTERNET_ASYNC_RESULT *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
231 if (bVerbose)
232 {
233 cout << "Function call finished" << endl;
234 cout << "dwResult: " << pAsyncRes->dwResult << endl;
235 cout << "dwError: " << pAsyncRes->dwError << endl;
236 cout.flush();
237 }
238 SetEvent(hRequestCompleteEvent);
239 }
240 break;
241 case INTERNET_STATUS_RECEIVING_RESPONSE:
242 if (bVerbose)
243 {
244 cout << "Receiving Response" << endl;
245 cout.flush();
246 }
247 break;
248 case INTERNET_STATUS_RESPONSE_RECEIVED:
249 {
250 DWORD *dwBytesReceived = (DWORD*)lpStatusInfo;
251 if (*dwBytesReceived == 0)
252 bAllDone = TRUE;
253 if (bVerbose)
254 {
255 cout << "Received " << *dwBytesReceived << endl;
256 cout.flush();
257 }
258 }
259
260 }
261
262 }
263
264}
265