Welcome to MSDN Blogs Sign in | Join | Help

Printing documents to Microsoft XPS Document Writer without user interaction

Now that the XPS storm has been started, people are generating XPS documents from all kinds of sources. Among different ways of XPS generation, the easily way is still through printing to the Microsoft XPS Document Writer (the MXDW printer driver).

If you're printing from your own applications, it's easy to specify MXDW as the printer driver and provide a file name for the XPS document to be saved to. But if you're using certain applications to print a documents, a print dialog box and a file save dialog box could pop up on screen, blocking attempts for fully automatic document conversion. 

For different document types, you can check Windows registry to find the command to print it. For example, the command to print an HTML page is:

rundll32.exe mshtml.dll,PrintHTML "<document>" "<driver>" "<device>" "<port>"

So you should be able to print any webpage to any printing device, to any printer/file, fully automatically. But this creates a security risk, so it has since been blocked. User confirmation is needed to print an HTML page through MSHTML.DLL.

But if you're willing to write some code, automatic document printing is still possible. Here is one solution:

#include <windows.h>

#include <strsafe.h>

 

const wchar_t * Dialog_Class = L"#32770";

 

 

HRESULT PrintHTML(const wchar_t * pUri, const wchar_t * pFileName)

{

    HRESULT hr;

 

    STARTUPINFO          si = { sizeof(si) };

    PROCESS_INFORMATION  pi;

 

    wchar_t command[MAX_PATH];

 

    hr = StringCchPrintf(command, _countof(command),

             L"rundll32.exe mshtml.dll,PrintHTML \"%s\"", pUri);

 

    if (FAILED(hr))

    {

        return hr;

    }

 

    if (CreateProcess(0, command, 0, 0, FALSE, 0, 0, 0, &si, &pi))

    {

        printf("\r\nStarting '%S'\r\n", command);

 

        CloseHandle(pi.hProcess);

        CloseHandle(pi.hThread);

    }

 

    DWORD size = _countof(command);

    GetDefaultPrinter(command, & size);

    printf("  Default printer: '%S'\r\n", command);

 

    printf("\r\nWaiting for Print dialog box\r\n");

    Sleep(5 * 1000);

 

    // Find Print Dialog box

    HWND hWnd = FindWindow(Dialog_Class, L"Print");

 

    // Print button

    HWND hChild = FindWindowEx(hWnd, NULL, NULL, L"&Print");

 

    GetWindowText(hChild, command, _countof(command));

 

    printf("  hwnd = %p %p('%S')\r\n", hWnd, hChild, command);

 

    // Press Print button

    SendMessage (hChild, WM_IME_KEYDOWN, 'P', 0);

   

    printf("\r\nWaiting for File Save dialog box\r\n");

    Sleep(5 * 1000);

 

    // Find Save File Dialog Box

 

    hWnd   = FindWindow(Dialog_Class, L"Save the file as");

   

    hChild = FindWindowEx(hWnd, NULL, L"ComboBoxEx32", NULL);

    hChild = FindWindowEx(hChild, NULL, L"ComboBox", NULL);

    hChild = FindWindowEx(hChild, NULL, L"Edit", NULL);    // File name edit control

 

    printf("  hwnd = %p %p\r\n", hWnd, hChild);

   

    // Enter file name

    SendMessage(hChild, WM_SETTEXT, NULL, (LPARAM) pFileName);

 

    Sleep(1000);

 

    // Find Save button

    hChild = FindWindowEx(hWnd, NULL, NULL, L"&Save");

 

    GetWindowText(hChild, command, _countof(command));

 

    printf("  hwnd = %p %p('%S')\r\n", hWnd, hChild, command);

 

    // Press Save button

    SendMessage (hChild, WM_IME_KEYDOWN, 'S', 0);

 

    printf("\r\nSaving to '%S'\r\n", pFileName);

 

    return hr;

}

 

The code uses CreateProcess to call rundll32 with the right parameters to start the printing process. It then waits for a while for the Print dialog box to pop up and fakes a click on the Print button. After that, it waits for the File Save dialog box to enter a destination file name and click on the Save button.

 

Here is how this routine can be called:

 

      PrintHTML(L"http://blogs.msdn.com/fyuan", L"c:\\fyuan.xps");

 

The code will generate enough logging information for you to see if things are working or not:

 

         Starting 'rundll32.exe mshtml.dll,PrintHTML "http://blogs.msdn.com/fyuan"'   

      Default printer: 'Microsoft XPS Document Writer'

 

Waiting for Print dialog box

  hwnd = 0021075C 002B0754('&Print')

 

Waiting for File Save dialog box

  hwnd = 001E04A2 00260B72

  hwnd = 001E04A2 002D0BA6('&Save')

 

Saving to 'c:\fyuan.xps'

Note:

 

1) The code assumes MXDW is already the default printer driver. If this is not the case, you may want to add code to make it so before the Print dialog box pops up; or add code to mimic selection of MXDW as the printer driver.

 

2) The code uses fixed length wait for the Print dialog box and File SaveAs dialog box to pop up. This is not a very stable solution or it could take too much time. You may want to add better robust and efficient solutions.

 

3) The code is clealy very sensitive to OS version, application version, and UI language. You may need to find a more generic solution and a more robust solution.

Published Saturday, February 24, 2007 3:03 PM by fyuan
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# printing &raquo; Printing documents to Microsoft XPS Document Writer without user &#8230;

Friday, April 06, 2007 6:59 PM by carloshm

# re: Printing documents to Microsoft XPS Document Writer without user interaction

Hi Feng,

Would it be possible to use the System.Printing namespace to print XPS documents?

I was thinking that perhaps using it to print would be shorter.

Best regards

Wednesday, April 25, 2007 6:19 AM by himanshu

# re: Printing file

hii Feng,

Would it be possible to write a code which will just take the path from a location suppose "C:\himanshu\printhtml.htm" and print a html file for me . if that so than please help me out

Thursday, May 31, 2007 9:52 PM by John Bradstreet

# re: Printing documents to Microsoft XPS Document Writer without user interaction

Will the above code work in international builds of window?   It is searching for specific english strings (e.g. "Save the file as", and "Print").

Friday, September 28, 2007 6:19 PM by Peter Carlson

# re: Printing documents to Microsoft XPS Document Writer without user interaction

This is a terrible solution.  Nothing more than a hack.

What if the user has another save as box already open?  What if the user is using an international version?  You dont even make sure the save as window is a child of the process that you ran.

Sunday, October 21, 2007 11:51 PM by Jerry

# re: Printing documents to Microsoft XPS Document Writer without user interaction

Thanks to your doc, it helped me a lot but...

How can I print a pdf document without user interaction ?

Thank you very much

Friday, October 26, 2007 4:46 AM by Jessie

# re: Printing documents to Microsoft XPS Document Writer without user interaction

poor Jerry, saw your name again...

Monday, November 12, 2007 9:08 PM by Tien Tien

# re: Printing documents to Microsoft XPS Document Writer without user interaction

the first time i read that page is very helpful for me. But can i ask 1 more question.

How to make that C code above can install to IE. So i can use javascript or jsp to print a html page

Thank in advance

Thursday, January 31, 2008 12:32 PM by Robert Li

# re: Printing documents to Microsoft XPS Document Writer without user interaction

This is great information. Thank you for doing this.

Friday, February 01, 2008 8:26 PM by Noticias externas

# Generating XPS Automagically

I got a mail overnight asking about ways to automatically generate XPS from applications, specifically

Tuesday, May 27, 2008 12:29 PM by Goldtree

# re: Printing documents to Microsoft XPS Document Writer without user interaction

Hello Feng,

Would you suggest a solution without the UI hacking?

Appreciate,

Sunday, October 19, 2008 12:54 PM by Anuradha

# re: Printing documents to Microsoft XPS Document Writer without user interaction

Hi Feng

Would Like to ask you one doubt? Can the xps document created from same file have different sizes on different machines?

I am getting it, not sure its bug or thats the way it behaves?

Monday, October 27, 2008 8:51 AM by Tim Haughton

# re: Printing documents to Microsoft XPS Document Writer without user interaction

@Anuradha - see my answer to your post on the XPS forum.

Convert2XPS provides a way to convert or print documents to an XPS file without faking the click on the print dialog. It uses a collection of converters and a custom XPS printer driver to provide a conprehensive conversion suite.

Takes just 1 line of code.

Tuesday, July 28, 2009 10:59 PM by Tom

# mshtml.dll output compared against IE8 output

The mshtml.dll,PrintHTML is okay, but the output isn't as good as the results obtained by printing normally through IE8.  For example, I have an HTML file with a long table that includes <thead> and <tfoot> sections that I'd like to see repeated at the top and bottom of each page.  IE8 produces the desired result (a multi-page table with the table header and footer table sections repeated on each page), but the mshtml.dll,PrintHTML method doesn't repeat the header or footer table sections.  What gives?

Wednesday, August 05, 2009 12:23 PM by Zashkaser

# Привет

Sorry but I don’t share most of these ideas.

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker