Modificación de la configuración de la impresora mediante la función SetPrinter

La SetPrinter función permite a las aplicaciones cambiar varios atributos de impresora. Sin embargo, como muestra el código de este artículo, es necesario una cierta cantidad de preparación para llamar SetPrintercorrectamente a .

              Versión original del producto: Windows
Número de KB original: 140285

Parámetro hPrinter para SetPrinter

El primer parámetro es un identificador de la impresora cuya configuración se va a cambiar. Este parámetro debe recuperarse de OpenPrinter().

Parámetro dwLevel para SetPrinter

El segundo parámetro especifica la estructura de los datos que se pasan a SetPrinter(). El valor del parámetro puede ser 0, 2, 3, 4,5, 6, 7, 8 o 9.

Parámetro lpbPrinter para SetPrinter

El tercer parámetro es una PRINTER_INFO_n estructura donde n corresponde al número del segundo parámetro. Esta estructura puede causar confusión porque no es simplemente un búfer del tamaño de la estructura. Estas estructuras contienen información independiente del dispositivo, pero se siguen inmediatamente en la memoria por una cantidad variable de información dependiente del dispositivo, que proporciona el controlador de dispositivo. Por lo tanto, se trata de un poco de trabajo para determinar qué tan significativo debe ser este búfer. Esto se logra mediante una llamada a GetPrinter(), que se establecerá pcbNeeded en el tamaño total necesario.

Además, el búfer suele tener una gran cantidad de información independiente del dispositivo y dependiente del dispositivo. La aplicación no va a conocer ni preocuparse por los valores de la mayoría de estos miembros de la estructura. Por lo tanto, al realizar los cambios en los que está interesado, debe conectar los valores correctos para todos estos otros datos. Estos otros datos se establecen cuando se llama por GetPrinter() segunda vez.

Parámetro DwCommand para SetPrinter

El cuarto parámetro se usa para pausar la impresión, reanudar la impresión o borrar todos los trabajos de impresión. Este parámetro normalmente no se usa al mismo tiempo lpbPrinter que se usa. En este artículo no se trata de establecer el estado de la impresora, por lo que el código de ejemplo establece este parámetro en cero.

Acerca de DEVMODE

A menudo, se modificará un elemento de la estructura a la DEVMODE que apunta ( pDevMode en lugar de un elemento de PRINTER_INFO_n). En este caso, las pDevMode->dmFields marcas indicarán a la aplicación qué campos se pueden cambiar. Dado que esto se le da mediante GetPrinter(), puede comprobar la dmFields marca antes de intentar el cambio.

Además, dado que la modificación de campos en la parte independiente del dispositivo de DEVMODE también puede afectar a los cambios en la parte dependiente del dispositivo, debe llamar DocumentProperties() a antes de llamar SetPrinter() a para crear una estructura coherente DEVMODE para SetPrinter().

Código de ejemplo

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