Recently I was responsible for developing an application that needed to run a child process to perform a
conversion on legacy data. The data would later be imported into Paradox tables.
The child process, a legacy DOS application, imposed some constraints:
- A printer had to be installed.
- A page was printed after each run.
The first constraint was easy to satisfy but the second proved a little bit more
challenging. My intention was to disable the Windows default printer before running the child process, then purge
the print queue, and finally re-enable the printer. This part was the easiest because Windows
provides the necessary APIs:
- OpenPrinter retrieves a handle to the specified printer, given a name.
- SetPrinter sets the state of the specified printer object by pausing printing, resuming printing, or clearing all print jobs.
- ClosePrinter closes the specified printer object.
The challenging part was to get the default printer name to use in the OpenPrinter call.
It turns out that this simple task isn't simple at all. You must use a different strategy for
each version of Windows (95/98, NT, and 2000). Only Windows 2000 has a direct
API to access the default printer name!
- Windows 95/98: The EnumPrinters API is used in conjunction with the flag
PRINTER_ENUM_DEFAULT to return information about the default printer. We define the
data structure to be of type PRINTER_INFO_5 (level 5). You have to call this API
twice: the first time to get the size of the output buffer, and the second time to
retrieve the data.
- Windows NT: The GetProfileString API is used. It doesn't retrieve the value
from win.ini but from the registry, because Windows NT maps most .ini file references
to the registry. You have to query the device value of the windows section. The returned
value is of the form <printer name>,<driver name>,<port>, so you have
to extract the first part to get the default printer name.
- Windows 2000: The GetDefaultPrinter API is used. This time, you get the requested
information without a lot of contortions or conversions.
Below, you will find my code for the GetDefaultPrinterName function. Please note that the code
specific to Windows 2000 has not been tested due to a lack of resources -- use it at your own risk!
DWORD GetDefaultPrinterName(LPTSTR PrinterName, DWORD BufferSize)
{
OSVERSIONINFO osvi;
DWORD Needed, Returned, rc, BuffSize;
LPPRINTER_INFO_5 PrinterInfo;
char* p;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
if (!EnumPrinters(PRINTER_ENUM_DEFAULT,NULL,5,NULL,0,&Needed,&Returned))
{
if ((rc = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
return rc;
}
if ((PrinterInfo = LocalAlloc(LPTR,Needed)) == NULL)
rc = GetLastError();
else
{
if (!EnumPrinters(PRINTER_ENUM_DEFAULT,NULL,5,(LPBYTE) PrinterInfo,Needed,&Needed,&Returned))
rc = GetLastError();
else
{
if (Returned > 0)
{
if ((DWORD) lstrlen(PrinterInfo->pPrinterName) > BufferSize-1)
rc = ERROR_INSUFFICIENT_BUFFER;
else
{
lstrcpy(PrinterName,PrinterInfo->pPrinterName);
rc = ERROR_SUCCESS;
}
}
else
{
*PrinterName = '0';
rc = ERROR_SUCCESS;
}
}
LocalFree(PrinterInfo);
}
}
else if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
if (osvi.dwMajorVersion >= 5) /* Windows 2000 or later */
{
BuffSize = BufferSize;
if (!GetDefaultPrinter(PrinterName,&BuffSize))
rc = GetLastError();
else
rc = ERROR_SUCCESS;
}
else /* Windows NT 4.0 or earlier */
{
if (GetProfileString("windows","device","",PrinterName,BufferSize) == BufferSize-1)
return ERROR_INSUFFICIENT_BUFFER;
p = PrinterName;
while (*p != '0' && *p != ',')
++p;
*p = '0';
rc = ERROR_SUCCESS;
}
}
return rc;
}
By Philippe Randour.