Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

**Устранение ошибки установки альбомной ориентации печати в Delphi XE6**

Delphi , Синтаксис , Справочник по API-функциям

Устранение ошибки установки альбомной ориентации печати в Delphi XE6

В последнее время разработчики, использующие среду разработки Delphi XE6, столкнулись с неприятной ошибкой, которая проявляется при попытке установить альбомную ориентацию печати. Ошибка возникает в результате вызова функции Printer.Orientation := poLandscape; и сопровождается криптическим сообщением:

Операция не поддерживается на выбранном принтере

Отладка кода

При отладке кода, связанного с функционалом печати, выяснилось, что проблема заключается в том, что глобальный объект TPrinter не может получить структуру DEVMODE для принтера. Это происходит из-за ошибки в вызове функции DocumentProperties из модуля Vcl.Printers. В частности, проблема заключается в следующих строках:

if DeviceMode = 0 then  // выделение нового блока устройства, если он не был передан
begin
    DeviceMode := GlobalAlloc(GHND,
          DocumentProperties(0, FPrinterHandle, ADevice, nil, nil, 0));
    // ...snip...
end;

bufferSize := DocumentProperties(0, FPrinterHandle, ADevice, PDeviceMode(@dummyDevMode), PDeviceMode(@dummyDevMode), 0); //20160522 Borland забыл проверить результат

Функция DocumentProperties возвращает -1, что является ошибкой, так как параметры, передаваемые в функцию, не содержат явных ошибок. Несмотря на то, что DocumentProperties не документирована как функция, устанавливающая код последней ошибки при сбое, вызов GetLastError возвращает код ошибки 50 - Запрос не поддерживается.

Обзор кода

В коде присутствуют серьезные недочеты:

  • Вызов DocumentProperties без проверки возвращаемого значения (возвращает значение меньше нуля при сбое).
  • DocumentProperties возвращает знаковое 32-битное целое.
  • При вызове GlobalAlloc происходит потеря данных, так как он ожидает беззнаковое 32-битное целое.
  • DocumentProperties возвращает -1, который преобразуется в FFFFFFFF при передаче в GlobalAlloc, и в результате попытка выделения 4 ГБ памяти.

Почему ошибка возникает только в XE6

Тот же самый код работает в Delphi 7, что делает проблему особенно странной. Это связано с изменениями в переводах заголовков функций DocumentProperties в Winapi.WinSpool в XE6, где присутствует сложная система перегрузок функций.

Минимальная тестовая программа

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

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils, Windows, WinSpool;

var
    dwBufferLen: DWORD;
    defaultPrinter: string;
    ADevice: PChar; // Указатель на имя принтера
    printerHandle: THandle;
    devModeSize: Integer;
    deviceMode: THandle;
begin
    dwBufferLen := 1024;
    SetLength(defaultPrinter, dwBufferLen);
    GetDefaultPrinter(PChar(defaultPrinter), @dwBufferLen);
    SetLength(defaultPrinter, dwBufferLen);
    ADevice := PChar(defaultPrinter);

    if not OpenPrinter(ADevice, {var}printerHandle, nil) then
        raise Exception.Create('Ошибка при открытии принтера');

    devModeSize := DocumentProperties(0, printerHandle, ADevice, nil, nil, 0);
    if devModeSize < 0 then
    begin
        // DocumentProperties возвращает значение меньше нуля, что означает сбой.
        // Он также должен установить код последней ошибки; но мы все равно поднимем его.
        RaiseLastOSError;
        Exit;
        // Это хорошо, что мы терпим неудачу, так как возвращаемое значение -1 преобразуется в $FFFFFFFF.
        // Delphi затем просит GlobalAlloc попытаться выделить 4 ГБ памяти.
    end;

    deviceMode := GlobalAlloc(GHND, NativeUInt(devModeSize));
    if deviceMode = 0 then
        raise Exception.Create('Ошибка выделения памяти для DEVMODE');
end.

Подтвержденный ответ

После долгих попыток решения проблемы, был найден следующий способ устранения ошибки:

DevSize := DocumentPropertiesA(0, FDriverHandle, FDeviceName, nil, nil, 0);
if DevSize = -1 then
begin
    log('Ошибка при общении с драйвером принтера! Попытка обойти ошибку ');
    GetDriverInfos(FDriverHandle);
    DevSize := DocumentPropertiesA(0, FDriverHandle, FDeviceName, nil, nil, 0);
    if DevSize <> -1 then
        log('Ошибка обойдена.');
end;

Этот метод помог в Delphi XE6 и более поздних версиях, включая Delphi 10.1 Berlin. Ошибка возникала случайным образом и, по-видимому, была связана с обновлением драйверов или операционной системы.

Альтернативный ответ

Возможно, проблема связана с разрядностью приложения. Если переключить тестовый код с 32-битной на 64-битную разрядность, то проблема может быть решена. Это указывает на то, что 32-битное приложение пытается работать с 64-битными драйверами, что приводит к ошибке.

Выводы

Проблема установки альбомной ориентации печати в Delphi XE6 связана с ошибкой в работе с драйверами принтеров и может быть вызвана изменениями в операционной системе. Для её решения можно использовать функцию GetDriverInfos, которая может "сбросить" систему управления принтерами, или же убедиться, что приложение и драйверы принтеров работают в одной разрядности.

Создано по материалам из источника по ссылке.

Описание контекста: Разработчики сталкиваются с проблемой установки альбомной ориентации печати в Delphi XE6, связанной с ошибками в работе с драйверами принтеров.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Справочник по API-функциям ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2024-12-26 14:08:19/0.0036139488220215/0