Изменение параметров принтера с помощью функции DocumentProperties()

В этой статье показано, как изменить параметры принтера с помощью DocumentProperties() функции .

Исходная версия продукта: Принтера
Исходный номер базы знаний: 167345

Сводка

Использовать структуру DEVMODE для изменения параметров принтера сложнее, чем просто изменить поля структуры. В частности, допустимая структура DEVMODE для устройства содержит частные данные, которые могут быть изменены только функцией DocumentProperties() .

В этой статье объясняется, как изменить содержимое структуры DEVMODE с помощью DocumentProperties() функции .

Дополнительная информация

Структура DEVMODE, как описано в пакете SDK для Win32, содержит общедоступные или "независимые от устройства данные", а также частные или "зависимые от устройства данные". Частная часть DEVMODE существует сразу после общедоступной части, определенной структурой DEVMODE, в непрерывном буфере памяти.

Программа не может предсказать размер этого буфера, так как он отличается от принтера к принтеру и от версии к версии драйвера принтера. Кроме того, структура DEVMODE, объявленная программой, не содержит достаточно места для данных частных устройств. Если буфер DEVMODE, в который отсутствуют частные данные, передается в такие функции, как CreateDC(), ResetDC()и DocumentProperties(), функция может завершиться ошибкой.

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

  1. Определите требуемый размер буфера с устройства, а затем выделите для него достаточно памяти.

    DocumentProperties() возвращает количество байтов, необходимых для буфера DEVMODE, если для последнего параметра задано значение 0. В примере кода в этой статье используется этот метод для определения правильного размера буфера. Затем в примере кода используется функция выделения памяти во время выполнения C для выделения достаточно большого malloc() буфера. Так как DocumentProperties() функции, такие как ResetDC() и , CreateDC() принимают указатели на DEVMODE в качестве параметра, большинство приложений могут выделять память, адресуемую указателем.

    Однако такие функции, как общие PrintDlg() , принимают параметры, необходимые для обработки, в глобальную память. Если программа использует окончательный буфер DEVMODE в качестве параметра для одной из этих функций, она должна выделить память с помощью GlobalAlloc() и получить указатель на буфер с помощью GlobalLock().

  2. Попросите драйвер устройства инициализировать буфер DEVMODE с параметрами по умолчанию.

    Пример кода вызывает DocumentProperties() второй раз для инициализации выделенного буфера с текущими параметрами по умолчанию. DocumentProperties() Заполняет буфер, называемый параметром pDevModeOutput , текущими параметрами принтера при DM_OUT_BUFFER передаче команды в параметре fMode.

  3. Внесите изменения в общедоступную часть DEVMODE и попросите драйвер устройства объединить изменения в частную часть DEVMODE, вызвав DocumentProperties().

    После инициализации буфера с текущими параметрами на шаге 2 пример кода вносит изменения в общедоступную часть DEVMODE. Описание элементов DEVMODE см. в документации по пакету SDK для Win32. Этот пример кода определяет, может ли принтер использовать параметры ориентации и дуплексных (двусторонних) и изменяет их соответствующим образом.

    Примечание.

    Флаг в члене dmFields DEVMODE является только признаком того, что принтер использует связанный элемент структуры. Принтеры имеют различные физические характеристики и поэтому могут поддерживать только подмножество задокументированных возможностей DEVMODE. Чтобы определить поддерживаемые параметры поля DEVMODE, приложения должны использовать DeviceCapabilities().

    Затем пример кода выполняет третий вызов DocumentProperties() и передает буфер DEVMODE в параметрах pDevModeInput и pDevModeOutput. Он также передает объединенные команды DM_IN_BUFFER и DM_OUT_BUFFER в параметре fMode с помощью оператора OR("|"). Эти команды сообщают функции принять все параметры, содержащиеся во входном буфере, и объединить их с текущими параметрами устройства. Затем он записывает результат в буфер, указанный в параметре out.

Примечание.

