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:
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.
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:
[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.
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 useInternetReadFile
since it is a synchronous function. You must loop on InternetReadFileEx
while theib.dwBufferLength
is not 0. Before each iteration you must adjust the lpvBuffer
pointer and reset thedwBufferLength
members of ib
: add the received length to the pointer and set dwBufferLength
to your remaining buffer size.
//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):
[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).
buf[ib.dwBufferTotal] = 0;
9 Close the connection handle
InternetCloseHandle( m_httpFile );
The callback will receive this notification when the handle is closed:
[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:
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.