"...pass in a URL, get a stream..."
Disclaimer THIS DOCUMENT IS AN EARLY RELEASE OF THE FINAL SPECIFICATION. IT IS MEANT TO SPECIFY AND ACCOMPANY SOFTWARE THAT IS STILL IN DEVELOPMENT. SOME OF THE INFORMATION IN THIS DOCUMENTATION MAY BE INACCURATE OR MAY NOT BE AN ACCURATE REPRESENTATION OF THE FUNCTIONALITY OF THE FINAL SPECIFICATION OR SOFTWARE. MICROSOFT ASSUMES NO RESPONSIBILITY FOR ANY DAMAGES THAT MIGHT OCCUR EITHER DIRECTLY OR INDIRECTLY FROM THESE INACCURACIES. MICROSOFT MAY HAVE TRADEMARKS, COPYRIGHTS, PATENTS OR PENDING PATENT APPLICATIONS, OR OTHER INTELLECTUAL PROPERTY RIGHTS COVERING SUBJECT MATTER IN THIS DOCUMENT. THE FURNISHING OF THIS DOCUMENT DOES NOT GIVE YOU A LICENSE TO THESE TRADEMARKS, COPYRIGHTS, PATENTS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
Without a doubt the easiest, most efficient and most powerful way to download data from the Internet is using the new URL Open Stream (UOS) functions. Before jumping into the specifications, let's cover a few of the high-level features and the philosophy behind the creation of these functions. The UOS functions are the newest addition to the ActiveX™ extensions to the Win32 API. They combine the familiarity of C-style programming with the power of COM. These functions work equally well inside an ActiveX framework (for example, a component, a document or frame window, a subcomponent, or a scriptable object) or completely standalone.
Unlike other more complex interface negotiations, using these functions requires knowledge of no more than two COM interfaces, IStream and IBindStatusCallback.
Because these functions use services from URL monikers and WinInet, all the caching and thread synchronization features of those components are in use whenever you call these functions. In addition, the UOS functions handle all the host binding operations if your code is in an ActiveX container: the UOS functions automatically do the right thing to manage the download in the ActiveX client framework.
Every UOS function works in the same basic way: the caller implements an IBindStatusCallback interface (optional in some cases), then calls the function. The URLOpenStream and URLOpenPullStream functions require the caller to be on a thread that has a message loop (GetMessage/DispatchMessage). In the case of an ActiveX component, a message loop is a given if this function is called from the main thread. For a standalone application without a user interface, a message loop is still necessary for these functions.
With the URL Open Stream functions, you can:
- Download a URL to a file with a single function call. You can optionally get progress notifications in the background.
- Create a blocking-type stream with a single function that will block when you call IStream::Read. You can optionally get progress notifications in the background.
- Post an Internet query (using the HTTP POST verb) with a single call and get the results in a stream.
- Optionally hook into the ActiveX client framework simply by passing your this pointer.
- Configure callbacks using either the push or pull model.
Callbacks are issued on an IBindStatusCallback interface that is implemented on the caller. This is a simple callback interface to implement, because most of the methods on the interface are optional (for example, OnStartBinding, GetPriority, OnStopBinding) and can simply return S_OK or E_NOTIMPL. Although clients may choose to implement many of the IBindStatusCallback methods, the only callback required to do anything for the UOS functions to work correctly is OnDataAvailable for the URLOpenStream and URLOpenPullStream functions. In fact, for some UOS functions (URLDownloadToFile and URLDownloadToCacheFile. URLOpenBlockingStream), OnDataAvailable is never called because it is unnecessary. Furthermore, GetBindInfo is neverinvoked for UOS clients, because the bind information is determined according to which UOS function is being called. The UOS programming model is straightforward because there are no special flags to pass to the functions.
The URL Open Stream functions are described below:
LPUNKNOWN pCaller,
LPCWSTR szURL,
DWORD dwResv,
LPBINDSTATUSCALLBACK lpfnCB);
URLDownloadToCacheFile downloads data into the Internet cache and returns the filename of the cache location for retrieving the bits. The client can optionally be notified of progress via a notification callback.
This function will always return a filename if the download operation succeeds. If the given URL is a "file:" URL, URLDownloadToCacheFile will directly return the
filename for the "file:" URL rather than making a copy to the
cache. If the given URL is an Internet URL ("http:", "ftp:"), URLDownloadToCacheFile will download this file and return the local filename of the cached copy. Using this function ensures that a filename is returned without unnecessary copying of data.
- LPUNKNOWNpCaller
- Pointer to the controlling IUnknown of the calling ActiveX component (if the caller is an ActiveX component). If the caller is not an ActiveX component, this value may be set to NULL. Otherwise, the caller is a COM object that is contained in another component (such as an ActiveX Control in the context of an HTML page). The parameter represents the outermost IUnknown of the calling component. The function will attempt the download in the context of the ActiveX client framework and allow the caller's container to receive callbacks on the progress of the download.
- LPCWSTRszURL
- The URL to be downloaded. Cannot be NULL.
- DWORDdwBufLen
- Reserved for future use; must be zero.
- DWORDdwResv
- Reserved for future use; must be zero.
- LPBINDSTATUSCALLBACKlpfnCB
- Pointer to caller's IBindStatusCallback interface pointer on the caller.
URLDownloadToCacheFile calls this interface's OnProgress method on some connection activity, including the arrival of data. OnDataAvailable is never called. Implementing OnProgress allows a caller to implement some user interface or other progress monitoring functionality. It also allows the download operation to be completely canceled by returning E_ABORT from the OnProgress call. Can be NULL.
LPUNKNOWN pCaller,
LPCWSTR szURL,
LPCTSTR szFileName,
DWORD dwResv,
URLDownloadToFile downloads bits from the Internet and saves them to a file. The client can optionally be notified of progress via a notification callback.
- LPUNKNOWNpCaller
- Pointer to the controlling IUnknown of the calling
ActiveX component (if the caller is an ActiveX component).
If the caller is not an ActiveX component, this value may
be set to NULL. Otherwise, the caller is a COM object that
is contained in another component (such as an ActiveX Control
in the context of an HTML page). The parameter
represents the outermost IUnknown of the calling component.
The function will attempt the download in the context of the
ActiveX client framework and allow the caller's container to
receive callbacks on the progress of the download.
- LPCWSTRszURL
- The URL to be downloaded. Cannot be NULL.
- LPCTSTRszFileName
- Name of the file to create with bits that come from the download.
- DWORDdwResv
- Reserved for future use; must be zero.
- LPBINDSTATUSCALLBACKlpfnCB
- Pointer to the IBindStatusCallback interface pointer on the caller. URLDownloadToFile calls this interface's OnProgress method on some connection activity, including the arrival of data. OnDataAvailable is never called. Implementing OnProgress allows a caller to implement some user interface or other progress monitoring functionality. It also allows the download operation to be completely canceled by returning E_ABORT from the OnProgress call. Can be NULL.
LPUNKNOWN pCaller,
LPCWSTR szURL,
DWORD dwResv,
LPBINDSTATUSCALLBACK lpfnCB);
URLOpenStream creates a push-type stream object from a URL. The data is downloaded from the Internet as fast as possible. Every time data is available, it is "pushed" at the client through a notification callback.
- LPUNKNOWNpCaller
- Pointer to the controlling IUnknown of the calling
ActiveX component (if the caller is an ActiveX component). If the caller is not an ActiveX component, this value may be set to NULL. Otherwise, the caller is a COM object that is contained in another component (such as an ActiveX Control in the context of an HTML page). The parameter represents the outermost IUnknown of the calling component. The function will attempt the download in the context of the
ActiveX client framework and allow the caller's container to receive callbacks on the progress of the download.
- LPCWSTRszURL
- The URL to be converted to a stream object. Cannot be NULL.
- DWORDdwResv
- Reserved for future use; must be zero.
- LPBINDSTATUSCALLBACKlpfnCB
- Pointer to caller's IBindStatusCallback interface, on which URLOpenStream calls OnDataAvailable every time data arrives from the Internet. OnDataAvailable can return E_ABORT to abort the download. When the callback is invoked and the pstm member of the STGMEDIUM structure is not NULL, the caller can read from the stream the amount of data specified in the dwSize argument passed with the OnDataAvailable call (delta anything that has been read on previous calls to OnDataAvailable). If the caller does not read the full amount or does not call pstm Read at all, OnDataAvailable will still be called the next time data arrives, as long the grfBSCF flags do not indicate BINDF_LASTDATANOTIFICATION. In that case, no more data will be downloaded. Any data that is not read at any given time will still be available the next time OnDataAvailable is called.
The logic in the following code fragment is a typical implementation of OnDataAvailable as it is used by the URLOpenStream function:
HRESULT MyBindStatusCallback::OnDataAvailable
(
DWORD grfBSCF, DWORD dwSize, ..., STGMEDIUM * pstgmed
)
{
if( dwSize < sizeof(BITMAPINFOHEADER) )
return(NOERROR); // not enough has been read yet, just return
if( !g_bGotInfoHeader ) // did we get info before?
{
// No, go ahead, read now...
DWORD dwRead;
HRESULT hr = pstgmed->pstm->Read( &bmih, sizeof(bmih), &dwRead);
if( SUCCEEDED(hr) )
{
// now we got it... we can return
g_bGotInfoHeader = TRUE;
return(hr);
}
}
}
LPUNKNOWN pCaller,
LPCWSTR szURL,
LPSTREAM *ppStream,
DWORD dwResv,
LPBINDSTATUSCALLBACK lpfnCB);
URLOpenBlockingStream creates a blocking-type stream object from a URL. The data is downloaded from the Internet on demand by a call to IStream::Read. The Read call will block until enough data has arrived.
- LPUNKNOWNpCaller
- Pointer to the controlling IUnknown of the calling
ActiveX component (if the caller is an ActiveX component). If the caller is not an ActiveX component, this value may be set to NULL. Otherwise, the caller is a COM object that is contained in another component (such as an ActiveX Control in the context of an HTML page). The parameter represents the outermost IUnknown of the calling component. The function will attempt the download in the context of the
ActiveX client framework and allow the caller's container to receive callbacks on the progress of the download.
- LPCWSTRszURL
- The URL to be converted to a stream object. Cannot be NULL.
- LPSTREAM *ppStream
- Pointer to the IStream interface pointer on the stream object created by this function. The caller can read from the stream as soon as it has this pointer. If the data requested has not yet been downloaded, the Read method will block until enough data has been downloaded. The following is a code fragment that logically does this:
- DWORDdwResv
- Reserved for future use; must be zero.
- LPBINDSTATUSCALLBACKlpfnCB
- Pointer to the IBindStatusCallback interface pointer on the caller. URLOpenBlockingStream calls this interface's OnProgress method on some connection activity, including the arrival of data. OnDataAvailable is never called. Implementing OnProgress allows a caller to implement some user interface or other progress monitoring functionality. It also allows the download operation to be completely canceled by returning E_ABORT from the OnProgress call. Can be NULL.
LPUNKNOWN pCaller,
LPCWSTR szURL,
DWORD dwResv,
LPBINDSTATUSCALLBACK lpfnCB);
URLOpenPullStream creates a pull-type stream object from a URL. The data is downloaded from the Internet on demand. If not enough data is available locally to satisfy the requests, the IStream::Read call will not block until enough data has arrived. Instead, Read will immediately return E_PENDING, and URLOpenPullStream will request the next packet of data from the Internet server.
- LPUNKNOWNpCaller
- Pointer to the controlling IUnknown of the calling
ActiveX component (if the caller is an ActiveX component). If the caller is not an ActiveX component, this value may be set to NULL. Otherwise, the caller is a COM object that is contained in another component (such as an ActiveX Control in the context of an HTML page). The parameter represents the outermost IUnknown of the calling component. The function will attempt the download in the context of the
ActiveX client framework and allow the caller's container to receive callbacks on the progress of the download.
- LPCWSTRszURL
- The URL to be converted to a stream object. Cannot be NULL.
- DWORDdwResv
- Reserved for future use; must be zero.
- LPBINDSTATUSCALLBACKlpfnCB
- Pointer to caller's IBindStatusCallback interface, on which URLOpenPullStream calls OnDataAvailable every time data arrives from the Internet. OnDataAvailable can return E_ABORT to abort the download. When the callback is invoked and the pstm member of the STGMEDIUM structure is not NULL, the caller can read from the stream the amount of data specified in the dwSize argument passed with the OnDataAvailable call (delta anything that has been read on previous calls to OnDataAvailable). If the caller does not read the full amount or does not call pstmRead at all, OnDataAvailable will not be called again until this happens and Read returns E_PENDING.
The pull model is slightly more cumbersome than the push model, but it gives total control to the client over the amount of Internet access for the download.
The logic in the following code fragment is a typical implementation of OnDataAvailable as it is used by the URLOpenStream function: