none
Advanced Printer Properties Dialog in WPF

    Question

  • I'm trying to get the advanced printer properties dialog to display on the push of a button.  It should display the same thing as the Preferences button on the PrintDialog.ShowDialog window.  Is there a supplied class to do this in the .NET Framework?  If not, how is this done considering the Window API wants a DEVMODE and WPF printing uses a PrintTicket?  I seen examples of how to do this using Windows Forms, but haven't seen any examples for getting this same functionality in WPF.  Which is why I'm thinking I'm missing something.

    Any help would be appreciated

    Wednesday, October 07, 2009 5:48 PM

Answers

  • I think I may be making some headway, but I need some assistance on one issue.  The print settings are flowing out of the dialog, but not in.  For example, if the PrintTicket is set to Landscape when entering the dialog, the dialog still shows Portrait.  But if the orientation is changed while it is open, it does show this change on the retrieved PrintTicket.  How do I fix this one issue?

    EDIT:  Had a ref keyword on the pDevModeInput parameter.  Removed it and it works as expected.  So below is a working solution.  If there is a better way or if I'm doing something incorrectly, please let me know.

    		[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true,
    			 ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    		static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
    			[MarshalAs(UnmanagedType.LPWStr)] string pDeviceName,
    			IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
    
    			PrintTicketConverter ptc = new PrintTicketConverter(SelectedPrintQueue.Name, SelectedPrintQueue.ClientPrintSchemaVersion);
    			IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
    
    			byte[] myDevMode = ptc.ConvertPrintTicketToDevMode(SelectedPrintQueuePrintTicket, BaseDevModeType.UserDefault);
    			GCHandle pinnedDevMode = GCHandle.Alloc(myDevMode, GCHandleType.Pinned);
    			IntPtr pDevMode = pinnedDevMode.AddrOfPinnedObject();
    			DocumentProperties(mainWindowPtr, IntPtr.Zero, SelectedPrintQueue.Name, pDevMode, pDevMode, 14);
    			SelectedPrintQueuePrintTicket = ptc.ConvertDevModeToPrintTicket(myDevMode);
    			pinnedDevMode.Free();
    
    • Edited by TBlackbird Thursday, October 08, 2009 7:00 PM Bug in code found and removed
    • Marked as answer by TBlackbird Thursday, October 08, 2009 7:00 PM
    Thursday, October 08, 2009 6:29 PM

All replies

  • It is the same as in WindowsForms.....

    You need to add the referance System.Windows.Forms

    and than

     

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click

     

    Dim dlg As New System.Windows.Forms.PrintDialog

    dlg.ShowDialog()

     

    End Sub


    Kenneth
    Wednesday, October 07, 2009 7:36 PM
  • I'm looking to display the advanced printer settings, not the printer dialog.  Run your code above and hit the preferences button on the window that is displayed.  That is the window I want/need without having to get there from the print dialog.
    Thursday, October 08, 2009 2:11 PM
  • I think I may be making some headway, but I need some assistance on one issue.  The print settings are flowing out of the dialog, but not in.  For example, if the PrintTicket is set to Landscape when entering the dialog, the dialog still shows Portrait.  But if the orientation is changed while it is open, it does show this change on the retrieved PrintTicket.  How do I fix this one issue?

    EDIT:  Had a ref keyword on the pDevModeInput parameter.  Removed it and it works as expected.  So below is a working solution.  If there is a better way or if I'm doing something incorrectly, please let me know.

    		[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true,
    			 ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    		static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
    			[MarshalAs(UnmanagedType.LPWStr)] string pDeviceName,
    			IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
    
    			PrintTicketConverter ptc = new PrintTicketConverter(SelectedPrintQueue.Name, SelectedPrintQueue.ClientPrintSchemaVersion);
    			IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
    
    			byte[] myDevMode = ptc.ConvertPrintTicketToDevMode(SelectedPrintQueuePrintTicket, BaseDevModeType.UserDefault);
    			GCHandle pinnedDevMode = GCHandle.Alloc(myDevMode, GCHandleType.Pinned);
    			IntPtr pDevMode = pinnedDevMode.AddrOfPinnedObject();
    			DocumentProperties(mainWindowPtr, IntPtr.Zero, SelectedPrintQueue.Name, pDevMode, pDevMode, 14);
    			SelectedPrintQueuePrintTicket = ptc.ConvertDevModeToPrintTicket(myDevMode);
    			pinnedDevMode.Free();
    
    • Edited by TBlackbird Thursday, October 08, 2009 7:00 PM Bug in code found and removed
    • Marked as answer by TBlackbird Thursday, October 08, 2009 7:00 PM
    Thursday, October 08, 2009 6:29 PM
  • Be careful. For network printers you will need to use the SelectedPrintQueuePrintTicket.FullName property instead of the Name property!
    Thursday, August 19, 2010 4:39 AM
  • Thank you,

    I was trying to do this myself and you saved me a lot of trouble.

    I especially like your usage of pinning the GCHandle as I was going the route of Marshal.AllocHGlobal, with the code looking a lot less clean and unnecessary copying.

    Monday, October 25, 2010 5:19 PM
  • A simpler way to do this is to simply invoke the regular WPF PrintDialog.ShowDialog() and let the user set whatever he wants (including printer preferences) over there. When the user clicks the Print button the document should reflow itself based on the new page size and other settings in the PrintTicket and then start printing. Also notice that in Microsoft applications such as WordPad, clicking the Apply button and closing the PrintDialog without clicking Print still causes the document to relow itself to the new settings.

    If your objective is simply to force the user to preview the new page size/orientation in case he directly clicks the Print button, then you can simply pop up a MessageBox notifying him that the document has changed and whether he want to continue printing.

    Tuesday, October 16, 2012 9:38 AM