Modificar as configurações da impressora usando a função SetPrinter

A SetPrinter função permite que os aplicativos alterem vários atributos de impressora. No entanto, como o código neste artigo demonstra, uma certa quantidade de preparação é necessária para chamar SetPrintercorretamente .

Versão original do produto: Windows
Número de KB original: 140285

parâmetro hPrinter para SetPrinter

O primeiro parâmetro é um identificador para a impressora cujas configurações devem ser alteradas. Esse parâmetro deve ser recuperado de OpenPrinter().

parâmetro dwLevel para SetPrinter

O segundo parâmetro especifica a estrutura dos dados que estão sendo passados para SetPrinter(). O valor do parâmetro pode ser 0, 2, 3, 4,5, 6, 7, 8 ou 9.

Parâmetro lpbPrinter para SetPrinter

O terceiro parâmetro é uma PRINTER_INFO_n estrutura em que n corresponde ao número no segundo parâmetro. Essa estrutura pode causar confusão porque não é simplesmente um buffer do tamanho da estrutura. Essas estruturas contêm informações independentes do dispositivo, mas são imediatamente seguidas na memória por alguma quantidade variável de informações dependentes do dispositivo, que é fornecida pelo driver do dispositivo. Portanto, um pouco de trabalho está envolvido para determinar o quão significativo esse buffer deve ser. Isso é obtido chamando GetPrinter(), que será definido pcbNeeded como o tamanho total necessário.

Além disso, o buffer normalmente tem uma grande quantidade de informações independentes de dispositivo e dependentes de dispositivo nele. Seu aplicativo não saberá nem se importará com os valores na maioria desses membros da estrutura. Portanto, ao fazer as alterações nas quais você está interessado, você deve conectar os valores corretos para todas essas outras partes de dados. Esses outros dados são definidos quando você chama GetPrinter() uma segunda vez.

Parâmetro DwCommand para SetPrinter

O quarto parâmetro é usado para pausar a impressão, retomar a impressão ou limpar todos os trabalhos de impressão. Normalmente, esse parâmetro não é usado ao mesmo tempo lpbPrinter que é usado. Este artigo não está preocupado em definir o estado da impressora, portanto, o código de exemplo define esse parâmetro como zero.

Sobre o DEVMODE

Muitas vezes, um elemento da DEVMODE estrutura apontada por pDevMode será modificado (em vez de um elemento de PRINTER_INFO_n). Quando esse for o caso, os pDevMode->dmFields sinalizadores informarão ao aplicativo quais campos podem ser alterados. Como isso é dado a você por GetPrinter(), você pode marcar o dmFields sinalizador antes de tentar a alteração.

Além disso, como modificar campos na parte independente do DEVMODE dispositivo também pode afetar alterações na parte dependente do dispositivo, você precisa chamar DocumentProperties() antes de chamar SetPrinter() para criar uma estrutura consistente DEVMODE para SetPrinter().

Código de exemplo

// MySetPrinter
// Demonstrates how to use the SetPrinter API.  This particular function changes the orientation
// for the printer specified in pPrinterName to the orientation specified in dmOrientation.
// Valid values for dmOrientation are:
// DMORIENT_PORTRAIT (1) or DMORIENT_LANDSCAPE (2)
BOOL MySetPrinter(LPTSTR pPrinterName, short dmOrientation)
{
    HANDLE hPrinter = NULL;
    DWORD dwNeeded = 0;
    PRINTER_INFO_2 *pi2 = NULL;
    DEVMODE *pDevMode = NULL;
    PRINTER_DEFAULTS pd;
    BOOL bFlag;
    LONG lFlag;

    // Open printer handle (on Windows NT, you need full-access because you
    // will eventually use SetPrinter)...
    ZeroMemory(&pd, sizeof(pd));
    pd.DesiredAccess = PRINTER_ALL_ACCESS;
    bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    if (!bFlag || (hPrinter == NULL))
        return FALSE;

    // The first GetPrinter tells you how big the buffer should be in
    // order to hold all of PRINTER_INFO_2. Note that this should fail with
    // ERROR_INSUFFICIENT_BUFFER.  If GetPrinter fails for any other reason
    // or dwNeeded isn't set for some reason, then there is a problem...
    SetLastError(0);
    bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
    if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
    {
        ClosePrinter(hPrinter);
        return FALSE;
    }

    // Allocate enough space for PRINTER_INFO_2...
    pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
    if (pi2 == NULL)
    {
        ClosePrinter(hPrinter);
        return FALSE;
    }

    // The second GetPrinter fills in all the current settings, so all you
    // need to do is modify what you're interested in...
    bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
    if (!bFlag)
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        return FALSE;
    }

    // If GetPrinter didn't fill in the DEVMODE, try to get it by calling
    // DocumentProperties...
    if (pi2->pDevMode == NULL)
    {
        dwNeeded = DocumentProperties(NULL, hPrinter,
        pPrinterName,
        NULL, NULL, 0);
        if (dwNeeded <= 0)
        {
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            return FALSE;
        }

        pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
        if (pDevMode == NULL)
        {
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            return FALSE;
        }

        lFlag = DocumentProperties(NULL, hPrinter,
        pPrinterName,
        pDevMode, NULL,
        DM_OUT_BUFFER);
        if (lFlag != IDOK || pDevMode == NULL)
        {
            GlobalFree(pDevMode);
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            return FALSE;
        }
        pi2->pDevMode = pDevMode;
    }

    // Driver is reporting that it doesn't support this change...
    if (!(pi2->pDevMode->dmFields & DM_ORIENTATION))
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
        GlobalFree(pDevMode);
        return FALSE;
    }

    // Specify exactly what we are attempting to change...
    pi2->pDevMode->dmFields = DM_ORIENTATION;
    pi2->pDevMode->dmOrientation = dmOrientation;

    // Do not attempt to set security descriptor...
    pi2->pSecurityDescriptor = NULL;

    // Make sure the driver-dependent part of devmode is updated...
    lFlag = DocumentProperties(NULL, hPrinter,
      pPrinterName,
      pi2->pDevMode, pi2->pDevMode,
      DM_IN_BUFFER | DM_OUT_BUFFER);
    if (lFlag != IDOK)
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        return FALSE;
    }

    // Update printer information...
    bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
    if (!bFlag)
    // The driver doesn't support, or it is unable to make the change...
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        return FALSE;
    }

    // Tell other apps that there was a change...
    SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L,
      (LPARAM)(LPCSTR)pPrinterName,
      SMTO_NORMAL, 1000, NULL);

    // Clean up...
    if (pi2)
        GlobalFree(pi2);
    if (hPrinter)
        ClosePrinter(hPrinter);
    if (pDevMode)
        GlobalFree(pDevMode);
    return TRUE;
}