Click here to Skip to main content
15,891,184 members
Articles / Programming Languages / C++
Article

Getting the location of a printer device

Rate me:
Please Sign up or sign in to vote.
3.75/5 (9 votes)
2 Dec 1999 208.5K   28   25
Getting the location of a printer device.

Sample Image - print_location.jpg

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 structs - 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;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionhow do i obtain printer's name Pin
Mihai Potcoava3-Oct-05 23:31
Mihai Potcoava3-Oct-05 23:31 
AnswerRe: how do i obtain printer's name Pin
kezhu29-Nov-05 20:42
kezhu29-Nov-05 20:42 
I have the same problem. Have you found the solution? If yes, can you please let me know how to get the HANDLE of DEVNAMES.

From MSDN http://support.microsoft.com/kb/q166129/, it gives hDevNames but it uses GetPrinter etc.

Any advice would be appreciated.

Thanks.

Ke

AnswerRe: how do i obtain printer's name Pin
Christopher Stratmann3-Jul-06 8:18
Christopher Stratmann3-Jul-06 8:18 
Generalmonitoring remote print queue in vc++ Pin
rayudu_kamma15-Jun-04 0:45
rayudu_kamma15-Jun-04 0:45 
Generalprinter sharer Pin
Member 64441829-Apr-04 22:12
Member 64441829-Apr-04 22:12 
Generalquestion about CPrintDialog and DEVMODE Structure Pin
lavocat2-Dec-02 0:22
lavocat2-Dec-02 0:22 
GeneralRe: question about CPrintDialog and DEVMODE Structure Pin
xufeisjtu25-Sep-05 16:00
xufeisjtu25-Sep-05 16:00 
GeneralRe: question about CPrintDialog and DEVMODE Structure Pin
Member 10342027-Jan-09 4:32
Member 10342027-Jan-09 4:32 
QuestionHow to Delete Pinter without restart computer Pin
Anonymous24-Nov-02 19:49
Anonymous24-Nov-02 19:49 
AnswerRe: How to Delete Pinter without restart computer Pin
Belal lehwany12-Dec-04 9:22
Belal lehwany12-Dec-04 9:22 
QuestionHow do I monitor a network printer? Pin
1-Sep-01 2:02
suss1-Sep-01 2:02 
AnswerRe: How do I monitor a network printer? Pin
Duncan Edwards Jones26-May-03 5:19
professionalDuncan Edwards Jones26-May-03 5:19 
QuestionRedirec Printout to EXE ? Pin
15-Jul-01 8:08
suss15-Jul-01 8:08 
AnswerRe: Redirec Printout to EXE ? Pin
Belal lehwany12-Dec-04 9:28
Belal lehwany12-Dec-04 9:28 
QuestionHow can I get the hDevNames Pin
24-Jun-01 22:09
suss24-Jun-01 22:09 
GeneralPostScript Printer Pin
navid_ahsan4-Dec-00 16:47
navid_ahsan4-Dec-00 16:47 
Generalprinter status Pin
harshalvv29-Aug-00 20:30
harshalvv29-Aug-00 20:30 
GeneralRe: printer status Pin
14-Nov-00 9:22
suss14-Nov-00 9:22 
GeneralRe: printer status Pin
4-Jun-02 0:34
suss4-Jun-02 0:34 
GeneralRe: printer status Pin
6-Jun-02 3:46
suss6-Jun-02 3:46 
GeneralRe: printer status Pin
Magnus Johansson7-May-01 22:03
Magnus Johansson7-May-01 22:03 
GeneralRe: printer status Pin
caffary25-Jan-02 9:33
caffary25-Jan-02 9:33 
GeneralRe: printer status Pin
6-Mar-02 18:49
suss6-Mar-02 18:49 
GeneralRe: printer status Pin
blongtq1-Jul-02 23:00
blongtq1-Jul-02 23:00 
GeneralRe: printer status Pin
Belal lehwany12-Dec-04 9:30
Belal lehwany12-Dec-04 9:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.