| Tenouk C & C++ | MFC Home | C++, MFC, Winsock & WinInet 7 | IIS Programming 1 | Download | Site Index |


 

 

 

 

 

C++, MFC, Winsock and WinInet Part 8

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2 and some Figure screen snapshots have been taken on Windows 2000 server. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer.  Supplementary item is WEBSITE.

  1. Running MYEX33A

  2. Back to the Story

  3. Building and Testing MYEX33A

  4. Using Telnet

  5. Building a Web Client with CHttpBlockingSocket

  6. The MYEX33A Winsock Client

  7. MYEX33A Support for Proxy Servers

  8. Testing the MYEX33A Winsock Client

  9. WinInet

  10. WinInet's Advantages over Winsock

  11. The MFC WinInet Classes

  12. CInternetSession

  13. CHttpConnection

  14. CFtpConnection, CGopherConnection

  15. CInternetFile

  16. CHttpFile

  17. CFtpFileFind, CGopherFileFind

  18. CInternetException

  19. Internet Session Status Callbacks

  20. A Simplified WinInet Client Program

  21. Building a Web Client with the MFC WinInet Classes

  22. The MYEX33A WinInet Client #1: Using CHttpConnection

  23. Testing the WinInet Client #1

  24. The MYEX33A WinInet Client #2: Using OpenURL()

  25. Testing the WinInet Client #2

  26. Asynchronous Moniker Files

  27. Monikers

  28. The MFC CAsyncMonikerFile Class

  29. Using the CAsyncMonikerFile Class in a Program

  30. Asynchronous Moniker Files vs. WinInet Programming

 

 

Running MYEX33A

 

Create a directory named WEBSITE under your project directory and copy the following sample files. You can create your own files if needed, provided the html file names are same, else you have to do some source code modifications.

 

WinInet, Winsock, MFC andC++ - Figure 83: Creating the root directory of the web for MYEX33A.

 

Figure 83: Creating the root directory of the web for MYEX33A.

 

Build and run this program. Let start our web server by selecting the Internet Start Server menu and make sure the IIS/World Wide Web is not running, else you need to stop it.

 

WinInet, Winsock, MFC andC++ - Figure 84: The IIS/WWW Publishing service was stopped to give a way for our own web server application.

 

Figure 84: The IIS/WWW Publishing service was stopped to give a way for our own web server application.

 

Next, start the server.

 

WinInet, Winsock, MFC andC++ - Figure 85: MYEX33A in action, starting the web server.

 

Figure 85: MYEX33A in action, starting the web server.

 

It seems that our status indicator not working lol! Forget it; next, select the Request (Winsock) client menu.

 

WinInet, Winsock, MFC andC++ - Figure 86: Testing the Winsock client request

 

Figure 86: Testing the Winsock client request

 

The following message should be displayed.

 

WinInet, Winsock, MFC andC++ - Figure 87: The Winsock client message.

 

Figure 87: The Winsock client message.

 

Together with the following dialog (the html source code).

 

WinInet, Winsock, MFC andC++ - Figure 88: Winsock client request html code.

 

Figure 88: Winsock client request html code.

 

Next, test the Request (WinInet) client menu.

 

WinInet, Winsock, MFC andC++ - Figure 89: Testing the WinInet client request.

 

Figure 89: Testing the WinInet client request.

 

The WinInet client html source should be displayed.

 

WinInet, Winsock, MFC andC++ - Figure 90: The WinInet client request html source code.

 

Figure 90: The WinInet client request html source code.

 

And the WinInet message is shown below.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 91: The WinInet client request message.

 

To change the configuration through the Configuration menu, you have to stop the server (select Stop Server menu). The following is the property page of the Configuration menu.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 92: The Configuration property page.

 

You can clear all the child window by using the Clear All context menu by right clicking anywhere in the child window.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 93: Clear All context menu in action.

 

Finally let test the Address bar. Make sure you are online. Type any URL such as shown below. Just click the OK for the warning dialog as shown below, the html size not fit to the declared buffer size in our source code.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 94: Testing the URL client request.

 

The following is the URL client html source.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 95: www.yahoo.com html source code.

 

Try our own test page: http://localhost/.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 96: The local test page

 

Check your project Debug window to see the previous activities. Well, that all!

 

Back to the Story: Building and Testing MYEX33A

 

Open the myex33a project in Visual C++, and then build the project. A directory under MYEX33A, called Website, contains some HTML files and is set up as the MYEX33A server's home directory, which appears to clients as the server's root directory. If you have another HTTP server running on your computer, stop it now. If you have installed IIS along with Windows NT Server, it is probably running now, so you must run the Internet Service Manager (Internet Information Services) program from the Administrative Tools menu. Select the web site folder for example, Default Web Site as shown below and then click the stop button (the one with the square). MYEX33A reports a bind error (10048) if another server is already listening on port 80.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 97: Stopping the web server.

 

Run the program from the debugger, and then choose Start Server from the Internet menu.

 

WinInet, Winsock, MFC andC++ - Figure 91: The WinInet client request message.

 

Figure 98: Starting our own, MYEX33A web server.

 

Now go to your Web browser and type localhost. You should see the Welcome to the Nothing test page complete with simple graphics.

 

WinInet, Winsock, MFC andC++ - Figure 99: MYEX33A – accessing web through browser.

 

Figure 99: MYEX33A – accessing web through browser.

 

 

The MYEX33A window should look like this.

 

WinInet, Winsock, MFC andC++ - Figure 100: MYEX33A – the web server activities.

 

Figure 100: MYEX33A – the web server activities.

 

Look at the Visual C++ debug window for a listing of the client's request headers. If you click the browser's Refresh button, you might notice MYEX33A error messages like this:

 

WINSOCK ERROR--SERVER: Send error #10054 -- 10/05/96 04:34:10 GMT

 

This tells you that the browser read the file's modified date from the server's response header and figured out that it didn't need the data because it already had the file in its cache. The browser then closed the socket, and the server detected an error. If the MYEX33A server were smarter, it would have checked the client's If-Modified-Since request header before sending the file.

 

Using Telnet

 

The Telnet utility is included with Windows Operating Systems. It's useful for testing server programs such as MYEX33A. With Telnet, you're sending one character at a time, which means that the server's CBlockingSocket::Receive function is receiving one character at a time. The Telnet window is shown here.

 

WinInet, Winsock, MFC andC++ - Figure 100: MYEX33A – the web server activities.

 

Figure 101: Using Telnet to grab a web page.

 

The first time you run Telnet, choose Preferences from the Terminal menu and turn on Local Echo. Each time thereafter, choose Remote System from the Connect menu and then type your server name and port number 80. You can type a GET request (followed by a double carriage return), but you'd better type fast because the MYEX33A server's Receive() calls are set to time-out after 10 seconds.

 

Building a Web Client CHttpBlockingSocket

 

If you had written your own Internet browser program a few years ago, you could have made a billion dollars by now. But these days, you can download browsers for free, so it doesn't make sense to write one. It does make sense, however, to add Internet access features to your Windows applications. Winsock is not the best tool if you need HTTP or FTP access only, but it is a good learning tool.

 

The MYEX33A Winsock Client

 

The MYEX33A program implements a Winsock client in the ClientSockThread.cpp file. The code is similar to the code for the simplified HTTP client. The client thread uses global variables set by the Configuration property sheet, including server filename, server host name, server IP address and port, and client IP address. The client IP address is necessary only if your computer supports multiple IP addresses. When you run the client, it connects to the specified server and issues a GET request for the file that you specified. The Winsock client logs error messages in the MYEX33A main window.

 

MYEX33A Support for Proxy Servers

 

