您的位置:首页 > 理论基础 > 计算机网络

Using WinInet HTTP functions in Full Asynchronous Mode

2012-08-06 14:41 761 查看


Detail

http://www.codeproject.com/Articles/822/Using-WinInet-HTTP-functions-in-Full-Asynchronous

After the theory, let’s look at some code for some of the points:


1&2: Create the connection using INTERNET_FLAG_ASYNC and setup the callback func:


Collapse | Copy
Code
m_Session = InternetOpen(AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, INTERNET_FLAG_ASYNC);
InternetSetStatusCallback( m_Session,
(INTERNET_STATUS_CALLBACK)InternetCallbackFunc );


3&4: Open the connection using InternetOpenUrl and wait for INTERNET_STATUS_REQUEST_COMPLETE

Use the
lParam
to send a session identifier to your callback. I always use the
this
pointer of my class
for it. I assume you know how to handle callbacks.


Collapse | Copy
Code
InternetOpenUrl( m_Session, uurl, NULL, 0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE |
INTERNET_FLAG_NO_CACHE_WRITE, (LPARAM)this );


The callback will receive a lots of messages then. Here are their orders along with the
dwInternetStatus
value:


Collapse | Copy
Code
[openUrl] InternetStatus: 60 INTERNET_STATUS_HANDLE_CREATED
**At this point you can save the HINTERNET handle using code like this in your callback:
INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
m_hHttpFile = (HINTERNET)(res->dwResult);

[openUrl] InternetStatus: 10
[openUrl] InternetStatus: 11
[openUrl] InternetStatus: 20
[openUrl] InternetStatus: 21
[openUrl] InternetStatus: 30
[openUrl] InternetStatus: 31
[openUrl] InternetStatus: 40
[openUrl] InternetStatus: 41
[openUrl] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE


5: Extract the content-length and set up the INTERNET_BUFFERS structure

Once you have the handle, try to call
HttpQueryInfo
with
HTTP_QUERY_CONTENT_LENGTH
to get the size of
the data to retrieve. This function can fail if the content-length field is not in the HTTP header.

Set up the
INTERNET_BUFFERS
structure.


Collapse | Copy
Code
INTERNET_BUFFERS ib = { sizeof(INTERNET_BUFFERS) };
ib.lpvBuffer = your allocated buffer
ib.dwBufferLength = its length


The
dwBufferTotal
is provided for your own use and is never modified by WinInet (as
far as I know). I use it to store the total size of the received data.


6&7&8 Read the remaining data in a loop

Use
InternetReadFileEx
with the
IRF_ASYNC
flag to read the remaining data asynchronously. Don’t use
InternetReadFile
since
it is a synchronous function. You must loop on
InternetReadFileEx
while the
ib.dwBufferLength
is not
0. Before each iteration you must adjust the
lpvBuffer
pointer and reset the
dwBufferLength
members of
ib
:
add the received length to the pointer and set
dwBufferLength
to your remaining buffer size.


Collapse | Copy
Code
//Start the pump
BOOL bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
if(!bOk && GetLastError()==ERROR_IO_PENDING)
wait...

//Pump
while( bOk && ib.dwBufferLength!=0 )
{
(adjust ib values)
bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
if(!bOk && GetLastError()==ERROR_IO_PENDING)
wait...
}


Your callback should receive these notifications (maybe more than once):


Collapse | Copy
Code
[connect] InternetStatus: 40 (receiving response)
[connect] InternetStatus: 41 (response received)
[connect] InternetStatus: 50
[connect] InternetStatus: 51
and maybe
[connect] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE


The last is received only if
GetLastError()
returned
ERROR_IO_PENDING
. If you stored the total data size
(in bytes) in the
dwBufferTotal
member, use it to set the final “0” in your string buffer (if it’s a string).


Collapse | Copy
Code
buf[ib.dwBufferTotal] = 0;


9 Close the connection handle


Collapse | Copy
Code
InternetCloseHandle( m_httpFile );


The callback will receive this notification when the handle is closed:


Collapse | Copy
Code
[connect] InternetStatus: 70 INTERNET_STATUS_HANDLE_CLOSING


In most error cases, the connection is closed unexpectedly. If it happens you’ll receive a 70 followed by a 100 (
INTERNET_STATUS_REQUEST_COMPLETE
). This can happen anywhere during
the process.


10 Before closing the m_Session handle

You must deregister the callback:


Collapse | Copy
Code
InternetSetStatusCallback( m_Session, NULL );


This should help those who tried to go through asynchronous mode in WinInet! Sorry, there are no attached files but you should be able to use the functions
and create nice classes now. If you liked this article please add an entry inmy guestbook and buy me a license of my shareware.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: