Click here to Skip to main content
Licence 
First Posted 2 Dec 1999
Views 113,699
Bookmarked 25 times

Getting the location of a printer device

By | 2 Dec 1999 | Article
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

About the Author

Dan Pilat



United States United States

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Questionhow do i obtain printer's name PinsussMihai Potcoava23:31 3 Oct '05  
AnswerRe: how do i obtain printer's name Pinmemberkezhu20:42 29 Nov '05  
AnswerRe: how do i obtain printer's name Pinmemberchris1758:18 3 Jul '06  
Generalmonitoring remote print queue in vc++ Pinmemberrayudu_kamma0:45 15 Jun '04  
Generalprinter sharer Pinmemberganesh30_v@yahoo.com22:12 29 Apr '04  
Generalquestion about CPrintDialog and DEVMODE Structure Pinmemberlavocat0:22 2 Dec '02  
GeneralRe: question about CPrintDialog and DEVMODE Structure Pinmemberxufeisjtu16:00 25 Sep '05  
GeneralRe: question about CPrintDialog and DEVMODE Structure PinmemberMember 1034204:32 27 Jan '09  
QuestionHow to Delete Pinter without restart computer PinsussAnonymous19:49 24 Nov '02  
AnswerRe: How to Delete Pinter without restart computer PinmemberBelal lehwany9:22 12 Dec '04  
QuestionHow do I monitor a network printer? PinmemberBudianto2:02 1 Sep '01  
AnswerRe: How do I monitor a network printer? PinmemberMerrion5:19 26 May '03  
QuestionRedirec Printout to EXE ? Pinmemberilker8:08 15 Jul '01  
AnswerRe: Redirec Printout to EXE ? PinmemberBelal lehwany9:28 12 Dec '04  
QuestionHow can I get the hDevNames Pinmembermecy22:09 24 Jun '01  
GeneralPostScript Printer Pinmembernavid_ahsan16:47 4 Dec '00  
Generalprinter status Pinsussharshal20:30 29 Aug '00  
GeneralRe: printer status PinmemberDak Lozar9:22 14 Nov '00  
GeneralRe: printer status PinmemberRohiniPS0:34 4 Jun '02  
GeneralRe: printer status PinmemberAnonymous3:46 6 Jun '02  
GeneralRe: printer status PinmemberMagnus Johansson22:03 7 May '01  
GeneralRe: printer status Pinmembercaffary9:33 25 Jan '02  
GeneralRe: printer status Pinmembergaurav sakhuja18:49 6 Mar '02  
GeneralRe: printer status Pinmemberblongtq23:00 1 Jul '02  
GeneralRe: printer status PinmemberBelal lehwany9:30 12 Dec '04  

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

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 3 Dec 1999
Article Copyright 1999 by Dan Pilat
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid