Virtual Developer Workshop: Containerized Development with Docker


A recent project required me to determine whether a printer supported printing in color. This seemed like the kind of task that others before me must have faced. I searched CodeGuru and other forums and found some approaches to this problem. However, none were too convincing or complete. Each article I found pointed out some flaw in the approach. With a little bit of research, I was able to develop my own approach to the problem.

Printer Drivers Reveal All

I always had a gut feeling that the information I needed was at a very basic low level. With some research, I stumbled across the DrvDeviceCapabilities() function. This function comes from the Microsoft DDK (Driver Development Kit). Microsoft recommends each hadrware vendor export this function from their drivers to provide requested information about a printer's capabilities. By using this function, it's pretty easy to determine color capabilities.

The Code

The first step in determining color capabilities is to open the printer. This is accomplished by the following:

BOOL rc = OpenPrinter(printer.GetBuffer(0), &hPrinter, NULL);

Once this is done, you'll need to get the printer and driver structures:

// get printer info.
rc     = GetPrinter(hPrinter, 2, NULL, NULL, &dwBytesNeeded);
pinfo2 = (PRINTER_INFO_2*) LocalAlloc(LPTR, dwBytesNeeded);
rc     = GetPrinter(hPrinter, 2, (LPBYTE)pinfo2, dwBytesNeeded,
// get driver info.
rc     = GetPrinterDriver(hPrinter, NULL, 2, NULL, NULL,
dinfo2 = (DRIVER_INFO_2*) LocalAlloc(LPTR, dwBytesNeeded);
rc     = GetPrinterDriver(hPrinter, NULL, 2, (LPBYTE)dinfo2,
                          dwBytesNeeded, &dwBytesNeeded);

The function we're interested in resides in the driver configuration file. Once we have it, we can call the function:

// get handle to printer driver config module
HMODULE hmod = LoadLibrary(dinfo2->pConfigFile);
if (hmod)
  // get pointer to exported function.
  GetProcAddress(hmod, "DrvDeviceCapabilities");
  if (DriverCaps)
    WCHAR wszPrinter[256] = {0};
    MultiByteToWideChar(CP_ACP, 0, printer, -1, wszPrinter, 256);
    // call exported function.
    dwColor = (*DriverCaps)(hPrinter, wszPrinter,
                            32 /*DC_COLORDEVICE*/,
                            (VOID*)NULL, pinfo2->pDevMode);

In the preceding code snippet, the DC_COLORDEVICE flag tells "DrvDeviceCapabillites" to return a 1 if the printer supports color, or a 0 if it does not.

To Use

Download the .zip file. It contains the following function:

int CheckForColorPrinter(CString printer)

Include the function in your code and pass it the name of the printer. (You can obtain the name of the printer from CPrintDialog.) If the printer supports color, the function returns "1". If color is NOT supported, it returns "0".



  • Mr

    Posted by Chris Mackay on 01/06/2014 09:42pm

    It is my opinion that dmColor is for telling the print handler how to handle the output and its value is never meant to distinguish a real B&W from a color printer. The HP LaserJet P2015, for example is a black toner only printer, but can handle color if it is converted to a grayscale; dmColor set to DMCOLOR_COLOR comes back as DMCOLOR_COLOR!!! Can anyone tell how to identify a Printer as providing only MonoChrome output (including GRAYSCALE) as opposed to one that can provide both MonoChromer AND Color? The information must be in the system somewhere, especially since it can be seen in Windows 7 Devices and Printers page when a device (such as Samsung CLX-3300) is selected. WMI Scripting might have the answer but it is hiding from me!

    • Second Comment a Decade Later

      Posted by mnin on 06/11/2014 01:22pm

      I found this page yesterday and read the post and the comment - trying to fix our print dialog. I know nothing of MFC. It seems like nobody knows the 'real deal' when it comes to querying Windows/Drivers for info about printers though. I'm liking the authoritative tone of Einman. Think I'm going to use the GetDeviceCapabilities way once I've got some basic info about the printers using the method described above. We should take this to SO lol

  • Not recommended

    Posted by einman on 08/29/2004 08:37am

    There are a variety of problems with this:

    1. You should use the Win32 function DeviceCapabilities, not hack directly into the driver entry point. This breaks Win9x compatibility, which you might not care about, but it also may break future OS compatibility, which is a bad idea.

    This is a nice demonstration of how one could hack into a printer driver (and in fact we do things like this to test our own drivers), but it it completely unnecessary, since there is an OS function to do it.

    2. DC_COLORDEVICE is only supported in Windows 2000 and later, and because of that, drivers designed for NT4 or 9x won't return it. Worse yet, some color drivers don't fill it in correctly.

    The right way(s) to do it:

    DC_COLORDEVICE was intended for this purpose, but it wasn't added until Windows 2000, and isn't required for a color driver to function correctly, so some drivers don't implement it.

    You can find out if a driver is set to print color by calling GetDeviceCaps() on a printer DC and looking at PLANES and BITSPIXEL. Unless they're both 1, the device is color. This is the official way to do it. However, this will really tell you if the driver is currently set to print color. A color printer set to monochrome mode would appear like a monochrome printer. If that's fine, OK.

    If not, try checking DC_COLORDEVICE as well. Lastly, you could try calling DocumentProperties (DM_COPY) to get a DEVMODE, change dmColor to DMCOLOR_COLOR, and pass it back in for validation (DM_COPY|DM_MODIFY), and unless it comes back DMCOLOR_MONOCHROME, the printer is probably color.

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date