Enumerating Printers

Most of the API printer functions require a handle to a printer.  This handle is easlity obtained by using the OpenPrinter() API function.  However, this latter function requires the name of the printer.  Other functions such as CreateDC() require a driver name as well.  In order to get the printer's name and driver name, you'll need to either, read the win.ini file, use the EnumPrinters() function, or use the PrintDlg() function with the PD_RETURNDEFAULT flag.  As you may have guessed, this latter method can only be used to retrive the default printer info.  Most often you'll want to use the EnumPrinters() function, especially for networked printers.

KEYWORDS: EnumPrinters().
 



 

//---------------------------------------------------------------------------

// Here's the win.ini method:

void GetPrinters(TStrings *Drivers, TStrings *Devices, TStrings *Ports)
{
    TStringList *PrinterList = new TStringList();
    TIniFile *IniFile = new TIniFile("win.ini");
    IniFile->ReadSectionValues("Devices", PrinterList);

    for (int index = 0; index < PrinterList->Count; index++)
    {
        AnsiString Abuffer = PrinterList->Strings[index];

        // parse the buffer to extract individual properties
        Devices->Add(Abuffer.SubString(1, Abuffer.Pos("=") - 1));
        Abuffer = Abuffer.SubString(Abuffer.Pos("=") + 1,
                                    Abuffer.Length() - Abuffer.Pos("="));
        Drivers->Add(Abuffer.SubString(1, Abuffer.Pos(",") - 1));
        Ports->Add(Abuffer.SubString(Abuffer.Pos(",") + 1,
                                     Abuffer.Length() - Abuffer.Pos(",")));
    }

    delete IniFile;
    delete PrinterList;
}

//---------------------------------------------------------------------------

// This is the EnumPrinters method:

void Enum9xPrinters(TStrings *Drivers, TStrings *Devices, TStrings *Ports)
{
    DWORD dwNeeded, dwNumPrinters;
    EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, NULL,
                 0, &dwNeeded, &dwNumPrinters);

    unsigned char *buffer = new unsigned char[dwNeeded];
    EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, buffer,
                 dwNeeded, &dwNeeded, &dwNumPrinters);

    LPPRINTER_INFO_2 lppi2;
    for (int index = 0; index < (int)dwNumPrinters; index++)
    {
        lppi2 = (LPPRINTER_INFO_2)(buffer + index *
                                   sizeof(PRINTER_INFO_2));

        Devices->Add(lppi2->pPrinterName);
        Ports->Add(lppi2->pPortName);
    }
    delete [] buffer;

    EnumPrinterDrivers(NULL, NULL, 2, NULL, 0,
                       &dwNeeded, &dwNumPrinters);

    buffer = new unsigned char[dwNeeded];
    EnumPrinterDrivers(NULL, NULL, 2, buffer, dwNeeded,
                       &dwNeeded, &dwNumPrinters);

    LPDRIVER_INFO_2 lpdi2;
    for (int index = 0; index < (int)dwNumPrinters; index++)
    {
        lpdi2 = (LPDRIVER_INFO_2)(buffer + index *
                                  sizeof(DRIVER_INFO_2));

        AnsiString File = lpdi2->pDataFile;
        File = ExtractFileName(File);
        File = File.SubString(1, File.Length() -
                              ExtractFileExt(File).Length());
        Drivers->Add(File);
    }
    delete [] buffer;
}

//---------------------------------------------------------------------------

// Here's how you use the above functions...

void __fastcall TForm1::EnumPrintersClick(TObject *Sender)
{
    TStringList *Drivers = new TStringList();
    TStringList *Devices = new TStringList();
    TStringList *Ports = new TStringList();

    Enum9xPrinters(Drivers, Devices, Ports);
    // or use:  GetPrinters(Drivers, Devices, Ports);

    for (int index = 0; index < Drivers->Count; index++)
    {
        ListBox1->Items->Add(Drivers->Strings[index]);
        ListBox1->Items->Add(Devices->Strings[index]);
        ListBox1->Items->Add(Ports->Strings[index]);
        ListBox1->Items->Add("------------------------");
    }
    
    delete Drivers;
    delete Devices;
    delete Ports;
}

//---------------------------------------------------------------------------

// You can either read the win.ini file to extract 
// the default printer name, or use the PrintDlg() 
// API function with the PD_RETURNDEFAULT flag...

// Method 1: GetProfileString()
void GetDefaultPrinter(char *printer_name)
{
    char *def_string = "no printer";
    char buffer[MAX_PATH];
    GetProfileString("windows", "device", def_string,
                     buffer, MAX_PATH);

    AnsiString Abuffer(buffer);
    int first_comma = Abuffer.Pos(",");
    strcpy(printer_name, Abuffer.SubString(1, first_comma - 1).c_str());
}

// Method 2: PrintDlg()
void GetDefaultPrinter2(char *printer_name)
{
    PRINTDLG pd;
    ZeroMemory(&pd, sizeof(PRINTDLG));
    pd.lStructSize = sizeof(PRINTDLG);
    pd.Flags = PD_RETURNDEFAULT;

    if (PrintDlg(&pd))
    {
        LPDEVNAMES lpdn = (LPDEVNAMES)GlobalLock(pd.hDevNames);

        CopyMemory((LPBYTE)printer_name,
                   ((LPBYTE)lpdn + lpdn->wDeviceOffset),
                   lpdn->wOutputOffset - lpdn->wDeviceOffset);

        GlobalUnlock(pd.hDevNames);
        GlobalFree(pd.hDevNames);
        GlobalFree(pd.hDevMode);        
    }
}

//---------------------------------------------------------------------------

// Here's how you use the above functions...

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char printer_name[MAX_PATH];

    GetDefaultPrinter(printer_name);
    ShowMessage(printer_name);

    GetDefaultPrinter2(printer_name);
    ShowMessage(printer_name);

}