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
:
class GPrinter
{
public:
GPrinter();
BOOL Open(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS *lpDefaults=NULL);
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);
void SetSilent(BOOL bSilent=TRUE);
operator HANDLE() const {return m_hPrinter;}
protected:
BOOL Get(int nLevel, LPBYTE lpBuf, int nBufSize);
HANDLE m_hPrinter;
LPBYTE m_lpGetInfoBuf;
BOOL m_bSilent;
public:
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:
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)
{
AfxMessageBox(prnInfo.pLocation);
}
}
::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:
Collapse
BOOL ReportLastError()
{
LPVOID lpMsgBuf = NULL;
BOOL bFormat = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
if(bFormat && lpMsgBuf)
{
AfxMessageBox((LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
}
return bFormat;
}
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)
{
ASSERT(!m_hPrinter);
BOOL bOpen = ::OpenPrinter((char *)lpszPrinterName,
&m_hPrinter, lpDefaults);
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);
else
if(!m_bSilent)
ReportLastError();
return bGet;
}