关于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
5
HANDLE hConnectedEvent, hRequestOpenedEvent, hRequestCompleteEvent;
6
HINTERNET hInstance, hConnect, hRequest;
7
char *lpszUrl, *lpszServer;
8
9
BOOL bAllDone = FALSE;
10
BOOL bVerbose = FALSE;
11
12
void __stdcall Callback(HINTERNET hInternet,
13
DWORD dwContext,
14
DWORD dwInternetStatus,
15
LPVOID lpStatusInfo,
16
DWORD dwStatusInfoLen);
17
18
void 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
176
void __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