Figure 2   Simple Hyperlink Navigation APIs

Function

Description

HlinkSimpleNavigateToString

Executes a hyperlink jump to a new document or object represented as a string

HlinkSimpleNavigateToMoniker

Executes a hyperlink jump to a new document or object represented as a moniker

HlinkGoBack

Executes a hyperlink jump backwards within the navigation stack

HlinkGoForward

Executes a hyperlink jump forwards within the navigation stack

Figure 4   WM_CONTEXTMENU Message Handler

 void CScribView::OnContextMenu(CWnd* pWnd, CPoint point) 
{
    CRect rect;
    GetClientRect (&rect);
    ClientToScreen (&rect);

    if (rect.PtInRect (point))
    {
        CMenu menu;
        menu.LoadMenu (IDR_CONTEXTMENU);
        CMenu* pContextMenu = menu.GetSubMenu (0);

        // If the Scribble application is not hosted in a frame that
        // is capable of hosting ActiveX Document Objects, disable the
        // "Go Back" and "Go Forward" menu items.  The Simple
        // Hyperlink Navigation APIs related to Go Back and Go Forward
        // only work in-frame.
        CScribDoc* pScribDocument = GetDocument ();
        if (!pScribDocument -> IsDocObject())
        {
            pContextMenu -> EnableMenuItem(ID_GOBACK, MF_GRAYED);
            pContextMenu -> EnableMenuItem(ID_GOFORWARD, MF_GRAYED);
        }

        // Display the context menu.
        pContextMenu -> TrackPopupMenu (TPM_LEFTALIGN | TPM_LEFTBUTTON |
                                        TPM_RIGHTBUTTON, point.x, 
                                        point.y, this);
    }
}

Figure 5   Context Menu Item Message Handlers

 ////////////////////////////////////////////////////////////////////
//
//    OnGoBack: Context menu handler for "Go Back".  Calls the
//              Simple Hyperlink Navigation API HlinkGoBack to go
//              back in the Hyperlink history stack.
//
////////////////////////////////////////////////////////////////////
void CScribDoc::OnGoBack()
{
  IUnknown* pUnk = NULL;

  // Obtain the IUnknown pointer to the document.
  HRESULT hr = this -> ExternalQueryInterface ((void*)&IID_IUnknown,
                                               LPVOID *)&pUnk);

  if (hr == S_OK)
    // Go Back in the hyperlink history stack
    HlinkGoBack (pUnk);
}

///////////////////////////////////////////////////////////////////
//    OnGoForward:  Context menu handler for "Go Back".  Calls
//                  the Simple Hyperlink Navigation API HlinkGoForward
//                  to go forward in the Hyperlink history stack.
//
///////////////////////////////////////////////////////////////////
void CScribDoc::OnGoForward()
{
  IUnknown* pUnk = NULL;

  // Obtain the IUnknown pointer to the document.
  HRESULT hr = this -> ExternalQueryInterface ((void*)&IID_IUnknown,
                                               LPVOID *)&pUnk);

  if (hr == S_OK)
    // Go Forward in the hyperlink history stack
    hr = HlinkGoForward (pUnk);
}

///////////////////////////////////////////////////////////////////
//
//    OnMSHomePage:  Context menu handler for "Microsoft Home Page".
//                   Calls the Simple Hyperlink Hyperlink Navigation
//                   API HlinkSimpleNavigateToString to display the
//                   HTML page for Microsoft's Web site
//
///////////////////////////////////////////////////////////////////
void CScribDoc::OnMSHomePage()
{
  HRESULT hr;
  IUnknown* pUnk = NULL;

  if (this -> IsDocObject())
    // Obtain the IUnknown pointer to the document.
    hr = this -> ExternalQueryInterface ((void*)&IID_IUnknown,
                                         LPVOID *)&pUnk);

  HlinkSimpleNavigateToString(L"http://www.microsoft.com/default.htm",
                              NULL, NULL, pUnk, 0, NULL, NULL, 0);
}

Figure 8   URL Open Stream Functions

Function

Description

URLOpenStream

Creates a push-type stream object from a URL

URLOpenBlockingStream

Creates a blocking-type stream object from a URL

URLDownloadToFile

Downloads bits from the Internet and saves them to a file

URLOpenPullStream

Creates a pull-type stream object from a URL

URLOpenHttpStream

Advanced function for doing more sophisticated HTTP and FTP downloads, such as performing an HTTP POST

Figure 9   IBindStatusCallback Interface

 interface IBindStatusCallback: IUnknown
    {
    HRESULT GetBindInfo([out] DWORD* pgrfBINDF, 
                        [in, out] BINDINFO* pbindinfo);
    HRESULT OnStartBinding([in] DWORD dwReserved, [in] IBinding* pbinding);
    HRESULT GetPriority([out] LONG* pnPriority);
    HRESULT OnProgress([in] ULONG ulProgress, [in] ULONG ulProgressMax, 
                       [in] ULONG ulStatusCode, [in] LPCWSTR szStatusText);
    HRESULT OnDataAvailable([in] DWORD grfBSC, [in] DWORD dwSize, [in]
                            FORMATETC* pformatetc, [in] STGMEDIUM*   pstgmed);
    HRESULT OnObjectAvailable( [in] REFIID riid, [in] IUnknown *punk);
    HRESULT OnLowResource([in] DWORD dwReserved);
    HRESULT OnStopBinding([in] HRESULT hrStatus, [in] LPCWSTR szStatusText);
    };

Figure 10   IBindStatusCallback Implementation

Function

Implementation

URLOpenStream

Mandatory

URLOpenBlockingStream

Optional

URLDownloadToFile

Optional

URLOpenPullStream

Mandatory

URLOpenHttpStream

Optional

Figure 11   PushCBindStatusCallback::OnDataAvailable

 HRESULT CBindStatusCallback::OnDataAvailable 
(DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed)
{
.
.
.
    if (dwSize < sizeof(BITMAPINFOHEADER) )
        return (NOERROR);  // not enough has been read yet

    // if we did not get the header information, read it now
    if (!g_bGotInfoHeader)
    {
        if (pstgmed->pstm != NULL)
        {
            DWORD dwRead;
            HRESULT hr = pstgmed->pstm->Read (&bmih, sizeof(bmih), &dwRead);

            if (SUCCEEDED(hr))
            {
                g_bGotInfoHeader = TRUE;
                return(hr);
            }
        }
    }
.
.
.
}

Figure 12   PullCBindStatusCallback::OnDataAvailable

 HRESULT CBindStatusCallback::OnDataAvailable (DWORD grfBSCF, DWORD dwSize,
                                              FORMATETC* pfmtetc, 
                                              STGMEDIUM* pstgmed)
{
    HRESULT hr = NOERROR;
    DWORD dwAmountToRead = dwSize - m_readSoFar;
    BYTE *buffer = new BYTE [dwAmountToRead];

    while (TRUE)
    {
        DWORD dwRead;

        hr = pstgmed->pstrm->Read (buffer, dwAmountToRead, &dwRead);

        if (hr == E_PENDING)
        {
            // we'll get notified again when more data comes
            return (NOERROR);
        }

        if (SUCCEEDED(hr))
        {
            // ok, process bits .... and keep looping
        }
        else
        {
            // we have an error...
            return(hr);
        }
    }
}

Figure 13   Members of the UOS Structure

Member

Description

ULONG ulSize

Size of this structure.

LPUNKNOWN punkCaller

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

LPCTSTR szURL

URL to be downloaded.

LPCTSTR szVerb

GET, PUT, POST, or a custom verb understood by the server. If NULL, GET is assumed.

LPCTSTR szHeaders

HTTP headers to use during connection to server. Can be NULL.

LPBYTE szPostData

Additional data to send after the headers. Typically this will be a POST data arguments. Can be NULL.

ULONG ulPostDataLen

Size of szPostData. Must not be 0 if szPostData is not NULL.

ULONG fURLEncode

Flags with either the UOS_URLENCODPOSTDATA, UOS_URLENCODEURL, or can be NULL. The two flags can be combined by a bitwise OR.

ULONG ulMode

Can be one of UOSM_PUSH, UOSM_PULL, UOS_BLOCK, or UOS_FILE. Each of these maps to one of the functions above and makes this function's programming model fit the corresponding function.

LPCTSTR szFileName

Name of the local file to write URL data to if ulMode is UOS_FILE. Otherwise, must be NULL.

LPSTREAM *ppStream

Pointer to IStream pointer if ulMode is UOS_BLOCK. Otherwise, must be NULL.

LPBINDSTATUSCALLBACK lpbscb

Pointer to IBindStatusCallback interface. This interface and the caller's programming model responsibility depend on the ulMode flag above. The function will behave exactly like the corresponding UOS functions above, depending on the flag settings.

Figure 15   AVIDNLDR Retrieve Button Message Handler

 ///////////////////////////////////////////////////////////////////
// CAVIDownloaderDlg::OnBtnRetrieve - Message handler for the Retrieve
// command button.  Downloads the .AVI file from the Internet and runs // it in the Media Architects Video Play OCX Control.
//
///////////////////////////////////////////////////////////////////
void CAVIDownloaderDlg::OnBtnRetrieve() 
{
    // This application does not do any checking to insure that the
    // user has entered a valid URL.  This exercise is left to the
    // reader.

    // Create a IBindStatusCallback object 
    ptrURLDownloadToFileCallback pURLDownloadToFileCallback;

    if (!pURLDownloadToFileCallback)
    {
        AfxMessageBox (_T("Unable to create IBindStatusCallback object."));
        return;
    }

    // Disable the "Retrieve" button    
    m_btnRetrieve.EnableWindow(FALSE);
    BeginWaitCursor();

    // Create a temporary file to hold the the .AVI file.  This demo
    // does not manage files.
    LPTSTR lpTempFileName = new TCHAR[MAX_PATH];
    LPTSTR lpPathName= new TCHAR[MAX_PATH];

    // Retrieve the path of the directory designated for temporary
    // files.
    ::GetTempPath(MAX_PATH,lpPathName);

    // Create a name for a temporary file.
    if (0 != GetTempFileName (lpPathName, _T("AVI"), 0,
           lpTempFileName))
    {
        // Swap out the .TMP extension with .AVI
        CString szFileName = lpTempFileName;
        szFileName = szFileName.Left ((szFileName.GetLength() - 3)) +
              _T("AVI");

        // Call the UOS function to do the file download
        CString szURL;
        m_URLString.GetWindowText (szURL);
        HRESULT hr = URLDownloadToFile (NULL, szURL, szFileName, 0,
              pURLDownloadToFileCallback);

        if ((hr == S_OK) && (pURLDownloadToFileCallback -> got_File ()
               == TRUE))
        {
            // Setup the Media Architects Video Play OCX Control
            // and play the .AVI file that was downloaded.
            m_VideoPlay.SetFilename (szFileName);
            m_VideoPlay.SetLoop (TRUE);

           // Play the entire video
           VARIANT varEntireVideo;
           varEntireVideo.vt = VT_ERROR;
           m_VideoPlay.Play (varEntireVideo, varEntireVideo);
        }
    }

    delete [] lpTempFileName;
    delete [] lpPathName;

    pURLDownloadToFileCallback -> Release();

    m_btnRetrieve.EnableWindow(TRUE);
    EndWaitCursor();
}