• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 2, 文章 - 73, 評論 - 60, 引用 - 0
            數據加載中……

            Using WinInet HTTP functions in Full Asynchronous Mode

            Introduction

            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).

            Theory

            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.

            Detail

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

            Bibliography

            About the Author

            Benjamin Mayrargue



            Location: United States United States

            Other popular Internet / Network articles:

            posted on 2007-12-20 13:49 郭天文 閱讀(2449) 評論(0)  編輯 收藏 引用 所屬分類: VC++Windows Mobile

            伊人热热久久原色播放www| AV无码久久久久不卡蜜桃| 久久精品亚洲一区二区三区浴池 | 欧美久久综合九色综合| 久久久久久久久久久精品尤物| avtt天堂网久久精品| 久久笫一福利免费导航 | 久久99精品久久久久久9蜜桃| 99久久无色码中文字幕人妻| 97久久国产亚洲精品超碰热| 狠狠色婷婷久久一区二区| AV无码久久久久不卡网站下载| 看全色黄大色大片免费久久久 | 99久久国产综合精品成人影院| 久久99精品久久只有精品| 久久99精品国产麻豆不卡| 久久久老熟女一区二区三区| 久久伊人中文无码| 久久亚洲精品视频| 久久综合综合久久狠狠狠97色88| 久久久这里只有精品加勒比 | 伊人色综合九久久天天蜜桃| 国产精品久久久久久久久鸭 | 女同久久| 很黄很污的网站久久mimi色| 久久久综合九色合综国产| 久久久免费精品re6| 久久亚洲sm情趣捆绑调教 | 无码久久精品国产亚洲Av影片| 久久久久亚洲av综合波多野结衣 | 精品综合久久久久久97| 亚洲欧洲久久久精品| 久久亚洲国产成人影院网站 | 国产午夜久久影院| 国产精品欧美亚洲韩国日本久久 | 日产精品99久久久久久| MM131亚洲国产美女久久| 久久精品亚洲日本波多野结衣| 色综合久久久久无码专区| AV无码久久久久不卡蜜桃| 无码人妻精品一区二区三区久久久 |