Andrey Bushman
Andrey Bushman

Reputation: 12516

Why I don't get the context of the virtual printer?

Windows 8.1 x64

I have installed PdfCreater virtual printer. It is the default printer (and single) on my computer.

Now I want to get its context:

HDC GetPrinterDC(void)
{
    PRINTER_INFO_5 pinfo5[3];
    ZeroMemory(pinfo5, sizeof(pinfo5));
    DWORD dwNeeded, dwReturned;
    if (EnumPrinters(PRINTER_ENUM_DEFAULT, NULL, 5,
        (LPBYTE)pinfo5, sizeof(pinfo5), 
        &dwNeeded, /* I get 0 */
        &dwReturned /* I get 0 */)) {
        // And I am here...
        return CreateDC(NULL, pinfo5[0].pPrinterName, NULL, NULL); // NULL
    }
    return 0;
}

But I get NULL. Why does it happen?

Upvotes: 1

Views: 241

Answers (1)

Barmak Shemirani
Barmak Shemirani

Reputation: 31659

Don't do error check on the result of the first EnumPrinters (Petzold doesn't do it either)

Note also, the amount of required memory could be several hundred bytes for 1 printer. But PRINTER_INFO_5 pinfo5[1]; may allocate less than that. So you have to allocate what the first EnumPrinters call tells you.

HDC printerDC = NULL;
DWORD flags = PRINTER_ENUM_LOCAL;// | PRINTER_ENUM_CONNECTIONS;
DWORD memsize, printer_count;

//figure out how much memory we need
EnumPrinters(flags, NULL, 5, NULL, 0, &memsize, &printer_count);
if (memsize < 1) return;

//allocate memory
BYTE* bytes = new BYTE[memsize];

if (EnumPrinters(flags, NULL, 5, bytes, memsize, &memsize, &printer_count))
{
    if (printer_count > 0)
    {
        PRINTER_INFO_5* printerInfo = (PRINTER_INFO_5*)bytes;
        printerDC = CreateDC(NULL, printerInfo->pPrinterName, NULL, NULL);

        //optional, list printer names
        for (UINT i = 0; i < printer_count; i++)
        {
            OutputDebugString(printerInfo->pPrinterName);
            OutputDebugString(L"\n");
            printerInfo++;
        }
    }
}
delete[] bytes;

If you want to access default printer, another option is to use PRINTDLG (without actually showing any print dialog)

PRINTDLG pdlg;
memset(&pdlg, 0, sizeof(PRINTDLG));
pdlg.lStructSize = sizeof(PRINTDLG);
// Set the flag to return printer DC, but don't show dialog
pdlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;

PrintDlg(&pdlg);
printerDC = pdlg.hDC;

see also
How To Print a Document
How To: Retrieve a Printer Device Context

Upvotes: 3

Related Questions