DocumentProperties() ссылается на конкретный принтер с помощью дескриптора к принтеру: hPrinter. Этот дескриптор получен из OpenPrinter(), который также иллюстрирует пример кода. OpenPrinter() требуется имя принтера, которое обычно является понятным именем принтера, которое отображается в оболочке операционной системы. Это имя можно получить из EnumPrinters(), из структуры DEVNAMES, возвращаемой PrintDlg(), или из принтера по умолчанию.

В этой статье первые два шага выделения правильного размера буфера и инициализации этого буфера выполняются с помощью DocumentProperties(). Эти действия также можно выполнить с помощью GetPrinter().

Дополнительные сведения и пример см. в статье Изменение параметров принтера с помощью функции SetPrinter.

Пример кода

Пример кода выполняет следующие три шага для получения и изменения буфера DEVMODE. Функция принимает именованный принтер и настраивает DEVMODE для печати двусторонней и в альбомной ориентации, если она поддерживает эти функции. Результирующий объект DEVMODE, возвращаемый вызывающей объекту, подходит для других вызовов API, использующих буферы DEVMODE, таких как CreateDC(), SetPrinter(), PrintDlg()или ResetDC(). Когда вызывающий объект завершил работу с помощью буфера DEVMODE, вызывающий объект отвечает за освобождение памяти.

 LPDEVMODE GetLandscapeDevMode(HWND hWnd, char *pDevice)
 {
    HANDLE hPrinter;
    LPDEVMODE pDevMode;
    DWORD dwNeeded, dwRet;
    
    /* Start by opening the printer */ 
    if (!OpenPrinter(pDevice, &hPrinter, NULL))
        return NULL;
    
    /*
    * Step 1:
    * Allocate a buffer of the correct size.
    */ 
    dwNeeded = DocumentProperties(hWnd,
    hPrinter, /* Handle to our printer. */ 
    pDevice, /* Name of the printer. */ 
    NULL, /* Asking for size, so */ 
    NULL, /* these are not used. */ 
    0); /* Zero returns buffer size. */ 
    pDevMode = (LPDEVMODE)malloc(dwNeeded);
    
    /*
    * Step 2:
    * Get the default DevMode for the printer and
    * modify it for your needs.
    */ 
    dwRet = DocumentProperties(hWnd,
    hPrinter,
    pDevice,
    pDevMode, /* The address of the buffer to fill. */ 
    NULL, /* Not using the input buffer. */ 
    DM_OUT_BUFFER); /* Have the output buffer filled. */ 
    if (dwRet != IDOK)
    {
        /* If failure, cleanup and return failure. */ 
        free(pDevMode);
        ClosePrinter(hPrinter);
        return NULL;
    }
    
    /*
    * Make changes to the DevMode which are supported.
    */ 
    if (pDevMode->dmFields & DM_ORIENTATION)
    {
        /* If the printer supports paper orientation, set it.*/ 
        pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
    }
    
    if (pDevMode->dmFields & DM_DUPLEX)
    {
        /* If it supports duplex printing, use it. */ 
        pDevMode->dmDuplex = DMDUP_HORIZONTAL;
    }
    
    /*
    * Step 3:
    * Merge the new settings with the old.
    * This gives the driver an opportunity to update any private
    * portions of the DevMode structure.
    */ 
    dwRet = DocumentProperties(hWnd,
    hPrinter,
    pDevice,
    pDevMode, /* Reuse our buffer for output. */ 
    pDevMode, /* Pass the driver our changes. */ 
    DM_IN_BUFFER | /* Commands to Merge our changes and */ 
    DM_OUT_BUFFER); /* write the result. */ 
    
    /* Finished with the printer */ 
    ClosePrinter(hPrinter);
    
    if (dwRet != IDOK)
    {
        /* If failure, cleanup and return failure. */ 
        free(pDevMode);
        return NULL;
    }
    
    /* Return the modified DevMode structure. */ 
    return pDevMode;
}