title: How to show printer properties/preferences dialog and save changes?
body: <p><strong>EDIT: My fault! I expected the changes to be written back to the default printer settings when in fact only the local instance of the PrinterSettings are changed. - The below code seems to work as intended</strong></p>
  
  <p>I am trying to show the custom printer properties of a given printer. I need this as part of a custom PrintDialog which I am trying to write.</p>
  
  <p>Most of the examples that I can find online manage to show the dialog but any changes the user might make are lost which makes it useless.</p>
  
  <p>Example:
  <a href="http://www.codeproject.com/KB/system/PrinterPropertiesWindow.aspx" rel="noreferrer">http://www.codeproject.com/KB/system/PrinterPropertiesWindow.aspx</a></p>
  
  <p>(regarding above page: I tried to change the code as suggested by BartJoy (on the page) but that didn't fix it)</p>
  
  <p>I also tried the sample and suggestions on the pinvoke.net page but it still doesn't work:</p>
  
  <p><a href="http://www.pinvoke.net/default.aspx/winspool.documentproperties" rel="noreferrer">http://www.pinvoke.net/default.aspx/winspool.documentproperties</a></p>
  
  <p>From the above websites I assume that the problem might only be on 64 bit Windows and/or if a printer name is longer than 32 characters.</p>
  
  <p>I don't know what I should try next... I appreciate any suggestions and comments!</p>
  
  <p>EDIT: Here is what I have tried:</p>
  
  <pre><code>[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);
  
  [DllImport("winspool.drv")]
  private static extern int OpenPrinter(string pPrinterName, out IntPtr hPrinter, IntPtr pDefault);
  [DllImport("winspool.drv")]
  private static extern int ClosePrinter(IntPtr phPrinter);
  
  [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);
  
  private const int DM_PROMPT = 4;
  private const int DM_OUT_BUFFER = 2;
  private const int DM_IN_BUFFER = 8;
  
  private void OpenPrinterPropertiesDialog()
  {
      var printerSettings = new System.Drawing.Printing.PrinterSettings();
      var printerName = printerSettings.PrinterName;
  
      IntPtr handle;
      OpenPrinter(printerName, out handle, IntPtr.Zero);
  
      IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);
      IntPtr pDevMode = GlobalLock(hDevMode);
      int sizeNeeded = DocumentProperties(this.Handle, handle, printerName, pDevMode, pDevMode, 0);
      IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);
      DocumentProperties(this.Handle, handle, printerName, devModeData, pDevMode, DM_IN_BUFFER | DM_PROMPT | DM_OUT_BUFFER);
  
      ClosePrinter(handle);
      GlobalUnlock(hDevMode);
  
      printerSettings.SetHdevmode(devModeData);
      printerSettings.DefaultPageSettings.SetHdevmode(devModeData);
  
      GlobalFree(hDevMode);
      Marshal.FreeHGlobal(devModeData);
  }
  </code></pre>
  
  <p>I have tried to use the OpenPrinter and ClosePrinter method and pass the devModeData as the output parameter in the second call as I found it strange that the original code from the pinvoke.net didn't do this. (but I admit, that I don't know what I am doing - this is just trial and error).</p>
  
  <p>Here is the original code from the pinvoke site:</p>
  
  <pre><code>private void OpenPrinterPropertiesDialog(PrinterSettings printerSettings)
  {
      IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);
      IntPtr pDevMode = GlobalLock(hDevMode);
      int sizeNeeded = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, 0);
      IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);
      DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, IntPtr.Zero, pDevMode, 14);
      GlobalUnlock(hDevMode);
      printerSettings.SetHdevmode(devModeData);
      printerSettings.DefaultPageSettings.SetHdevmode(devModeData);
      GlobalFree(hDevMode);
      Marshal.FreeHGlobal(devModeData);
  }
  </code></pre>