Modificar configurações de impressora com a Função DocumentProperties()

Este artigo mostra como modificar as configurações da impressora com a DocumentProperties() função.

Versão original do produto: Impressora
Número de KB original: 167345

Resumo

Usar uma estrutura DEVMODE para modificar as configurações da impressora é mais difícil do que apenas alterar os campos da estrutura. Especificamente, uma estrutura DEVMODE válida para um dispositivo contém dados privados que só podem ser modificados pela DocumentProperties() função.

Este artigo explica como modificar o conteúdo de uma estrutura DEVMODE com a DocumentProperties() função.

Mais informações

Uma estrutura DEVMODE, conforme documentado pelo SDK do Win32, contém dados públicos ou "independentes de dispositivo" e dados privados ou "dependentes de dispositivo". A parte privada de um DEVMODE existe imediatamente após a parte pública, que é definida pela estrutura DEVMODE, em um buffer contíguo de memória.

Um programa não pode prever o tamanho desse buffer porque ele é diferente de impressora para impressora e de versão para versão do driver de impressora. Além disso, uma estrutura DEVMODE declarada por um programa não contém espaço suficiente para dados de dispositivo privado. Se um buffer DEVMODE que não tem dados privados for passado para funções como CreateDC(), ResetDC()e DocumentProperties(), a função poderá falhar.

Para usar de forma confiável um DEVMODE com um driver de dispositivo, crie e modifique-o seguindo estas etapas:

  1. Determine o tamanho necessário do buffer do dispositivo e, em seguida, aloque memória suficiente para ele.

    DocumentProperties() retorna o número de bytes necessários para um buffer DEVMODE quando o último parâmetro é definido como 0. O código de exemplo neste artigo usa essa técnica para determinar o tamanho correto do buffer. Em seguida, o código de exemplo usa a função de alocação de memória em tempo de execução C de malloc() para alocar um buffer grande o suficiente. Como DocumentProperties() e funções gostam ResetDC() e CreateDC() levam ponteiros para um DEVMODE como um parâmetro, a maioria dos aplicativos pode alocar memória que é endereçada por um ponteiro.

    No entanto, funções como os parâmetros de tomada comuns PrintDlg() necessários para serem manipulados para a memória global. Se um programa usar o buffer de DEVMODE final como parâmetro para uma dessas funções, ele deverá alocar memória usando GlobalAlloc() e obter um ponteiro para o buffer usando GlobalLock().

  2. Peça ao driver do dispositivo para inicializar o buffer DEVMODE com as configurações padrão.

    O código de exemplo chama DocumentProperties() uma segunda vez para inicializar o buffer alocado com as configurações padrão atuais. DocumentProperties() preenche o buffer chamado de parâmetro pDevModeOutput com as configurações atuais da impressora quando o DM_OUT_BUFFER comando é passado no parâmetro fMode.

  3. Faça alterações na parte pública do DEVMODE e peça ao driver do dispositivo para mesclar as alterações na parte privada do DEVMODE chamando DocumentProperties().

    Depois de inicializar o buffer com as configurações atuais na etapa 2, o código de exemplo faz alterações na parte pública do DEVMODE. Consulte a documentação do SDK do Win32 para obter descrições dos membros de DEVMODE. Este código de exemplo determina se a impressora pode usar configurações de orientação e duplex (lado duplo) e as altera adequadamente.

    Observação

    Um sinalizador no membro dmFields de um DEVMODE é apenas uma indicação de que uma impressora usa o membro da estrutura associado. As impressoras têm uma variedade de características físicas diferentes e, portanto, só podem dar suporte a um subconjunto das funcionalidades documentadas de um DEVMODE. Para determinar as configurações com suporte do campo de um DEVMODE, os aplicativos devem usar DeviceCapabilities().

    Em seguida, o código de exemplo faz uma terceira chamada para DocumentProperties() e passa o buffer DEVMODE nos parâmetros pDevModeInput e pDevModeOutput. Ele também passa os comandos combinados de DM_IN_BUFFER e DM_OUT_BUFFER no parâmetro fMode usando o operador OR("|"). Esses comandos dizem à função para pegar as configurações contidas no buffer de entrada e mesclá-las com as configurações atuais do dispositivo. Em seguida, ele grava o resultado no buffer especificado no parâmetro out.

Observação

DocumentProperties() refere-se a uma impressora específica por um identificador para uma impressora: hPrinter. Esse identificador é obtido de OpenPrinter(), que o código de exemplo também ilustra. OpenPrinter() requer o nome de uma impressora, que normalmente é o nome amigável da impressora como ela aparece no shell do Sistema Operacional. Esse nome pode ser obtido de EnumPrinters(), da estrutura DEVNAMES retornada por PrintDlg(), ou da Impressora Padrão.

Neste artigo, as duas primeiras etapas de alocar o tamanho correto do buffer e inicializar esse buffer são executadas com DocumentProperties(). Você também pode seguir essas etapas usando GetPrinter().

Para obter mais informações e um exemplo disso, consulte Modificar configurações da impressora usando a função SetPrinter.

Código de exemplo

O código de exemplo segue estas três etapas para obter e alterar o buffer DEVMODE. A função usa uma impressora nomeada e configura um DEVMODE para imprimir de lado duplo e na orientação paisagística se ela dá suporte a esses recursos. O DEVMODE resultante que é retornado ao chamador é adequado para outras chamadas de API que usam buffers DEVMODE, como CreateDC(), SetPrinter(), PrintDlg()ou ResetDC(). Quando o chamador é concluído usando o buffer DEVMODE, o chamador é responsável por liberar a memória.

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