Печать Win32 - невозможно установить ландшафтный режим

У меня есть старое приложение, которое мне нужно для печати в ландшафтном режиме. В документации, которую я нашел, говорится, что нужно получить структуру DEVMODE, изменить пару полей и вернуть ее обратно. Что у меня есть:

    HANDLE printer_handle;
    LPHANDLE printer_handle_pointer(&printer_handle);
    OpenPrinter(printer_name.get(), printer_handle_pointer, NULL);
    size_t devmode_size = DocumentProperties(hWnd, printer_handle_pointer, printer_name.get(), NULL, NULL, 0);
    DEVMODE * devmode = reinterpret_cast<DEVMODE *>(new char[devmode_size]);
    DocumentProperties(NULL, printer_handle_pointer, printer_name.get(), devmode, NULL, DM_OUT_BUFFER);
    devmode->dmSize = sizeof( DEVMODE);
    devmode->dmFields |= DM_ORIENTATION;
    devmode->dmOrientation = DMORIENT_LANDSCAPE;
    DocumentProperties(NULL, printer_handle_pointer, printer_name.get(), devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER);
    hdcPrint = CreateDC(NULL, printer_name.get(), NULL, devmode);

Моя текущая проблема заключается в том, что первый DocumentProperties (тот, который возвращает размер структуры DEVMODE) возвращает -1 (на самом деле эквивалент без знака), что означает состояние ошибки. Это происходит как в режиме отладки, так и в режиме выпуска (в одном отчете, который я видел в Интернете, эта проблема была в режиме отладки, но не в режиме выпуска). printer_name.get() действителен, но я не знаю, как проверить правильность hWnd или printer_handle_pointer в отладчике.

Итак, я бы хотел, чтобы кто-нибудь сказал мне, что я делаю неправильно, или как лучше это диагностировать, или как определить, действительны ли дескрипторы и указывают ли они на достоверную информацию, я был бы признателен.

Я использую VS 2008SP1 на Vista Business SP1, если это имеет значение. Исходное приложение было написано с более ранней версией VS на какой-то версии XP.


person David Thornley    schedule 24.03.2009    source источник


Ответы (2)


Вы разместили реальный код?

Также взгляните на сигнатуру функции DocumentProperties:

LONG DocumentProperties(
     __in   HWND hWnd,
     __in   HANDLE hPrinter,         
     __in   LPTSTR pDeviceName,
     __out  PDEVMODE pDevModeOutput,
     __in   PDEVMODE pDevModeInput,
     __in   DWORD fMode

Третий параметр принимает HANDLE, а не указатель на HANDLE (или LPHANDLE), как в вашем коде:

DocumentProperties(NULL, 
                   printer_handle_pointer, /* <--- ? */
                   printer_name.get(), 
                   devmode, 
                   NULL, 
                   DM_OUT_BUFFER);

Вместо этого используйте:

DocumentProperties(NULL, 
                   printer_handle, /* <--- ? */
                   printer_name.get(), 
                   devmode, 
                   NULL, 
                   DM_OUT_BUFFER);

Взгляните на этот пример кода для изменения Devmode с помощью функции DocumentProperties.

Обычно я использую GetPrinterW для получения структуры PRINTER_INFO_2W. Участник pDevMode возвращает вам режим разработки. Мне повезло с этим devmode.

person dirkgently    schedule 24.03.2009
comment
Спасибо за подсказку, но мне метод GetPrinter() не помог. - person David Thornley; 24.03.2009

Из документации Microsoft для DocumentProperties:

Чтобы внести изменения в параметры печати, которые являются локальными для приложения, приложение должно выполнить следующие действия:

  1. Получите число байтов, необходимое для полной структуры DEVMODE, вызвав DocumentProperties и указав ноль в параметре fMode.
  2. Выделите память для полной структуры DEVMODE.
  3. Получите текущие настройки принтера, вызвав DocumentProperties. Передайте указатель на структуру DEVMODE, выделенную на шаге 2, в качестве параметра pDevModeOutput и укажите значение DM_OUT_BUFFER.
  4. Измените соответствующие элементы возвращенной структуры DEVMODE и укажите, какие элементы были изменены, установив соответствующие биты в элементе dmFields структуры DEVMODE.
  5. Вызовите DocumentProperties и передайте измененную структуру DEVMODE обратно как параметры pDevModeInput и pDevModeOutput и укажите значения DM_IN_BUFFER и DM_OUT_BUFFER (которые объединяются с помощью оператора ИЛИ). Структуру DEVMODE, возвращенную третьим вызовом DocumentProperties, можно использовать в качестве аргумента. в вызове функции CreateDC.

Похоже, вы пропустили шаг 1, поэтому ваш первый вызов DocumentProperties не удался.

В моей собственной программе я также устанавливаю размер страницы, меняя длину и ширину местами. Это для специального небольшого принтера этикеток с нестандартным размером бумаги, хотя я не знаю, потребуется ли это для более садового принтера.

double width = 8.5;
double height = 11.0;
devmode.dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH;
devmode.dmOrientation = DMORIENT_LANDSCAPE;
devmode.dmPaperSize = DMPAPER_USER;
devmode.dmPaperLength = (short)(width * 25.4 * 10);
devmode.dmPaperWidth = (short)(height * 25.4 * 10);
person Mark Ransom    schedule 24.03.2009
comment
На самом деле у меня есть шаг 1 (строка начинается с size_t devmode_size), и проблема в том, что devmode_size (возвращаемое значение) неточное. Мне видимо было непонятно. - person David Thornley; 24.03.2009
comment
Я немного изменил вопрос, чтобы было понятнее. Надеюсь это поможет. - person David Thornley; 24.03.2009