Click here to Skip to main content
12,622,517 members (33,437 online)
Click here to Skip to main content
Add your own
alternative version


99 bookmarked

Using WinInet HTTP functions in Full Asynchronous Mode

, 29 Jan 2001
Rate this:
Please Sign up or sign in to vote.
Using WinInet functions asynchronously is a nightmare since no samples exist. Here's one!


If you have ever dug into the MSDN for WinInet API, you noticed that it can be used asynchronously and that it is the recommended way to use it.

If then you decide to use it, you won’t find any explanation of how to use it asynchronously. And no samples are available anywhere on Internet. After a long research and lots of testing, I finally managed to reconstruct a big part of the (voluntary?) missing documentation.

Why asynchronous is better? Because it can handle timeouts correctly. Just what’s missing in WinInet under IE5.5.

If you try to use TerminateThread or CloseHandle functions to handle timeouts (these methods are given in MSDN articles), you’ll fall into unrecoverable leaks of all kinds.

This has been tested successfully with: IE4.01SP3, IE5.0, IE5.01, IE5.5SP1 under WinNT4 on mono and multiprocessor machines, under a stressed environment (15 concurrent instances running non-stop for 12 hours on multi-proc NT server machines).


To use WinInet functions in full asynchronous mode, you must do things in the right order:

  1. Use INTERNET_FLAG_ASYNC to open the session
  2. Set a status callback using InternetSetStatusCallback
  3. Open the connection using InternetOpenUrl
  4. If InternetOpenUrl returned NULL and GetLastError is ERROR_IO_PENDING:
    • wait for the INTERNET_STATUS_HANDLE_CREATED notification in the callback, and save the connection Handle.
    • wait for the INTERNET_STATUS_REQUEST_COMPLETE notification in the callback before going further.
  5. Extract the content-length from the header and set up an INTERNET_BUFFERS structure:
    • dwStructSize = sizeof(INTERNET_BUFFERS)
    • lpvBuffer = your allocated buffer
    • dwBufferLength = its length
  6. Use InternetReadFileEx with the IRF_ASYNC flag to read the remaining data asynchronously. Don’t use InternetReadFile since it is a synchronous function.
  7. If InternetReadFileEx returned False and GetLastError is ERROR_IO_PENDING: wait for the INTERNET_STATUS_REQUEST_COMPLETE notification in the callback before going further.

    Warning: INTERNET_BUFFERS members are modified asynchronously (only the dwBufferLength member and the content of the buffer).

  8. If the dwBufferLength member is not 0, move the lpvBuffer pointer from this amount and subtract this amount from the buffer length so dwBufferLength reflects the remaining size lpvBuffer points to, then loop to 6.
  9. Close the connection handle with InternetCloseHandle and wait for INTERNET_STATUS_HANDLE_CLOSING and the facultative INTERNET_STATUS_REQUEST_COMPLETE notification (sent only if an error occurs – like a sudden closed connection -, you must test the cases).

At this state, you can either begin a new connection process or close the session handle. But before closing it, you should un-register the callback function.


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:

                          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, 

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

**At this point you can save the HINTERNET handle using code like this in your callback:
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

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.

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.

//Start the pump
BOOL bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
if(!bOk && GetLastError()==ERROR_IO_PENDING)

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

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 in my guestbook and buy me a license of my shareware.



This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Benjamin Mayrargue
United States United States
No Biography provided

You may also be interested in...


Comments and Discussions

SuggestionI propose to get rid of async mode [modified] Pin
XinyiChen20-Aug-11 7:19
memberXinyiChen20-Aug-11 7:19 
GeneralAsyncdemo no longer available Pin
Mike Ady5-Jul-10 4:49
memberMike Ady5-Jul-10 4:49 
GeneralDownload manager using InternetReadFileEx Pin
sairamdp12-Apr-10 0:22
membersairamdp12-Apr-10 0:22 
Questionhow to use InternetSetFilePointer in asyc mode? Pin
liaosea17-Jun-08 21:59
memberliaosea17-Jun-08 21:59 
QuestionQuestion Pin
Alireza_136210-Feb-08 22:50
memberAlireza_136210-Feb-08 22:50 
QuestionWhat if I don't need to read any reply? Pin
Sean OConnor21-Aug-07 10:49
memberSean OConnor21-Aug-07 10:49 
AnswerRe: What if I don't need to read any reply? [modified] Pin
Benjamin.Mayrargue17-Nov-07 2:24
memberBenjamin.Mayrargue17-Nov-07 2:24 
GeneralRe: What if I don't need to read any reply? Pin
Sean O'Connor1-Apr-08 0:06
memberSean O'Connor1-Apr-08 0:06 
GeneralDoes not work when using modem Pin
vonuyx6-Jun-07 4:36
membervonuyx6-Jun-07 4:36 
Generalman, YOUR "code" is a nightmare Pin
kkez30-Jan-05 6:12
memberkkez30-Jan-05 6:12 
GeneralRe: man, YOUR "code" is a nightmare Pin
cristip3216-Mar-05 22:41
membercristip3216-Mar-05 22:41 
GeneralRe: man, YOUR "code" is a nightmare Pin
Ultra_Ca30-Aug-06 10:40
memberUltra_Ca30-Aug-06 10:40 
GeneralRe: man, YOUR "code" is a nightmare Pin
Benjamin.Mayrargue17-Nov-07 2:25
memberBenjamin.Mayrargue17-Nov-07 2:25 
GeneralInternetReadFileEx returns truncated data when HTTP answers are in “Transfer-Encoding: chunked” mode Pin
Anonymous17-Nov-04 4:52
sussAnonymous17-Nov-04 4:52 

I am experimenting problems using wininet asynchonously on smartphone 2003. The problem is data are sometimes truncated when receiving “Transfer-Encoding: chunked” HTTP answers.

I proceed as follow:

1- I call InternetOpen and set the callback using InternetSetStatusCallback
2- Then I use InternetConnect to prepare the connection
3- I create the request with HttpOpenRequest (POST request, HTTP/1.1)
4- I set the required HTTP header using HttpAddRequestHeaders
5- Then I send the request with HttpSendRequest
6- Upon reception of INTERNET_STATUS_REQUEST_COMPLETE event (in the callback) I start reading the received data using the following piece of code:

DWORD nbAvailBytes=0;
ib.dwBufferLength = 1; // to enter the loop

while (ok && ib.dwBufferLength!=0)
// reallocate buffer to have space for available data
if (spaceLeftInBuffer == 0)
inputStreamBuffer = (MB_UBYTE*)realloc(inputStreamBuffer, totalLen + LEN);
spaceLeftInBuffer = LEN;

// init struct
ib.lpvBuffer = inputStreamBuffer+totalLen;
ib.dwBufferLength = spaceLeftInBuffer;

ResetEvent(g_hCompleteEvent); // event set when receiving INTERNET_STATUS_REQUEST_COMPLETE event

// read data
ok = InternetReadFileEx( hRequest, &ib, IRF_ASYNC | HSR_CHUNKED, (LPARAM)this);

if (!ok)
if(GetLastError() == ERROR_IO_PENDING)
ok = TRUE; // to continue the loop
if (WaitForSingleObject(g_hCompleteEvent, CONNECTION_TIMEOUT) == WAIT_TIMEOUT)
return ErrNetwork;
// update totalLen
totalLen = totalLen + ib.dwBufferLength;
spaceLeftInBuffer = spaceLeftInBuffer - ib.dwBufferLength;


The problem occurs when the network becomes slow. In this case InternetReadFileEx returns a nul ib.dwBufferLength and then we exit the reading loop. We get then truncated data.

One trick giving a bit more reliability is adding some delay in the loop (using Sleep()) but this is only a trick.

I have also tryied without success to set HTTP version to 1.0 (as trunk are only used in version 1.1). The outgoing HTTP request are still in version 1.1.

I thank you all for your help.


