We have build a custom print dialog that has a button for showing the printer specific dialog. I read this answer by Shurup, and it helped me to achieve this. (Edit: But it contains an error, as explained in my answer)
However, we use this in combination with stored settings. When we call the method with our PrinterSettings
they get ignored. The native dialog shows its default settings, regardless of the provided settings object.
EDIT: Removed my fail-code.
Thanks to this page I found a working solution! The code in the other stackoverflow answer that I linked, contained a small but significant error: The external call to DocumentProperties
had the input DEVMODE parameter defined as ref
parameter. The working solution doesn't use ref! This may seem insignificant, but actually (at least in my Win32 XP environment) it caused the printer dialog to ignore the input!
This code takes the settings from the PrinterSettings, sets the printer dialog accordingly and updates the PrinterSettings afterwards (you may ignore the calls to get a window handle from WPF):
[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("kernel32.dll")]
static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
static extern bool GlobalUnlock(IntPtr hMem);
private void OpenPrinterPropertiesDialog(PrinterSettings printerSettings)
{
Window parentWindow = Window.GetWindow(this);
if (parentWindow == null)
{
return;
}
IntPtr hDevMode = IntPtr.Zero;
IntPtr devModeData = IntPtr.Zero;
try
{
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(parentWindow).Handle;
//get DEVMODE from settings
hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);
IntPtr pDevMode = GlobalLock(hDevMode);
//get needed size and allocate memory
int sizeNeeded = DocumentProperties(hwnd, IntPtr.Zero, printerSettings.PrinterName, IntPtr.Zero, pDevMode, 0);
devModeData = Marshal.AllocHGlobal(sizeNeeded);
//show the native dialog
DocumentProperties(hwnd, IntPtr.Zero, printerSettings.PrinterName, devModeData, pDevMode, 14);
GlobalUnlock(hDevMode);
//get settings and page settings from changed DEVMODE
printerSettings.SetHdevmode(devModeData);
printerSettings.DefaultPageSettings.SetHdevmode(devModeData);
}
finally
{
if (hDevMode != IntPtr.Zero)
{
Marshal.FreeHGlobal(hDevMode);
}
if (devModeData != IntPtr.Zero)
{
Marshal.FreeHGlobal(devModeData);
}
}
}