Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Print XML documents well formatted by a WebBrowser with any orientation: Portrait & Landscape

4.33/5 (2 votes)
24 Nov 2010CPOL3 min read 17.4K  
A sample project shows How to print XML documents by a WebBrowser control , with orientation setted programingly.

Introduction


A sample showing how to print XML documents serially by a WebBrowser Control, in orientations setted programmingly.


Background


If you want to output the XML file to printer well formatted (like a WebPage or a Report ) by a StyleSheet file(css,or xslt), it seems a natural way to use a WebBrowser control in a WinForm application. Unfortunately there is no interface in WebBrowser to set the orientation programmingly. WebBrowser.ShowPageSetupDialog() method should be called, and users who want to print several XML documents in different orientations must click the Portrait or Landscape RadioButton in the [Page Setup] dialog, and then click the OK button to let the printing going on.


There should be no way to change the orientation setting of WebBrowser without [Page Setup] dialog, So I tried to find out a way to simulate the actions users do when a [Page Setup] dialog shown.


With a CBT hook DLL created by VC++2008 (the code is short and easy to understand, thanks people for sharing their C++ codes in the internet. I am not really good at C++ ), application caught the [Page Setup] Dialog of WebBrowser shown by a ShowPageSetupDialog() call, and set the orientation in the dialog by SendMessage() method , then send a message to close the dialog immediately. It works silently , users can not realize that a dialog has shown and the actions done by the application.


How Does it Work



  1. There are 3 functions in the C++ source file named PrinterHooker.cpp:

    CBTHookCallback()  Keep watching on if there is a dialog will be shown, send a message named "PRINTLIB_HOOK_HCBT_ACTIVATE" to the application setted the hook when found one. 


    SetCBTHook() Set the hook to be effective.


    UnSetCBTHook() Disable the hook after a printing.


  2. I created a dialog named frmPrint.cs to be shown when printing a document, which with a ProgressBar and a infomation Label in it as a friendly UI. And most of important functions implemented in this class:

In the SetPrintOrient() function, the PrintHook.SetCBTHook() is called before the calling of ShowPageSetupDialog(), so a "PRINTLIB_HOOK_HCBT_ACTIVATE" message will be sent back from PrintHooker when the [Page Setup] dialog being activated by OS.  


private void SetPrintOrient(EOrientationType orientationType)
{
    menumOrientationType = orientationType;
    try
    {
        SetCBTHook(this.Handle, GetCurrentThreadId());
        wbPrint.ShowPageSetupDialog();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

In the WndProc() function,application checks the title of the window to find out if it is a [Page Setup] dialog when received the "PRINTLIB_HOOK_HCBT_ACTIVATE" message from PrintHooker.  


protected override void WndProc(ref Message m)
{
    if (m.Msg == RegisterWindowMessage("PRINTLIB_HOOK_HCBT_ACTIVATE"))
    {
        IntPtr hwndPageSetting = m.WParam;
        StringBuilder sbtitle = new StringBuilder(256);
        GetWindowText(hwndPageSetting, sbtitle, 256);
        if (sbtitle.ToString() == PAGE_SETUP_TITLE)
        {
            //Do the actions to set the orientation
            ...
            //Close the [Page Setup] dialog immediately after orientation setting.
            SendMessage(hwndPageSetting, WM_CLOSE, IntPtr.Zero, null);
            //Delete the hook
            UnSetCBTHook();
        }
    }
    base.WndProc(ref m);
}


  1. Form1.cs is a simple sample Form to show how to initiallize the frmPrint with XmlPrinter class, and how to print several XML documents like this:

private void button1_Click(object sender, EventArgs e)
{
    XmlPrintLib.XmlPrinter.Print(this, Path.Combine(Application.StartupPath, "XMLFile1.xml"), false);
    XmlPrintLib.XmlPrinter.Print(this, Path.Combine(Application.StartupPath, "XMLFile2.xml"), true);
    XmlPrintLib.XmlPrinter.Print(this, Path.Combine(Application.StartupPath, "XMLFile1.xml"), false);
    XmlPrintLib.XmlPrinter.Print(this, Path.Combine(Application.StartupPath, "XMLFile2.xml"), true);
}

Just run it and click the print button ,four sample documents will be output to your printer in the order of [Portrait, Landscape , Portrait, Landscape ].


Key Point


The appearance of [Page Setup] dialog is different depend on the IE language , please remember to modify App.config in advance, there are texts of PageSetup Dialog in it, comment out the sections don't match your IE Language!


for example, it works well in Japanese OS like this:


<appSettings>
  <!-- English -->
  <!--
  <add key="PAGE_SETUP_TITLE" value="Page Setup" />
  <add key="BUTTON_PORTRAIT" value="Portrait" />
  <add key="BUTTON_LANDSCAPE" value="Landscape" />
  <add key="BUTTON_OK" value="OK" />
  -->

  <!-- Japanese -->
  <add key="PAGE_SETUP_TITLE" value="ページ設定" />
  <add key="BUTTON_PORTRAIT" value="縦" />
  <add key="BUTTON_LANDSCAPE" value="横" />
  <add key="BUTTON_OK" value="OK" />
  <!-- Chinese -->
  <!--
  <add key="PAGE_SETUP_TITLE" value="页面设置" />
  <add key="BUTTON_PORTRAIT" value="纵向" />
  <add key="BUTTON_LANDSCAPE" value="横向" />
  <add key="BUTTON_OK" value="确定" />
  -->
</appSettings>

It should works well in Visual Studio 2008 and .NET Framework 3.5. If error occurs, read the comment in source for more details.


Points of Interest


It's such a complex solution for such a simple thing. I do not think it is the best way, anyone has better ideas to set the orientation of WebBrowser?


History


Edited on 2010/11/18. Any new improvements will be posted if necessary.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)