Modyfikowanie ustawień drukarki przy użyciu funkcji SetPrinter

Funkcja SetPrinter umożliwia aplikacjom zmianę różnych atrybutów drukarki. Jednak, jak pokazuje kod w tym artykule, pewna ilość przygotowania jest niezbędna do poprawnego wywołania SetPrinter.

Oryginalna wersja produktu: Windows
Oryginalny numer KB: 140285

hPrinter parametru SetPrinter

Pierwszym parametrem jest dojście do drukarki, której ustawienia mają zostać zmienione. Ten parametr powinien zostać pobrany z pliku OpenPrinter().

dwLevel parametru SetPrinter

Drugi parametr określa strukturę danych przekazywanych do SetPrinter()programu . Wartość parametru może wynosić 0, 2, 3, 4,5, 6, 7, 8 lub 9.

Parametr lpbPrinter dla elementu SetPrinter

Trzeci parametr to PRINTER_INFO_n struktura, w której n odpowiada liczbie w drugim parametrze. Ta struktura może powodować nieporozumienia, ponieważ nie jest to po prostu bufor rozmiaru struktury. Struktury te zawierają informacje niezależne od urządzenia, ale są natychmiast obserwowane w pamięci przez pewną zmienną ilość informacji zależnych od urządzenia, które są podawane przez sterownik urządzenia. W związku z tym jest trochę pracy, aby określić, jak istotny powinien być ten bufor. Jest to osiągane przez wywołanie GetPrinter()elementu , co spowoduje ustawienie pcbNeeded całkowitego wymaganej wielkości.

Ponadto bufor zwykle zawiera dużą ilość informacji niezależnych od urządzenia i zależnych od urządzenia. Aplikacja nie będzie wiedzieć ani dbać o wartości w większości tych elementów członkowskich struktury. Dlatego podczas wprowadzania zmian, które Cię interesują, musisz podłączyć odpowiednie wartości dla wszystkich tych innych elementów danych. Te inne elementy danych są ustawiane podczas wywoływania GetPrinter() po raz drugi.

Parametr DwCommand dla elementu SetPrinter

Czwarty parametr służy do wstrzymywania drukowania, wznawiania drukowania lub wyczyszczania wszystkich zadań drukowania. Ten parametr zwykle nie jest używany w tym samym czasie, w lpbPrinter jakim jest używany. Ten artykuł nie dotyczy ustawiania stanu drukarki, dlatego przykładowy kod ustawia ten parametr na zero.

Informacje o środowisku DEVMODE

Często element DEVMODE struktury wskazywanej przez pDevMode zostanie zmodyfikowany (zamiast elementu PRINTER_INFO_n). W takim przypadku flagi poinformują pDevMode->dmFields aplikację, które pola można zmienić. Ponieważ jest to podane przez GetPrinter()program , możesz sprawdzić flagę dmFields przed podjęciem próby zmiany.

Ponadto, ponieważ modyfikowanie pól w części niezależnej DEVMODE od urządzenia może również wpływać na zmiany w części zależnej od urządzenia, należy wywołać DocumentProperties() ją przed wywołaniem SetPrinter() , aby utworzyć spójną DEVMODE strukturę dla SetPrinter()elementu .

Przykładowy kod

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