If your computer is connected to a LAN at work, chances are it's not exposed directly to the Internet but rather connected through a proxy server, sometimes called a firewall (or proxy with firewall). There are two kinds of proxy servers: Web and Winsock. Web proxy servers, sometimes called CERN proxies, support only the HTTP, FTP, and gopher protocols. (The gopher protocol, which predates HTTP, allows character-mode terminals to access Internet files.) A Winsock client program must be specially adapted to use a Web proxy server. A Winsock proxy server is more flexible and thus can support protocols such as RealAudio. Instead of modifying your client program source code, you link to a special Remote Winsock DLL that can communicate with a Winsock proxy server.

The MYEX33A client code can communicate through a Web proxy if you check the Use Proxy check box in the Client Configuration page. In that case, you must know and enter the name of your proxy server. From that point on, the client code connects to the proxy server instead of to the real server. All GET and POST requests must then specify the full Uniform Resource Locator (URL) for the file. If you were connected directly to SlowSoft's server, for example, your GET request might look like this:

 

GET /customers/newproducts.html HTTP/1.0

 

But if you were connected through a Web proxy server, the GET would look like this:

 

GET http://slowsoft.com/customers/newproducts.html HTTP/1.0

 

Testing the MYEX33A Winsock Client

 

The easiest way to test the Winsock client is by using the built-in Winsock server. Just start the server as before, and then choose Request (Winsock) from the Internet menu. You should see some HTML code in a message box. You can also test the client against IIS, the server running in another MYEX33A process on the same computer, the MYEX33A server running on another computer on the Net, and an Internet server. Ignore the "Address" URL on the dialog bar for the time being; it's for one of the WinInet clients. You must enter the server name and filename in the Client page of the Configuration dialog.

 

WinInet

 

WinInet is a higher-level API than Winsock, but it works only for HTTP, FTP, and gopher client programs in both asynchronous and synchronous modes. You can't use it to build servers. The WININET DLL is independent of the WINSOCK32 DLL. Microsoft Internet Explorer 3.0 (IE3) uses WinInet and so do ActiveX controls.

 

WinInet's Advantages over Winsock

 

WinInet far surpasses Winsock in the support it gives to a professional-level client program. Following are just some of the WinInet benefits:

  1. Caching: Just like IE3, your WinInet client program caches HTML files and other Internet files. You don't have to do a thing. The second time your client requests a particular file, it's loaded from a local disk instead of from the Internet.

  2. Security: WinInet supports basic authentication, Windows NT challenge/response authentication, and the Secure Sockets Layer (SSL). Authentication is described in Module 33.

  3. Web proxy access: You enter proxy server information through the Control Panel (click on the Internet icon), and it's stored in the Registry. WinInet reads the Registry and uses the proxy server when required.

  4. Buffered I/O: WinInet's read function doesn't return until it can deliver the number of bytes you asked for. (It returns immediately, of course, if the server closes the socket.) Also, you can read individual text lines if you need to.

  5. Easy API: Status callback functions are available for UI update and cancellation. One function, CInternetSession::OpenURL, finds the server's IP address, opens a connection, and makes the file ready for reading, all in one call. Some functions even copy Internet files directly to and from disk.

  6. User friendly: WinInet parses and formats headers for you. If a server has moved a file to a new location, it sends back the new URL in an HTTP Location header. WinInet seamlessly accesses the new server for you. In addition, WinInet puts a file's modified date in the request header for you.

 

The MFC WinInet Classes

 

WinInet is a modern API available only for Win32. The MFC wrapping is quite good, which means we didn't have to write our own WinInet class library. Yes, MFC WinInet supports blocking calls in multithreaded programs, and by now you know that makes us happy. The MFC classes closely mirror the underlying WinInet architecture, and they add exception processing. These classes are summarized in the sections on the following pages.

 

CInternetSession

 

You need only one CInternetSession object for each thread that accesses the Internet. After you have your CInternetSession object, you can establish HTTP, FTP, or gopher connections or you can open remote files directly by calling the OpenURL() member function. You can use the CInternetSession class directly, or you can derive a class from it in order to support status callback functions.

The CInternetSession constructor calls the WinInet InternetOpen() function, which returns an HINTERNET session handle that is stored inside the CInternetSession object. This function initializes your application's use of the WinInet library, and the session handle is used internally as a parameter for other WinInet calls.

 