Questionhow to do HttpQueryInfo? Pin
HuaHsin12-Jul-04 23:20
memberHuaHsin12-Jul-04 23:20 
AnswerRe: how to do HttpQueryInfo? Pin
Abhijeet Dev5-Nov-04 10:05
memberAbhijeet Dev5-Nov-04 10:05 
GeneralWinInet by MSDN!!! Pin
Chulips2-Jun-04 8:19
memberChulips2-Jun-04 8:19 
GeneralRe: WinInet by MSDN!!! Pin
cristip3216-Mar-05 22:45
membercristip3216-Mar-05 22:45 
GeneralDetecting a resource Pin
Chulips1-Jun-04 12:51
memberChulips1-Jun-04 12:51 
GeneralRe: Detecting a resource Pin
bbb28046710-Jul-08 3:31
memberbbb28046710-Jul-08 3:31 
GeneralCookie Pin
rgm20-May-04 10:02
sussrgm20-May-04 10:02 
QuestionHTTP_QUERY_CONTENT_LENGTH not returning size.. ? Pin
G33K31-Mar-04 12:58
memberG33K31-Mar-04 12:58 
AnswerRe: HTTP_QUERY_CONTENT_LENGTH not returning size.. ? Pin
tomwg1234529-Dec-09 19:46
membertomwg1234529-Dec-09 19:46 
GeneralHttpQueryInfo API is not retrieving the proper Cookie data. Pin
shanpalaniram26-Jan-04 0:40
membershanpalaniram26-Jan-04 0:40 
K-PAX15-Sep-03 23:59
memberK-PAX15-Sep-03 23:59 
Zinkyu19-Sep-07 5:22
memberZinkyu19-Sep-07 5:22 
GeneralSSL and/or authentication Pin
Robert J28-Aug-03 3:11
memberRobert J28-Aug-03 3:11 
GeneralNeed full code Pin
no_body6915-Jun-03 23:21
memberno_body6915-Jun-03 23:21 
GeneralDont't use aync mode anymore! Pin
Lucky Hocking30-Jan-03 20:34
sussLucky Hocking30-Jan-03 20:34 
QuestionWininet. Really works? Pin
Eric CHAUVET29-Dec-02 15:20
sussEric CHAUVET29-Dec-02 15:20 
QuestionHow to implemente proxy authentication Pin
Anonymous26-Mar-02 16:51
memberAnonymous26-Mar-02 16:51 
GeneralInternetWriteFile Pin
Ed K28-Dec-01 13:06
memberEd K28-Dec-01 13:06 
GeneralRe: InternetWriteFile Pin
Chaitanya Ram31-Jan-02 20:04
memberChaitanya Ram31-Jan-02 20:04 
GeneralRe: InternetWriteFile Pin
tyounsi4-May-04 12:10
membertyounsi4-May-04 12:10 
GeneralRe: InternetWriteFile Pin
Anonymous7-Jun-05 5:13
sussAnonymous7-Jun-05 5:13 
GeneralRe: InternetWriteFile Pin
Member 342329118-May-09 3:36
memberMember 342329118-May-09 3:36 
Volodya Orlenko7-Dec-01 7:22
memberVolodya Orlenko7-Dec-01 7:22 
Volodya Orlenko12-Dec-01 5:26
memberVolodya Orlenko12-Dec-01 5:26 
Anonymous31-Mar-03 22:23
sussAnonymous31-Mar-03 22:23 
jweston25-Aug-04 12:43
memberjweston25-Aug-04 12:43 
foetalstalk29-Oct-04 4:48
memberfoetalstalk29-Oct-04 4:48 
Lou Montulli6-Jul-05 18:25
sussLou Montulli6-Jul-05 18:25 
GeneralAsync Challenge Pin
F X4-Dec-01 0:20
memberF X4-Dec-01 0:20 
GeneralThe wonderful world of the WinInet Async API Pin
Rhea1-Dec-01 6:13
memberRhea1-Dec-01 6:13 
GeneralRe: The wonderful world of the WinInet Async API Pin
tntntn2-Dec-01 6:14
membertntntn2-Dec-01 6:14 
GeneralInternetReadFileEx & Unicode Pin
tntntn22-Nov-01 22:17
membertntntn22-Nov-01 22:17 
GeneralRe: InternetReadFileEx & Unicode Pin
Niels Keurentjes30-Nov-01 4:30
memberNiels Keurentjes30-Nov-01 4:30 
GeneralRe: InternetReadFileEx & Unicode Pin
Rhea1-Dec-01 5:46
memberRhea1-Dec-01 5:46 
GeneralFinding out the file's size Pin
Anonymous12-Sep-01 13:30
memberAnonymous12-Sep-01 13:30 
GeneralRe: Finding out the file's size Pin
Anonymous27-Oct-01 0:44
memberAnonymous27-Oct-01 0:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.161128.1 | Last Updated 30 Jan 2001
Article Copyright 2000 by Benjamin Mayrargue
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid