/*
* lpr for cygwin/windows
*
* Copyright (C) 2000-2003 Rick Rankin
* http://www.cygwin.com/ml/cygwin/2000-07/msg00320.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* See the COPYING file for full license information.
*/
#include "src/lpr/Printer.hh"
#include "src/lpr/Win32Utils.hh"
using namespace std;
inline LPTSTR tstr(const string & str)
{
return const_cast(str.c_str());
}
Printer::Printer(const string &name, bool debugFlag) throw(PrinterException)
: m_devName(name),
m_debugFlag(debugFlag),
m_devHandle(INVALID_HANDLE_VALUE),
m_devMode(0),
m_buffer(0),
m_bufferSize(4096),
m_bufferIndex(0),
m_rawFlag(false)
{
m_buffer = new unsigned char[m_bufferSize];
mapPortName();
open();
// Initialize the DEVMODE structure
// Get the amount of space needed for the buffer.
DWORD needed = DocumentProperties(NULL, m_devHandle, tstr(m_devName),
NULL, NULL, 0);
m_devMode = reinterpret_cast(new unsigned char[needed]);
// Get the default DEVMODE for the printer.
DWORD ret = DocumentProperties(NULL, m_devHandle, tstr(m_devName),
m_devMode, NULL, DM_OUT_BUFFER);
if (ret != IDOK)
throw PrinterException("error getting the default device mode: " +
Win32Utils::getErrorMessage());
// Close the printer, because we'll need to reopen it later, passing it
// the DEVMODE structure with any optional changes by the user.
close();
}
Printer::~Printer()
{
close();
if (m_buffer != 0)
delete [] m_buffer;
if (m_devMode != 0)
delete m_devMode;
}
void Printer::close()
{
if (m_devHandle != INVALID_HANDLE_VALUE)
{
ClosePrinter(m_devHandle);
m_devHandle = INVALID_HANDLE_VALUE;
}
}
void Printer::endDoc() throw(PrinterException)
{
if (!EndDocPrinter(m_devHandle))
throw PrinterException("EndDocPrinter error: " +
Win32Utils::getErrorMessage());
}
void Printer::endPage() throw(PrinterException)
{
cout << "Printer::endPage()" << endl;
if (!EndPagePrinter(m_devHandle))
throw PrinterException("EndPagePrinter error: " +
Win32Utils::getErrorMessage());
}
void Printer::flush(void) throw(PrinterException)
{
if (m_bufferIndex > 0)
{
write(m_buffer, m_bufferIndex);
m_bufferIndex = 0;
}
}
bool Printer::getRawFlag() const
{
return m_rawFlag;
}
void Printer::print(istream & in, const string & docName) throw(PrinterException)
{
startDoc(docName);
char ch;
char lastCh = '\0';
while (in.get(ch))
{
if (!m_rawFlag && ch == '\n' && lastCh != '\r')
put('\r');
put(ch);
lastCh = ch;
}
flush();
endDoc();
}
void Printer::put(unsigned char ch) throw(PrinterException)
{
if (m_bufferIndex == m_bufferSize)
flush();
m_buffer[m_bufferIndex++] = ch;
}
void Printer::setRawFlag(bool flag)
{
m_rawFlag = flag;
}
void Printer::startDoc(const string & docName) throw(PrinterException)
{
DOC_INFO_1 di1;
CHAR raw[] = "RAW";
open();
di1.pDocName = tstr(docName);
di1.pOutputFile = 0;
di1.pDatatype = raw;
if (StartDocPrinter(m_devHandle, 1, (LPBYTE) &di1) == 0)
throw PrinterException("StartDocPrinter error: " +
Win32Utils::getErrorMessage());
}
void Printer::startPage() throw(PrinterException)
{
cout << "Printer::startPage()" << endl;
if (!StartPagePrinter(m_devHandle))
throw PrinterException("StartPagePrinter error: " +
Win32Utils::getErrorMessage());
}
void Printer::write(unsigned char *buf, unsigned int size) throw(PrinterException)
{
DWORD written;
if (!WritePrinter(m_devHandle, buf, size, &written))
throw PrinterException("error writing to device '" + m_devName + "': " +
Win32Utils::getErrorMessage());
}
//***************************************************************************
//
// Private operations
//
//***************************************************************************
Printer::PrinterList Printer::enumPrinters(DWORD flags, LPTSTR name) throw(PrinterException)
{
DWORD numPrinters;
DWORD bytesNeeded;
EnumPrinters(flags, name, 5, 0, 0, &bytesNeeded, &numPrinters);
auto_ptr enumBuffer(new BYTE[bytesNeeded]);
if (!EnumPrinters(flags, name, 5, enumBuffer.get(), bytesNeeded,
&bytesNeeded, &numPrinters))
throw PrinterException("unable to enumerate printers: " +
Win32Utils::getErrorMessage());
PRINTER_INFO_5 *pi = reinterpret_cast(enumBuffer.get());
PrinterList list;
for (unsigned int ii = 0; ii < numPrinters; ++ii)
{
if (m_debugFlag)
cerr << "Printer name: '" << pi->pPrinterName << "', "
<< "Port name: '" << pi->pPortName << "'" << endl;
list.push_back(*pi++);
}
return list;
}
void Printer::mapPortName() throw(PrinterException)
{
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
bool isWindows9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
(osvi.dwMajorVersion > 4 ||
(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion > 0)));
bool isWindows2K_NT4 = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
osvi.dwMajorVersion >= 4);
if (m_debugFlag)
cout << "isWindows9x = " << isWindows9x << ", "
<< "isWindows2K_NT4 = " << isWindows2K_NT4 << endl;
if (isWindows9x)
{
TCHAR empty[] = "";
PrinterList list = enumPrinters(PRINTER_ENUM_NAME, empty);
for (PrinterList::iterator it = list.begin(); it != list.end(); ++it)
{
if (strcasecmp(m_devName.c_str(), it->pPortName) == 0)
{
if (m_debugFlag)
cout << "Mapped '" << m_devName << "' to '" << it->pPrinterName
<< "'" << endl;
m_devName = it->pPrinterName;
return;
}
}
}
else if (isWindows2K_NT4)
{
PrinterList list = enumPrinters(PRINTER_ENUM_LOCAL, 0);
for (PrinterList::iterator it = list.begin(); it != list.end(); ++it)
{
if (strcasecmp(m_devName.c_str(), it->pPortName) == 0)
{
if (m_debugFlag)
cout << "Mapped '" << m_devName << "' to '" << it->pPrinterName
<< "'" << endl;
m_devName = it->pPrinterName;
return;
}
}
list = enumPrinters(PRINTER_ENUM_CONNECTIONS, 0);
for (PrinterList::iterator it = list.begin(); it != list.end(); ++it)
{
if (strcasecmp(m_devName.c_str(), it->pPortName) == 0)
{
if (m_debugFlag)
cout << "Mapped '" << m_devName << "' to '" << it->pPrinterName
<< "'" << endl;
m_devName = it->pPrinterName;
return;
}
}
}
}
void Printer::open() throw(PrinterException)
{
PRINTER_DEFAULTS prDef;
CHAR raw[] = "RAW";
prDef.pDatatype = raw;
prDef.pDevMode = m_devMode;
prDef.DesiredAccess = PRINTER_ACCESS_USE;
if (m_devHandle == INVALID_HANDLE_VALUE &&
!OpenPrinter(tstr(m_devName), &m_devHandle, &prDef))
throw PrinterException("can't open '" + m_devName + "' for writing: " +
Win32Utils::getErrorMessage());
}