CHttpConnection

 

An object of class CHttpConnection represents a "permanent" HTTP connection to a particular host. You know already that HTTP doesn't support permanent connections and that FTP doesn't either. (The connections last only for the duration of a file transfer.) WinInet gives the appearance of a permanent connection because it remembers the host name. After you have your CInternetSession object, you call the GetHttpConnection() member function, which returns a pointer to a CHttpConnection object. (Don't forget to delete this object when you are finished with it.). The GetHttpConnection() member function calls the WinInet InternetConnect() function, which returns an HINTERNET connection handle that is stored inside the CHttpConnection object and used for subsequent WinInet calls.

 

CFtpConnection, CGopherConnection

 

These classes are similar to CHttpConnection, but they use the FTP and gopher protocols. The CFtpConnection member functions GetFile() and PutFile() allow you to transfer files directly to and from your disk.

 

CInternetFile

 

With HTTP, FTP, or gopher, your client program reads and writes byte streams. The MFC WinInet classes make these byte streams look like ordinary files. If you look at the class hierarchy, you'll see that CInternetFile is derived from CStdioFile, which is derived from CFile. Therefore, CInternetFile and its derived classes override familiar CFile functions such as Read() and Write(). For FTP files, you use CInternetFile objects directly, but for HTTP and gopher files, you use objects of the derived classes CHttpFile and CGopherFile. You don't construct a CInternetFile object directly, but you call CFtpConnection::OpenFile to get a CInternetFile pointer.

If you have an ordinary CFile object, it has a 32-bit HANDLE data member that represents the underlying disk file. A CInternetFile object uses the same m_hFile data member, but that data member holds a 32-bit Internet file handle of type HINTERNET, which is not interchangeable with a HANDLE. The CInternetFile overridden member functions use this handle to call WinInet functions such as InternetReadFile() and InternetWriteFile().

 

CHttpFile

 

This Internet file class has member functions that are unique to HTTP files, such as AddRequestHeaders(), SendRequest(), and GetFileURL(). You don't construct a CHttpFile object directly, but you call the CHttpConnection::OpenRequest function, which calls the WinInet function HttpOpenRequest() and returns a CHttpFile pointer. You can specify a GET or POST request for this call. Once you have your CHttpFile pointer, you call the CHttpFile::SendRequest member function, which actually sends the request to the server. Then you call Read().

 

CFtpFileFind, CGopherFileFind

 

These classes let your client program explore FTP and Gopher directories.

 

CInternetException

 

The MFC WinInet classes throw CInternetException objects that your program can process with try-catch logic.

 

Internet Session Status Callbacks

 

WinInet and MFC provide callback notifications as a WinInet operation progresses, and these status callbacks are available in both synchronous (blocking) and asynchronous modes. In synchronous mode (which we're using exclusively here), your WinInet calls block even though you have status callbacks enabled. Callbacks are easy in C++. You simply derive a class and override selected virtual functions. The base class for WinInet is CInternetSession. Now let's derive a class named CCallbackInternetSession:

class CCallbackInternetSession : public CInternetSession

{

public:

    CCallbackInternetSession( LPCTSTR pstrAgent = NULL, DWORD dwContext = 1,

        DWORD dwAccessType = PRE_CONFIG_INTERNET_ACCESS,

        LPCTSTR pstrProxyName = NULL, LPCTSTR pstrProxyBypass = NULL,

        DWORD dwFlags = 0 ) { EnableStatusCallback() }

protected:

    virtual void OnStatusCallback(DWORD dwContext, DWORD dwInternalStatus,

        LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);

};

The only coding that's necessary is a constructor and a single overridden function, OnStatusCallback(). The constructor calls CInternetSession::EnableStatusCallback to enable the status callback feature. Your WinInet client program makes its various Internet blocking calls, and when the status changes, OnStatusCallback() is called. Your overridden function quickly updates the UI and returns, and then the Internet operation continues. For HTTP, most of the callbacks originate in the CHttpFile::SendRequest function. What kind of events trigger callbacks? A list of the codes passed in the dwInternalStatus parameter is shown here.

 

Code Passed

Action Taken

INTERNET_STATUS_RESOLVING_NAME

Looking up the IP address of the supplied name. The name is now in lpvStatusInformation.

INTERNET_STATUS_NAME_RESOLVED

Successfully found the IP address. The IP address is now in lpvStatusInformation.

INTERNET_STATUS_CONNECTING_TO_SERVER

Connecting to the socket.

INTERNET_STATUS_CONNECTED_TO_SERVER

Successfully connected to the socket.

INTERNET_STATUS_SENDING_REQUEST

Send the information request to the server.

INTERNET_STATUS_REQUEST_SENT

Successfully sent the information request to the server.

INTERNET_STATUS_RECEIVING_RESPONSE

Waiting for the server to respond to a request.

INTERNET_STATUS_RESPONSE_RECEIVED

Successfully received a response from the server.

INTERNET_STATUS_CLOSING_CONNECTION

Closing the connection to the server.

INTERNET_STATUS_CONNECTION_CLOSED

Successfully closed the connection to the server.

INTERNET_STATUS_HANDLE_CREATED

Program can now close the handle.

INTERNET_STATUS_HANDLE_CLOSING

Successfully terminated this handle value.

INTERNET_STATUS_REQUEST_COMPLETE

Successfully completed the asynchronous operation.

 

Table 30.

 

You can use your status callback function to interrupt a WinInet operation. You could, for example, test for an event set by the main thread when the user cancels the operation.

 

A Simplified WinInet Client Program

 

And now for the WinInet equivalent of our Winsock client program that implements a blind GET request. Because you're using WinInet in blocking mode, you must put the code in a worker thread. That thread is started from a command handler in the main thread:

 

AfxBeginThread(ClientWinInetThreadProc, GetSafeHwnd());

 

Here's the client thread code:

CString g_strServerName = "localhost"; // or some other host name

UINT ClientWinInetThreadProc(LPVOID pParam)

{

    CInternetSession session;

    CHttpConnection* pConnection = NULL;

    CHttpFile* pFile1 = NULL;

    char* buffer = new char[MAXBUF];

    UINT nBytesRead = 0;

    try

    {

        pConnection = session.GetHttpConnection(g_strServerName, 80);

        pFile1 = pConnection->OpenRequest(1, "/"); // blind GET

        pFile1->SendRequest();

        nBytesRead = pFile1->Read(buffer, MAXBUF - 1);

        buffer[nBytesRead] = '\0'; // necessary for message box

        char temp[10];

        if(pFile1->Read(temp, 10) != 0) {

            // makes caching work if read complete

            AfxMessageBox("File overran buffer — not cached");

     }

        AfxMessageBox(buffer);

    }

    catch(CInternetException* e)

    {

        // Log the exception

        e->Delete();

    }

    if(pFile1) delete pFile1;

    if(pConnection) delete pConnection;

    delete [ ] buffer;

    return 0;

}

 

The second Read() call needs some explanation. It has two purposes. If the first Read() doesn't read the whole file, that means that it was longer than MAXBUF -1. The second Read() will get some bytes, and that lets you detect the overflow problem. If the first Read() reads the whole file, you still need the second Read() to force WinInet to cache the file on your hard disk. Remember that WinInet tries to read all the bytes you ask it to, through the end of the file. Even so, you need to read 0 bytes after that.

 

Building a Web Client with the MFC WinInet Classes

 

There are two ways to build a Web client with WinInet. The first method, using the CHttpConnection class, is similar to the simplified WinInet client on the preceding page. The second method, using CInternetSession::OpenURL, is even easier. We'll start with the CHttpConnection version.

 

The MYEX33A WinInet Client #1: Using CHttpConnection

 

The MYEX33A program implements a WinInet client in the file ClientInetThread.cpp. Besides allowing the use of an IP address as well as a host name, the program uses a status callback function. That function, CCallbackInternetSession::OnStatusCallback in the file Utility.cpp, puts a text string in a global variable g_pchStatus, using a critical section for synchronization. The function then posts a user-defined message to the application's main window. The message triggers an Update Command UI handler (called by CWinApp::OnIdle), which displays the text in the second status bar text pane.

 

Testing the WinInet Client #1

 

To test the WinInet client #1, you can follow the same procedure you used to test the Winsock client. Note the status bar messages as the connection is made (failed in the example!). Note that the file appears more quickly the second time you request it.

 

The MYEX33A WinInet Client #2: Using OpenURL()

 

The MYEX33A program implements a different WinInet client in the file ClientUrlThread.cpp. This client uses the "Address" URL (that you type to access the Internet site). Here's the actual code:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CString g_strURL = "http:// ";

 

UINT ClientUrlThreadProc(LPVOID pParam)

{

    char* buffer = new char[MAXBUF];

    UINT nBytesRead = 0;

 

    CInternetSession session; // can't get status callbacks for OpenURL

    CStdioFile* pFile1 = NULL; // could call ReadString to get 1 line

    try {

        pFile1 = session.OpenURL(g_strURL, 0, INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_KEEP_CONNECTION);

         // If OpenURL fails, we won't get past here

        nBytesRead = pFile1->Read(buffer, MAXBUF - 1);

        buffer[nBytesRead] = '\0'; // necessary for message box

        char temp[100];

        if(pFile1->Read(temp, 100) != 0)

        {

            // makes caching work if read complete

            AfxMessageBox("File overran buffer — not cached");

        }

        ::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "URL CLIENT", MB_OK);

    }

    catch(CInternetException* e)

    {

        LogInternetException(pParam, e);

        e->Delete();

    }

    if(pFile1) delete pFile1;

    delete [] buffer;

    return 0;

}

Note that OpenURL() returns a pointer to a CStdioFile object. You can use that pointer to call Read() as shown, or you can call ReadString() to get a single line. The file class does all the buffering. As in the previous WinInet client, it's necessary to call Read() a second time to cache the file. The OpenURL() INTERNET_FLAG_KEEP_CONNECTION parameter is necessary for Windows NT challenge/response authentication, which is described in Module 33. If you added the flag INTERNET_FLAG_RELOAD, the program would bypass the cache just as the browser does when you click the Refresh() button.

 

Testing the WinInet Client #2

 

You can test the WinInet client #2 against any HTTP server. You run this client by typing in the URL address, not by using the menu. You must include the protocol (http:// or ftp://) in the URL address. Type http://localhost. You should see the same HTML code in a message box. No status messages appear here because the status callback doesn't work with OpenURL().

 

Asynchronous Moniker Files

 

Just when you thought you knew all the ways to download a file from the Internet, you're going to learn about another one. With asynchronous moniker files, you'll be doing all your programming in your application's main thread without blocking the user interface. Sounds like magic, doesn't it? The magic is inside the Windows URLMON DLL, which depends on WinInet and is used by Microsoft Internet Explorer. The MFC CAsyncMonikerFile class makes the programming easy, but you should know a little theory first.

 

Monikers

 

A moniker is a "surrogate" COM object that holds the name (URL) of the "real" object, which could be an embedded component but more often is just an Internet file (HTML, JPEG, GIF, PNG and so on). Monikers implement the IMoniker interface, which has two important member functions: BindToObject() and BindToStorage(). The BindToObject() function puts an object into the running state, and the BindToStorage() function provides an IStream or an IStorage pointer from which the object's data can be read. A moniker has an associated IBindStatusCallback interface with member functions such as OnStartBinding() and OnDataAvailable(), which are called during the process of reading data from a URL. The callback functions are called in the thread that created the moniker. This means that the URLMON DLL must set up an invisible window in the calling thread and send the calling thread messages from another thread, which uses WinInet functions to read the URL. The window's message handlers call the callback functions.

 

The MFC CAsyncMonikerFile Class

 

Fortunately, MFC can shield you from the COM interfaces described above. The CAsyncMonikerFile class is derived from CFile, so it acts like a regular file. Instead of opening a disk file, the class's Open() member function gets an IMoniker pointer and encapsulates the IStream interface returned from a call to BindToStorage(). Furthermore, the class has virtual functions that are tied to the member functions of IBindStatusCallback. Using this class is a breeze; you construct an object or a derived class and call the Open() member function, which returns immediately. Then you wait for calls to overridden virtual functions such as OnProgress() and OnDataAvailable(), named, not coincidentally, after their IBindStatusCallback equivalents.

 

Using the CAsyncMonikerFile Class in a Program

 

Suppose your application downloads data from a dozen URLs but has only one class derived from CAsyncMonikerFile. The overridden callback functions must figure out where to put the data. That means you must associate each derived class object with some UI element in your program. The steps listed below illustrate one of many ways to do this. Suppose you want to list the text of an HTML file in an edit control that's part of a form view. This is what you can do:

 

  1. Use ClassWizard to derive a class from CAsyncMonikerFile.

  2. Add a character pointer data member m_buffer. Invoke new for this pointer in the constructor; invoke delete in the destructor.

  3. Add a public data member m_edit of class CEdit.

  4. Override the OnDataAvailable() function thus:

void CMyMonikerFile::OnDataAvailable(DWORD dwSize, DWORD bscfFlag)

{

    try {

        UINT nBytesRead = Read(m_buffer, MAXBUF - 1);

        TRACE("nBytesRead = %d\n", nBytesRead);

        m_buffer[nBytesRead] = '\0'; // necessary for edit control

        // The following two lines add text to the edit control

        m_edit.SendMessage(EM_SETSEL, (WPARAM) 999999, 1000000);

        m_edit.SendMessage(EM_REPLACESEL, (WPARAM) 0, (LPARAM) m_buffer);

    }

    catch(CFileException* pe) {

        TRACE("File exception %d\n, pe->m_cause");

        pe->Delete();

    }

}
  1. Embed an object of your new moniker file class in your view class.

  2. In you view's OnInitialUpdate() function, attach the CEdit member to the edit control like this:

 

m_myEmbeddedMonikerFile.m_edit.SubClassDlgItem(ID_MYEDIT, this);

 

  1. In your view class, open the moniker file like this:

 

m_myEmbeddedMonikerFile.Open("http://host/filename");

 

For a large file, OnDataAvailable() will be called several times, each time adding text to the edit control. If you override OnProgress() or OnStopBinding() in your derived moniker file class, your program can be alerted when the transfer is finished. You can also check the value of bscfFlag in OnDataAvailable() to determine whether the transfer is completed. Note that everything here is in your main thread and - most important - the moniker file object must exist for as long as the transfer is in progress. That's why it's a data member of the view class.

 

Asynchronous Moniker Files vs. WinInet Programming

 

In the WinInet examples earlier in this module, you started a worker thread that made blocking calls and sent a message to the main thread when it was finished. With asynchronous moniker files, the same thing happens, the transfer takes place in another thread, which sends messages to the main thread. You just don't see the other thread. There is one very important difference, however, between asynchronous moniker files and WinInet programming: with blocking WinInet calls, you need a separate thread for each transfer; with asynchronous moniker files, only one extra thread handles all transfers together. For example, if you're writing a browser that must download 50 bitmaps simultaneously, using asynchronous moniker files saves 49 threads, which makes the program much more efficient. Of course, you have some extra control with WinInet, and it's easier to get information from the response headers, such as total file length. Your choice of programming tools, then, depends on your application. The more you know about your options, the better your choice will be.

 

 

----End for Winsock, WinInet, IIS and MFC----

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. DCOM at MSDN.

  2. COM+ at MSDN.

  3. COM at MSDN.

  4. Win32 process, thread and synchronization story can be found starting from Module R.

  5. MSDN MFC 7.0 class library online documentation.

  6. MSDN MFC 9.0 class library online documentation - latest version.

  7. MSDN Library

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | C++, MFC, Winsock & WinInet 7 | IIS Programming 1 | Download | Site Index |