Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Getting the location of a printer device

0.00/5 (No votes)
2 Dec 1999 1  
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