Printing to Microsoft XPS Document Writer without showing File Save Dialog Box

Somehow commenting was not working on my blog, so a reader send me an email on how to print to XPS Document Writer in a server environment without popping up file save dialog box.

Printing to file is supported by GDI through the DOCINFO structure passed to StartDoc call. Here is a sample code:

void UILessXPSGeneration(const TCHAR * fileName)


    HDC hDC = CreateDC(NULL, L“Microsoft XPS Document Writer”, NULL, NULL);


    DOCINFO docinfo;


    memset(&docinfo, 0, sizeof(docinfo));


    docinfo.cbSize = sizeof(docinfo);

    docinfo.lpszOutput = fileName;


    int result;


    result = StartDoc(hDC, & docinfo);

    result = StartPage(hDC);


    const TCHAR * message = L“Hello XPS”;


    result = TextOut(hDC, 100, 100, message, (int) _tcslen(message));


    result = EndPage(hDC);

    result = EndDoc(hDC);




Here is the XPS FixedPage generated:

<FixedPage Width=816 Height=1056 xmlns= xml:lang=en-US>

      <Path Data=F1 M 16,16 L 80.8,16 80.8,32 16,32 z Fill=#ffffffff />

      <Glyphs Fill=#ff000000 FontUri=/font_0.TTF FontRenderingEmSize=14.3217

            StyleSimulations=None OriginX=16 OriginY=28.8


            UnicodeString=Hello XPS />



Comments (14)

  1. anon says:

    Thanks 😉

  2. Rhodry says:

    Hi Feng,

    Great work…..

    Is there any easy way of generalizing this to allow other 3rd party applications to print to the MXDW and not be bothered by the File Save As dialog?

    eg. "Hooking" the printing application’s StartDoc and generating a filename from a registry key template string (and the passed in PRINTER_JOB/DEVMODE info) (or in a known location) – such as the printer driver’s spool directory?

    eg. HKLM/Microsoft/Microsoft XPS Document Writer/AutoSaveTemplate =


    Where %M = machine name [filename escaped]

    %U = user name [filename escaped]

    %J = job number

    Is such a thing possible?

    Do you think it would be supported "out of the box"?



  3. Navigation says:


  4. Jai says:

    This works for me at least for the short term.

    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _

                   (ByVal hWndParent As Long, ByVal hWndChildAfter As Long, _

                   ByVal lpClassName As String, ByVal lpWindowName As String) As Long

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _

                   (ByVal hwnd As Long, ByVal wMsg As Long, _

                   ByVal wParam As Long, ByVal lParam As Any) As Long


    Private Declare Function PostMessage Lib "user32" _

       Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

    Private Declare Function FindWindow Lib "user32" _

       Alias "FindWindowA" (ByVal szClass$, ByVal szTitle$) As Long

       Private Const WM_CLOSE = &H10

       Private Const BM_CLICK As Long = &HF5&

       Private Const WM_KEYDOWN = &H100

       Private Const WM_KEYUP = &H101

       Private Const WM_CHAR = &H102

       Private Const WM_SETTEXT As Long = &HC

    Private Sub Command1_Click()

        WindowHandle = FindWindow(vbNullString, "Save the file as")

           cboBoxHandle = FindWindowEx(WindowHandle, 0, "ComboBoxEx32", "")

           retVal = SendMessage(cboBoxHandle, WM_SETTEXT, ByVal CLng(0), "c:w.xps")

           ButtonHandle = FindWindowEx(WindowHandle, 0, "Button", "&Save")

           retVal = SendMessage(ButtonHandle, BM_CLICK, 0, "0")End Sub

  5. ... says:

    mmm.. nice design, I must say..

  6. ... says:

    Du musst ein Fachmann sein – wirklich guter Aufstellungsort, den du hast!

  7. ... says:

    luogo grande:) nessun osservazioni!

  8. abuobaid says:

    How can i do that using any .NET language ?

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

  10. wajahat says:

    hi feng, great work.. i tested it in my application and it worked fine..but i am confused about my problem. actually we have an application in MFC..which supports printing like conventional applications.. now i want to create XPS documents on some event say behind some button click "generate XPS file" which asks the file name and i create an XPS file of that the problem is how my current DC(holding all my drawings) will be mapped to this new dc i have just created for writing XPS file..??I mean we already have written a wrapper over windows GDI library which does all drawings for my i want all my current drawingns to be written to the XPS file..actually i am not much familiar with windows graphics programming and GDI concepts..please help..thanks

  11. Süleyman says:

    What language is this sample written in?

    Is it possible to make use of MXDW in a .NET application? If yes, then how?


  12. Jason says:

    Where are the XPS spool files stored on the system?  When I print in WinXP to the XPS Document write the C:WINDOWSsystem32spoolPRINTERS contains a small .SHD file and a zero byte .SPL file.

  13. Mangesh says:

    Hi Feng,  

         I am trying to show a custom SaveAS dialog while printing to the XPS Printer driver. I have the following questions as below in this regards

    1] Is it possible to override the MXDW printer and launch the custom SaveAs dialog. Which dll or component should I customise.

    2] I need to add a filter to the pipeline for merging to existing documents or for conversion to PDF. Is it possible to use the MXDW printer for this purpose. Or should I use the XPSDrvSmpl and add to the filter pipeline.

    3] If I use the XPSDrvSmpl sample as in above, how do I show the Custom SaveAs dialog in that example. However the XPSDrvSmpl does a lot of unwanted UI stuff, while I am happy with what I see in the MXDW.

    Please advise.