Modificare le impostazioni della stampante usando la funzione SetPrinter

La SetPrinter funzione consente alle applicazioni di modificare vari attributi della stampante. Tuttavia, come illustrato nel codice in questo articolo, è necessaria una certa quantità di preparazione per chiamare SetPrintercorrettamente .

              Versione originale del prodotto: Windows
Numero KB originale: 140285

Parametro hPrinter per SetPrinter

Il primo parametro è un handle per la stampante le cui impostazioni devono essere modificate. Questo parametro deve essere recuperato da OpenPrinter().

Parametro dwLevel per SetPrinter

Il secondo parametro specifica la struttura dei dati passati a SetPrinter(). Il valore del parametro può essere 0, 2, 3, 4,5, 6, 7, 8 o 9.

Parametro lpbPrinter per SetPrinter

Il terzo parametro è una PRINTER_INFO_n struttura in cui n corrisponde al numero nel secondo parametro. Questa struttura può causare confusione perché non è semplicemente un buffer delle dimensioni della struttura. Queste strutture contengono informazioni indipendenti dal dispositivo, ma vengono immediatamente seguite in memoria da una quantità variabile di informazioni dipendenti dal dispositivo, fornite dal driver di dispositivo. Pertanto, è necessario un piccolo lavoro per determinare quanto deve essere significativo questo buffer. A tale scopo, chiamare GetPrinter(), che verrà impostato sulle pcbNeeded dimensioni totali necessarie.

Inoltre, il buffer contiene in genere una grande quantità di informazioni indipendenti dal dispositivo e dipendenti dal dispositivo. L'applicazione non conoscerà né si preoccuperà dei valori nella maggior parte di questi membri della struttura. Quindi, quando si apportano le modifiche a cui si è interessati, è necessario collegare i valori corretti per tutti questi altri dati. Questi altri dati vengono impostati quando si chiama GetPrinter() una seconda volta.

Parametro DwCommand per SetPrinter

Il quarto parametro viene usato per sospendere la stampa, riprendere la stampa o cancellare tutti i processi di stampa. Questo parametro in genere non viene usato contemporaneamente lpbPrinter all'utilizzo. Questo articolo non riguarda l'impostazione dello stato della stampante, pertanto il codice di esempio imposta questo parametro su zero.

Informazioni su DEVMODE

Spesso, un elemento della DEVMODE struttura a pDevMode cui punta verrà modificato (anziché un elemento di PRINTER_INFO_n). In questo caso, i pDevMode->dmFields flag indicheranno all'applicazione quali campi possono essere modificati. Poiché questa operazione viene fornita da GetPrinter(), è possibile controllare il dmFields flag prima di tentare la modifica.

Inoltre, poiché la modifica dei campi nella parte indipendente dal dispositivo di DEVMODE può influire anche sulle modifiche nella parte dipendente dal dispositivo, è necessario chiamare DocumentProperties() prima di chiamare SetPrinter() per creare una struttura coerente DEVMODE per SetPrinter().

Codice di esempio

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