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, 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();     } }

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

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

    m_myEmbeddedMonikerFile.m_edit.SubClassDlgItem(ID_MYEDIT, this);

  7. 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 chapter, 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.



Programming Microsoft Visual C++
Programming Microsoft Visual C++
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 332

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net