How to get the default printer name

By: Philippe Randour

Abstract: You want to access the default printer but you don't know how to get its name from the system. This article will show you how to achieve this result under Windows 95, 98, NT, and 2000. By Philippe Randour.

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.

Server Response from: SC2