Как я могу вызвать диалоговое окно для настройки параметров принтера вручную? - PullRequest
5 голосов
/ 07 апреля 2009

Я использую WPF, и мне нужно разрешить пользователям устанавливать некоторые параметры печати, такие как свойства принтера и принтера (например, лоток для бумаги, альбомная / книжная ориентация, дуплекс и т. Д.) Мне известен класс PrintDialog для получения объектов PrintQueue и PrintTicket. Однако мне нужно создать собственное решение и я не могу показать PrintDialog. Мне удается получить доступные объекты PrintQueue и позволить пользователям выбрать принтер. Я борюсь со свойствами принтера. Мой вопрос: как я могу показать диалоговое окно, в котором пользователь может установить свойства принтера для выбранного PrintQueue (диалоговое окно, которое отображается, когда пользователь нажимает кнопку «Свойства» в WPF PrintDialog).

Ответы [ 2 ]

4 голосов
/ 13 сентября 2009

Следующий код был найден здесь (минус событие Window_Loaded). Я проверил это, и это, кажется, работает как шарм. Очевидно, вам придется установить имя принтера в объекте PrinterSettings перед отображением диалогового окна.

Надеюсь, это работает для вас:

[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 pDevMode = GlobalLock(hDevMode);
    Int32 fMode = 0;
    int sizeNeeded = DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, fMode);
    IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);

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

private void Window_Loaded(object sender, RoutedEventArgs e) {
    OpenPrinterPropertiesDialog(new PrinterSettings(), new WindowInteropHelper(this).Handle);
}
3 голосов
/ 10 апреля 2013

Если вы нацелены на компиляцию x86 и запускаете с машины x64, код от Pwninstein не будет работать: при выделении devModeData, DocumentPropreties всегда будет неудачным и вернет sizeNeeded -1, а LastError код 13.

Чтобы решить проблему, убедитесь, что вы нацелились AnyCPU или просто измените вызов на DocumentPropreties на следующее:

int sizeNeeded = DocumentProperties(pHandle, 
                                    IntPtr.Zero, 
                                    printerSettings.PrinterName, 
                                    IntPtr.Zero, // This solves it
                                    pDevMode, 
                                    fMode);

Использование IntPtr.Zero вместо правильного указателя на структуру DevMode выглядит неправильно, но этот первый вызов DocumentProperties не пытается изменить память в этой позиции. Единственными данными, возвращаемыми вызовом, является объем памяти, необходимый для хранения данных режима устройства, которые представляют внутренние параметры драйвера принтера.

Справка:

...