SAMPLE: How To Do Asynchronous WinInet with MFC Classes

Last reviewed: September 30, 1997
Article ID: Q164983
The information in this article applies to:
  • Microsoft Visual C++, 32-bit Editions, version 5.0

SUMMARY

The MFC WinInet classes (CInternetSession, CInternetConnection, etc.) are not designed to be used with asynchronous WinInet connections or file transfer. Instead, developers looking for asynchronous-like behavior in their MFC WinInet application should implement separate synchronous WinInet sessions in secondary threads.

In the event that asynchronous WinInet using MFC is necessary, the ASYNCGET sample demonstrates some techniques for manipulating the MFC classes to do this.

The following file is available for download from the Microsoft Software Library:

 ~ Asyncget.exe (size: 37220 bytes) 

For more information about downloading files from the Microsoft Software Library, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q119591
   TITLE     : How to Obtain Microsoft Support Files from Online Services

MORE INFORMATION

A WinInet application creates an asynchronous WinInet session by using INTERNET_FLAG_ASYNC in the last parameter of the CInternetSession constructor, dwFlags.

Because some Internet operations may take a long period of time to complete, it is often desirable to make asynchronous WinInet calls, which return control to the application and run the operation in the background. This allows the application's user interface to continue to function. In addition, the application can display status updates on a lengthy download or even allow the user to halt an operation while it is executing. In this case, the recommended method for an MFC WinInet application is to not use INTERNET_FLAG_ASYNC in constructing the CInternetSession. Instead, for each necessary concurrent session, a secondary thread is spawned from the main thread. Each secondary thread is responsible for creating a new CInternetSession object without the INTERNET_FLAG_ASYNC flag and then performing any needed operations on that synchronous session, such as making an FTP connection and then downloading a file.

In some cases however, true asynchronous WinInet is really the desired goal. If this is the case, developers are encouraged to abandon their use of the MFC WinInet classes and make calls to the WinInet API directly. You can get more information about this from the Internet Client SDK at:

   http://www.microsoft.com/msdn/sdk/inetsdk/help/default.htm

Ultimately, if it is absolutely necessary to program asynchronous WinInet using the MFC classes, it is possible to do so. The ASYNCGET sample demonstrates some of the necessary techniques in a simple FTP download application. It also demonstrates some common methods for synchronizing asynchronous events as well as how to mix direct WinInet calls with MFC WinInet calls.

ASYNCGET is designed as a simple FTP file retrieval application. It proceeds in two phases - the connection phase and the download phase. The connection phase is a representation of an FTP connection; an FTP connection involves transparently connecting to an FTP server and then logging into that server. The download phase involves sending commands to the FTP server to request a file and then receiving that file to the local computer. In ASYNCGET, the download phase cannot begin until the connection phase is completed. Just to be confusing, ASYNCGET also refers to a "download" as the full process of proceeding through both phases. ASYNCGET allows for the download of only one file at a time, even though WinInet supports multiple concurrent downloads for some connection types. In addition, functionality has been added which allows the user to halt at any point in the download process.

Following is a list of the main problems that ASYNCGET addresses:

  • All CXXXConnection constructors throw exceptions when async: The constructor for these objects throws an exception whenever any error returns from its call to InternetConnect, which invalidates the object. Unfortunately, all WinInet API use the error code ERROR_IO_PENDING to signal that an asynchronous operation is still in progress. Because the MFC classes don't take this into account, this constructor needs to be wrapped in an exception-handling try/catch block.
  • Connection handle not available immediately: Not only does the connection object die as described above, but also the proper handle that you need to use with the connection object isn't available until an asynchronous call is made back into the session's status-callback. The trick here is to handle INTERNET_STATUS_HANDLE_CREATED in the status- callback and use the handle passed there to create a whole new connection object with an alternative constructor.
  • MFC doesn't pass all status-callback notifications: The WinInet API often spawn off new handles for asynchronous operations above and beyond the original connection handle. Because MFC can only pass on status- callback notifications for handles that it knows about, notifications on these handles don't get passed through to CInternetSession::OnStatusCallback. The only alternative is to forego calling EnableStatusCallback and register your own status callback directly.
  • Synchronization issues: The majority of the complexity in ASYNCGET is due to the inherent complexity of asynchronous operations in general. For more information on this subject, refer to the WinInet docs in the ActiveX SDK. Specifically in ASYNCGET, it was necessary to implement a CEvent object to ensure that the INTERNET_STATUS_HANDLE_CREATED code for connecting to a server was completed before the INTERNET_STATUS_REQUEST_COMPLETE code attempted to download a file from that server. Also, because notifications may still come in for an operation that was terminated by the user, it is necessary to check for this case and prevent any wayward code from attempting to use a CFtpConnection object that is long dead.
  • Mixing synchronous and asynchronous calls: As the WinInet documentation indicates, passing 0 for dwContext to any WinInet API should force that call to be synchronous, even if the session was created with INTERNET_FLAG_ASYNC. Preprocessor definitions have been added to the sample to allow you to selectively turn on synchronous connections and/or file-downloads. These preprocessor definitions merely change the dwContext value either in the session object or for the get-file request. See the top of GetFileDlg.cpp for more information.

Keywords          : AXSDKWinInet kbprg
Version           : 4.2
Platform          : NT WINDOWS
Solution Type     : kbcode


================================================================================


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: September 30, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.