Microsoft KB Archive/267240

From BetaArchive Wiki
Knowledge Base


How to print custom headers and footers for a WebBrowser control in Internet Explorer

Article ID: 267240

Article Last Modified on 5/11/2006



APPLIES TO

  • Microsoft Internet Explorer 4.0 128-Bit Edition
  • Microsoft Internet Explorer 4.01 Service Pack 2
  • Microsoft Internet Explorer 5.0
  • Microsoft Internet Explorer 5.01
  • Microsoft Internet Explorer 5.5
  • Microsoft Internet Explorer (Programming) 6.0



This article was previously published under Q267240

INTRODUCTION

When you host the WebBrowser control, you may often need to override the default headers and footers for a printed HTML document. Although Microsoft Internet Explorer 5.5 supports the configuration of printer templates, which allow you to customize headers and footers, Internet Explorer version 4.0 and later versions support the use of the IWebBrowser2::ExecWB method to customize headers and footers.

MORE INFORMATION

IWebBrowser2::ExecWB is a wrapper for the Exec method of the IOleCommandTarget interface. The ExecWB method has the following signature:

HRESULT ExecWB(
    OLECMDID cmdID,
    OLECMDEXECOPT cmdexecopt,
    VARIANT *pvaIn,
    VARIANT *pvaOut
);
                

When you use an OLECMDID enumeration of the OLECMDID_PRINT element together with the ExecWB method, you can specify extended printing information by passing in the SAFEARRAY structure through the VARIANT argument pvaIn. This SAFEARRAY data type takes a maximum of five items:

  1. A string (BSTR) that contains a custom header.
  2. A string (BSTR) that contains a custom footer.
  3. An IStream object that contains an HTML file that serves as an "optional header." This is the e-mail header that you see in Microsoft Outlook and Microsoft Outlook Express e-mail messages when you print them. This IStream object must point to a full, valid HTML document, not to HTML fragments, or it will print incorrectly.
  4. An alternative URL to use for the document. This is only relevant to Outlook and to Outlook Express.
  5. A set of printing flags (dwFlags) to configure the printer. This is only relevant to Outlook and to Outlook Express.

The following Microsoft Visual C++ code shows an event handler for a Print menu command in a Visual C++ WebBrowser host. The code focuses on very simple header, footer, and optional header values.

LRESULT CWebOCWindow::OnPrint(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
    SAFEARRAYBOUND psabBounds[1];
    SAFEARRAY *psaHeadFoot;
    HRESULT hr = S_OK;

    // Variables needed to send IStream header to print operation.
    HGLOBAL hG = 0;
    IStream *pStream= NULL;
    IUnknown *pUnk = NULL;
    ULONG lWrote = 0;
    LPSTR sMem = NULL;
    
    if (!webOC) {
        ATLTRACE(_T("DoPrint: Cannot print - WebBrowser control not ready\n"));
        goto cleanup;
    }
    
    // Initialize header and footer parameters to send to ExecWB().
    psabBounds[0].lLbound = 0;
    psabBounds[0].cElements = 3;
    psaHeadFoot = SafeArrayCreate(VT_VARIANT, 1, psabBounds);
    if (NULL == psaHeadFoot) {
        // Error handling goes here.
        goto cleanup;
    }
    VARIANT vHeadStr, vFootStr, vHeadTxtStream;
    long rgIndices;
    VariantInit(&vHeadStr);
    VariantInit(&vFootStr);
    VariantInit(&vHeadTxtStream);

    // Argument 1: Header
    vHeadStr.vt = VT_BSTR;
    vHeadStr.bstrVal = SysAllocString(L"This is my header string.");
    if (vHeadStr.bstrVal == NULL) {
        goto cleanup;
    }
    
    // Argument 2: Footer
    vFootStr.vt = VT_BSTR;
    vFootStr.bstrVal = SysAllocString(L"This is my footer string.");
    if (vFootStr.bstrVal == NULL) {
        ATLTRACE(_T("DoPrint: Could not allocate memory in %s: Line %d\n"), __FILE__, __LINE__);
        goto cleanup;
    }

    // Argument 3: IStream containing header text. Outlook and Outlook 
         // Express use this to print out the mail header.  
    if ((sMem = (LPSTR)CoTaskMemAlloc(512)) == NULL) {
        ATLTRACE(_T("DoPrint: Could not allocate memory in %s: Line %d\n"), __FILE__, __LINE__);
        goto cleanup;
    }
    // We must pass in a full HTML file here, otherwise this 
         // becomes corrupted when we print.
    sprintf(sMem, "<html><body><strong>Printed By:</strong> Custom WebBrowser Host 1.0<p></body></html>\0");

    // Allocate an IStream for the LPSTR that we just created.
    hG = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, strlen(sMem));
    if (hG == NULL) {
        ATLTRACE(_T("DoPrint: Could not allocate memory in %s: Line %d\n"), __FILE__, __LINE__);
        goto cleanup;
    }
    hr = CreateStreamOnHGlobal(hG, TRUE, &pStream);
    if (FAILED(hr)) {
        ATLTRACE(_T("OnPrint::Failed to create stream from HGlobal: %lX\n"), hr);
        goto cleanup;
    }
    hr = pStream->Write(sMem, strlen(sMem), &lWrote);
    if (SUCCEEDED(hr)) {
        // Set the stream back to its starting position.
        LARGE_INTEGER pos;
        pos.QuadPart = 0;
        pStream->Seek((LARGE_INTEGER)pos, STREAM_SEEK_SET, NULL);
        hr = pStream->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnk));
        vHeadTxtStream.vt = VT_UNKNOWN;
        vHeadTxtStream.punkVal = pUnk;
    }

    rgIndices = 0;
    SafeArrayPutElement(psaHeadFoot, &rgIndices, static_cast<void *>(&vHeadStr));
    rgIndices = 1;
    SafeArrayPutElement(psaHeadFoot, &rgIndices, static_cast<void *>(&vFootStr));
    rgIndices = 2;
    SafeArrayPutElement(psaHeadFoot, &rgIndices, static_cast<void *>(&vHeadTxtStream));
        
    //NOTE: Currently, the SAFEARRAY variant must be passed by using
            // the VT_BYREF vartype when you call the ExecWeb method.
    VARIANT vArg;
    VariantInit(&vArg);
    vArg.vt = VT_ARRAY | VT_BYREF;
    vArg.parray = psaHeadFoot;
    hr = webOC->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, &vArg, NULL);
    if (FAILED(hr)) {
        ATLTRACE(_T("DoPrint: Call to WebBrowser's ExecWB failed: %lX\n"), hr);
    goto cleanup;
    }
    return 1; 
    //WebBrowser control will clean up the SAFEARRAY after printing.
    cleanup:
    VariantClear(&vHeadStr);
    VariantClear(&vFootStr);
    VariantClear(&vHeadTxtStream);
    if (psaHeadFoot) {
        SafeArrayDestroy(psaHeadFoot);
    }
    if (sMem) {
        CoTaskMemFree(sMem);    
    }
    if (hG != NULL) {
        GlobalFree(hG);
    }
    if (pStream != NULL) {
        pStream->Release();
        pStream = NULL;
    }
    bHandled = TRUE;
    return 0;
}

REFERENCES

For more information about developing Web-based solutions for Microsoft Internet Explorer, visit the following Microsoft Web sites:

Keywords: kbfaq kbhowto kbprint kbwebbrowser KB267240