locked
Dialog for printer properties RRS feed

  • Question

  •  

    Hi, I’d like to show  printer properties dialog in my code.

    The first possibility I have is to use the standard windows dialog like:

     

    System.Windows.Forms.PrintDialog printDialog = new System.Windows.Forms.PrintDialog();

    printDialog.Document = this.printDocument;

    printDialog.ShowDialog();

     

    Then the user has to click the „Properties“ button and the dialog I wanna have pops up.

    But I’d like to show this dialog directly without using System.Windows.Forms.PrintDialog.

     

    Here is the code I have from codeproject.net:

     

    [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,  ref IntPtr pDevModeInput, int fMode);

    [DllImport("kernel32.dll")]

    static extern IntPtr GlobalLock(IntPtr hMem);

    [DllImport("kernel32.dll")]

    static extern bool GlobalUnlock(IntPtr hMem);

    [DllImport("kernel32.dll")]

    static extern bool GlobalFree(IntPtr hMem);

    public void OpenPrinterPropertiesDialog(PrinterSettings printerSettings, System.IntPtr pHandle)

    {

    IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);

          IntPtr pDevMode = GlobalLock(hDevMode);

          int sizeNeeded = DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, ref pDevMode, 0);

          IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);

    DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, devModeData, ref pDevMode, 4);

          GlobalUnlock(hDevMode);

          printerSettings.SetHdevmode(devModeData);

          printerSettings.DefaultPageSettings.SetHdevmode(devModeData);

          GlobalFree(hDevMode);

          Marshal.FreeHGlobal(devModeData);

    }

     

    The function OpenPrinterProperties calls the dialog I need. The only problem is:

                -the dialog does not represents the settings printerSettings.DefaultPageSettings

                -the changes you make in this dialog are not kept when you close the dialog

    (normally the changes should be written in printerSettings.DefaultPageSettings)

     

    What’s wrong with this code?

    Wednesday, September 26, 2007 11:14 AM

Answers

  • Hi Peter,

    I finally found the problem, please check out the following modified code:

    Code Block

    // The signature you use is not correct
    //[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, ref IntPtr pDevModeInput, int fMode);


    [DllImport("kernel32.dll")]
    static extern IntPtr GlobalLock(IntPtr hMem);

    [DllImport("kernel32.dll")]
    static extern bool GlobalUnlock(IntPtr hMem);

    [DllImport("kernel32.dll")]
    static extern bool GlobalFree(IntPtr hMem);

    [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);

    private const Int32 DM_OUT_BUFFER = 14;

    public void OpenPrinterPropertiesDialog(PrinterSettings printerSettings, System.IntPtr pHandle)
    {
        IntPtr hDevMode = printerSettings.GetHdevmode();
        //IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);

        IntPtr pDevMode = GlobalLock(hDevMode);

        //  If this parameter is zero, the DocumentProperties function returns the number of bytes required by the printer driver's DEVMODE data structure.
        Int32 fMode = 0;

        int sizeNeeded = DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, fMode);
        IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);

        // Output value. The function writes the printer driver's current print settings,
        // including private data, to the DEVMODE data structure specified by the
    pDevModeOutput parameter.
        fMode = DM_OUT_BUFFER;

        DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, devModeData, pDevMode, fMode);
        GlobalUnlock(hDevMode);
        printerSettings.SetHdevmode(devModeData);
        printerSettings.DefaultPageSettings.SetHdevmode(devModeData);
        GlobalFree(hDevMode);
        Marshal.FreeHGlobal(devModeData);
    }

     

     

    I’ve tested this code and it worked well both on Xp and server 2003. For more details, please visit DocumentProperties and C# Signature of it.

    Hope this helps!

    Thanks!

     

    Tuesday, October 2, 2007 4:00 AM

All replies

  • Hi Peter,

    I’d like to see how exactly you are using the function (OpenPrinterPropertiesDialog). Especially how exactly did you get the handle of the printer and pass it to the second argument (pHandle)?

    Thanks!

    Friday, September 28, 2007 8:21 AM
  • Hi Feng,

     

    due to Microsoft definition of the DocumentProperties there are to handles: one for the parent windot and another one

    for the printer.

     

    LONG DocumentProperties(
      HWND
    hWnd,               // handle to parent window
      HANDLE hPrinter,         // handle to printer object
      LPTSTR pDeviceName,      // device name
      PDEVMODE pDevModeOutput, // modified device mode
      PDEVMODE pDevModeInput// original device mode
      DWORD fMode              // mode options
    );

     

    The code I posted doesn't use the handle of the printer at all (I pass IntPtr.Zero instead of it). The value I pass to the second argument of OpenPrinterPropertiesDialog is the handle of the parent window.

     

    So I use the function OpenPrinterPropertiesDialog in that way:

     

    class MyWindow : System.Windows.Forms.Form

    {

    public MyWindow()

    {

    PrintDocument pDoc = new PrintDocument();

    OpenPrinterPropertiesDialog(pDoc.DefaultPageSettings.PrinterSettings, this.Handle);

    }

     

    private void OpenPrinterPropertiesDialog()

    {

    ...

    }

     

    Thank you for your reply! 

     

     

     

    Friday, September 28, 2007 8:54 AM
  • Hi Peter,

    Your code is actually using the “this.Handle” which is the window handle of the form.

    And in the article How to show a popup window for printer properties of codeproject, the signature of OpenPrinterPropertiesDialog function is like this:

    Code Block

    private void OpenPrinterPropertiesDialog(PrinterSettings printerSettings).

     

    Different with your code, so you can try modify your code like this and try again.

    Thanks!

    Friday, September 28, 2007 9:05 AM
  • Hi Cheng,

     

    yes, this is the article i used. As you can see the function OpenPrinterPropertiesDialog in this article uses the handle of the form too.

     

    Code Block

    DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, devModeData, ref pDevMode, 14);

                GlobalUnlock(hDevMode);

     

     

    And they also pass IntPtr.Zero instead of the handle of the printer. I believe it's not necessary to pass the real handle for the printer. It seems like passing printerSettings.PrinterName is enough.

     

     

     

    Friday, September 28, 2007 9:15 AM
  • Hi Peter,

    I’d apologize for replying too quickly. However, I have reproduced out your problem, but I still did not figure out the root cause.

    I will spend more time on it, Thanks for your understanding.

    Friday, September 28, 2007 9:50 AM
  • Hi Feng,

     

    thank you for taking your time. I'd be happy if you could help me. I've spend a lot of time trying to find a solution in the Internet but I couldn't find something useful.

     

    Friday, September 28, 2007 9:56 AM
  • Hi Peter,

    I finally found the problem, please check out the following modified code:

    Code Block

    // The signature you use is not correct
    //[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, ref IntPtr pDevModeInput, int fMode);


    [DllImport("kernel32.dll")]
    static extern IntPtr GlobalLock(IntPtr hMem);

    [DllImport("kernel32.dll")]
    static extern bool GlobalUnlock(IntPtr hMem);

    [DllImport("kernel32.dll")]
    static extern bool GlobalFree(IntPtr hMem);

    [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);

    private const Int32 DM_OUT_BUFFER = 14;

    public void OpenPrinterPropertiesDialog(PrinterSettings printerSettings, System.IntPtr pHandle)
    {
        IntPtr hDevMode = printerSettings.GetHdevmode();
        //IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);

        IntPtr pDevMode = GlobalLock(hDevMode);

        //  If this parameter is zero, the DocumentProperties function returns the number of bytes required by the printer driver's DEVMODE data structure.
        Int32 fMode = 0;

        int sizeNeeded = DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, fMode);
        IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);

        // Output value. The function writes the printer driver's current print settings,
        // including private data, to the DEVMODE data structure specified by the
    pDevModeOutput parameter.
        fMode = DM_OUT_BUFFER;

        DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, devModeData, pDevMode, fMode);
        GlobalUnlock(hDevMode);
        printerSettings.SetHdevmode(devModeData);
        printerSettings.DefaultPageSettings.SetHdevmode(devModeData);
        GlobalFree(hDevMode);
        Marshal.FreeHGlobal(devModeData);
    }

     

     

    I’ve tested this code and it worked well both on Xp and server 2003. For more details, please visit DocumentProperties and C# Signature of it.

    Hope this helps!

    Thanks!

     

    Tuesday, October 2, 2007 4:00 AM
  • A possible  reason  is  : Your printer's name is too long.

    If the printer's name longger than 32 ASCII. The follow code:

          printerSettings.SetHdevmode(devModeData);

          printerSettings.DefaultPageSettings.SetHdevmode(devModeData);

         will can't work well.

    I am finding how to resolve it too.

    Thursday, November 1, 2007 9:27 AM
  • Can anybody help me to get "Printer's Model Name" using c#

     


    Many Thanks Deepak
    Wednesday, June 16, 2010 10:22 AM