Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

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

View products that this article applies to.

This article was previously published under Q267240

↑ Back to the top


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.

↑ Back to the top

More information

IWebBrowser2::ExecWB is a wrapper for the Exec method of the IOleCommandTarget interface. The ExecWB method has the following signature:
    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;

	// Variables needed to send IStream header to print operation.
	HGLOBAL hG = 0;
	IStream *pStream= NULL;
	IUnknown *pUnk = NULL;
	ULONG lWrote = 0;
	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;

	// 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.
		pos.QuadPart = 0;
		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.
	vArg.vt = VT_ARRAY | VT_BYREF;
	vArg.parray = psaHeadFoot;
	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.
	if (psaHeadFoot) {
	if (sMem) {
	if (hG != NULL) {
	if (pStream != NULL) {
		pStream = NULL;
	bHandled = TRUE;
	return 0;

↑ Back to the top


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

↑ Back to the top

Keywords: KB267240, kbwebbrowser, kbprint, kbhowto, kbfaq

↑ Back to the top

Article Info
Article ID : 267240
Revision : 4
Created on : 5/11/2006
Published on : 5/11/2006
Exists online : False
Views : 638