Getting the location of a printer device






3.75/5 (9 votes)
Dec 3, 1999

213118
Getting the location of a printer device.
Introduction
If you want to get the location ('Printer room, second floor') of a printer device, you won't find it in the DEVMODE
or DEVNAMES
structure - you must use the Windows printer API. To make it easier to get, I've wrapped the printer API in a class called GPrinter
:
/////////////////////////////////////////////////////////////////////////// // wrapper class for the printer API... class GPrinter { public: GPrinter(); // open a printer with the name 'lpszPrinterName' BOOL Open(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS *lpDefaults=NULL); // get various types of printer info // pInfo is good for the lifetime of the class, // or until the next call to Get(), // whichever comes first BOOL Get(PRINTER_INFO_1 *pInfo); BOOL Get(PRINTER_INFO_2 *pInfo); BOOL Get(PRINTER_INFO_3 *pInfo); BOOL Get(PRINTER_INFO_4 *pInfo); BOOL Get(PRINTER_INFO_5 *pInfo); BOOL Get(PRINTER_INFO_7 *pInfo); // set to TRUE to turn off message box reporting of errors void SetSilent(BOOL bSilent=TRUE); // handy operator to return printer object handle operator HANDLE() const {return m_hPrinter;} protected: BOOL Get(int nLevel, LPBYTE lpBuf, int nBufSize); HANDLE m_hPrinter; // handle to the printer object LPBYTE m_lpGetInfoBuf; // temporary buffer BOOL m_bSilent; // silent mode flag public: // closes the open printer object void Close(); virtual ~GPrinter(); };
In order to use this class, you must first get the name of the printer from the DEVNAMES
structure. In the image above, the name would be 'HP LaserJet 5P'. Use that name to call the GPrinter::Open()
function. From there, you can use any of the API wrapper functions. Currently, it wraps only one function, ::GetPrinter()
, with a series of overloaded Get()
functions, each taking a specific type of PRINTER_INFO_*
struct
. There is some information overlap between the seven different types of struct
s - I use PRINTER_INFO_2
to get the printer location:
// Given a DEVNAMES handle, this function will display the device location void DisplayLocation(HANDLE hDevNames) { LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(hDevNames); LPCTSTR lpszDevice = (LPCTSTR)lpDev + lpDev->wDriverOffset; GPrinter prn; prn.SetSilent(); if(prn.Open(lpszDevice)) { PRINTER_INFO_2 prnInfo; if(prn.Get(&prnInfo) && prnInfo.pLocation) { // display the location AfxMessageBox(prnInfo.pLocation); } // you can call Close() here, but the destructor will do that for you } ::GlobalUnlock(hDevNames); }
Use the GPrinter::SetSilent()
function to turn off the display of error messages. There are more printer API functions which can be added to this class that I never got around to wrapping - feel free to add them. Here is the implementation for this class:
/////////////////////////////////////////////////////////////////////////// // first define helper function to display error messages BOOL ReportLastError() { LPVOID lpMsgBuf = NULL; BOOL bFormat = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL); if(bFormat && lpMsgBuf) { AfxMessageBox((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); } return bFormat; } /////////////////////////////////////////////////////////////////////////// // GPrinter Implementation GPrinter::GPrinter() { m_hPrinter = NULL; m_lpGetInfoBuf = NULL; m_bSilent = FALSE; } GPrinter::~GPrinter() { Close(); } void GPrinter::SetSilent(BOOL bSilent) { m_bSilent = bSilent; } BOOL GPrinter::Open(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS *lpDefaults) { // it should be closed! ASSERT(!m_hPrinter); BOOL bOpen = ::OpenPrinter((char *)lpszPrinterName, &m_hPrinter, lpDefaults); // i18nOk if(!bOpen && !m_bSilent) ReportLastError(); return bOpen; } void GPrinter::Close() { if(m_hPrinter) { ::ClosePrinter(m_hPrinter); m_hPrinter = NULL; } if(m_lpGetInfoBuf) { ::GlobalFree(m_lpGetInfoBuf); m_lpGetInfoBuf = NULL; } } BOOL GPrinter::Get(PRINTER_INFO_1 *pInfo) { return Get(1, (LPBYTE)pInfo, sizeof(*pInfo)); } BOOL GPrinter::Get(PRINTER_INFO_2 *pInfo) { return Get(2, (LPBYTE)pInfo, sizeof(*pInfo)); } BOOL GPrinter::Get(PRINTER_INFO_3 *pInfo) { return Get(3, (LPBYTE)pInfo, sizeof(*pInfo)); } BOOL GPrinter::Get(PRINTER_INFO_4 *pInfo) { return Get(4, (LPBYTE)pInfo, sizeof(*pInfo)); } BOOL GPrinter::Get(PRINTER_INFO_5 *pInfo) { return Get(5, (LPBYTE)pInfo, sizeof(*pInfo)); } BOOL GPrinter::Get(PRINTER_INFO_7 *pInfo) { return Get(7, (LPBYTE)pInfo, sizeof(*pInfo)); } BOOL GPrinter::Get(int nLevel, LPBYTE lpBuf, int nBufSize) { if(m_lpGetInfoBuf) { ::GlobalFree(m_lpGetInfoBuf); m_lpGetInfoBuf = NULL; } DWORD dwBytesReturned; DWORD dwBytesNeeded; ::GetPrinter(m_hPrinter, nLevel, NULL, 0, &dwBytesNeeded); m_lpGetInfoBuf = (LPBYTE)GlobalAlloc(GPTR, dwBytesNeeded); BOOL bGet = ::GetPrinter(m_hPrinter, nLevel, m_lpGetInfoBuf, dwBytesNeeded, &dwBytesReturned); if(bGet) memcpy(lpBuf, m_lpGetInfoBuf, nBufSize); // i18nOk else if(!m_bSilent) ReportLastError(); return bGet; }