admin
base
com
developer
drivers
ds
enduser
inetcore
inetsrv
loc
mergedcomponents
multimedia
net
printscan
ddk
dload
fax
faxsrv
inc
lib
print
drivers
embedded
spooler
dbglib
exts
idl
inc
inetpp2
inetsrv
localspl
monitors
oleprn
win95
winnt
addprint.cpp
addprint.h
addprint.rgs
asphelp.cpp
asphelp.h
asphelp.rgs
asptlb.h
cpinst.h
custom.cpp
dirs
dsprintq.cpp
dsprintq.h
dsprintq.rgs
olecvt.cpp
olecvt.h
olecvt.rgs
oleinst.cpp
oleinst.h
oleinst.rgs
oleinstall.htm
oleprn.clw
oleprn.cpp
oleprn.def
oleprn.dsp
oleprn.dsw
oleprn.idl
oleprn.rc
oleprnps.def
olesnmp.cpp
olesnmp.h
olesnmp.rgs
printer.cpp
printer.h
prnsec.cpp
prnsec.h
prturl.cpp
prturl.h
prturl.rgs
resource.h
sitem.h
slist.h
stdafx.cpp
stdafx.h
util.cpp
util.h
webpnp.ico
perflib
prtprocs
scripts
splexts
spllib
splsetup
spoolss
wpnpinst
dirs
makefil0
dirs
publish
scan
ui
wia
dirs
project.mk
public
published
sdktools
shell
termsrv
tools
windows
dirs
makefil0
884 lines
24 KiB
C++
884 lines
24 KiB
C++
// Printer.cpp: implementation of the CPrinter class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "Printer.h"
|
|
#include "wininet.h"
|
|
|
|
static const DWORD BIT_IGNORED_JOB = (JOB_STATUS_PAUSED |
|
|
JOB_STATUS_PRINTED |
|
|
JOB_STATUS_DELETING |
|
|
JOB_STATUS_OFFLINE |
|
|
JOB_STATUS_SPOOLING);
|
|
static const DWORD BIT_ERROR_JOB = (JOB_STATUS_ERROR | JOB_STATUS_PAPEROUT);
|
|
static const DWORD CHAR_PER_PAGE = 4800;
|
|
static const DWORD PAGEPERJOB = 1;
|
|
static const DWORD BYTEPERJOB = 2;
|
|
|
|
|
|
#ifdef WIN9X
|
|
#error This code requires DRIVER_INFO_6 which is not availabe under Win9X
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CPrinter::CPrinter():
|
|
m_hPrinter(NULL),
|
|
m_pInfo2(NULL),
|
|
m_pInfo4(NULL),
|
|
m_pDriverInfo6(NULL),
|
|
m_bCalcJobETA(NULL),
|
|
m_pszUrlBuffer(NULL),
|
|
m_pszOemUrl (NULL),
|
|
m_pszManufacturer (NULL)
|
|
{
|
|
}
|
|
|
|
CPrinter::~CPrinter()
|
|
{
|
|
if (m_pInfo2) {
|
|
LocalFree (m_pInfo2);
|
|
}
|
|
|
|
if (m_pInfo4) {
|
|
LocalFree (m_pInfo4);
|
|
}
|
|
|
|
if (m_pDriverInfo6) {
|
|
LocalFree (m_pDriverInfo6);
|
|
}
|
|
|
|
if (m_hPrinter) {
|
|
ClosePrinter (m_hPrinter);
|
|
}
|
|
|
|
if (m_pszUrlBuffer) {
|
|
LocalFree (m_pszUrlBuffer);
|
|
}
|
|
|
|
if (m_pszOemUrl) {
|
|
LocalFree (m_pszOemUrl);
|
|
}
|
|
|
|
if (m_pszManufacturer) {
|
|
LocalFree (m_pszManufacturer);
|
|
}
|
|
|
|
}
|
|
|
|
BOOL CPrinter::Open(LPTSTR pPrinterName, LPHANDLE phPrinter)
|
|
{
|
|
PRINTER_DEFAULTS pd = {NULL, NULL, PRINTER_ACCESS_USE};
|
|
|
|
if (m_hPrinter != NULL)
|
|
return FALSE;
|
|
|
|
if (! (OpenPrinter(pPrinterName, &m_hPrinter, &pd)))
|
|
return FALSE;
|
|
|
|
if (phPrinter) {
|
|
*phPrinter = m_hPrinter;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// This is a compiler safe way of checking that an unsigned integer is
|
|
// negative and returning zero if it is or the integer if it is not
|
|
// Note: Tval can be any size but must be unsigned
|
|
template<class T> inline T ZeroIfNegative(T Tval) {
|
|
if (Tval & (T(1) << (sizeof(Tval) * 8 - 1))) return 0;
|
|
else return Tval;
|
|
}
|
|
|
|
BOOL CPrinter::CalJobEta()
|
|
{
|
|
DWORD dwPrintRate = DWERROR;
|
|
PJOB_INFO_2 pJobInfo = NULL;
|
|
PJOB_INFO_2 pJob;
|
|
DWORD dwNumJobs;
|
|
DWORD dwNeeded = 0;
|
|
DWORD i;
|
|
float fFactor = 1;
|
|
float fTotal = 0;
|
|
DWORD dwNumJobsReqested;
|
|
BOOL bRet = FALSE;
|
|
const DWORD cdwLimit = 256;
|
|
|
|
if (! AllocGetPrinterInfo2())
|
|
return NULL;
|
|
|
|
if (m_pInfo2->cJobs > 0) {
|
|
|
|
if (m_pInfo2->cJobs > cdwLimit) {
|
|
fFactor = (float) m_pInfo2->cJobs / cdwLimit;
|
|
dwNumJobsReqested = cdwLimit;
|
|
}
|
|
else
|
|
dwNumJobsReqested = m_pInfo2->cJobs;
|
|
|
|
EnumJobs (m_hPrinter, 0, dwNumJobsReqested, 2,
|
|
NULL, 0, &dwNeeded, &dwNumJobs);
|
|
|
|
if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
|
|
(NULL == (pJobInfo = (PJOB_INFO_2)LocalAlloc(LPTR, dwNeeded))) ||
|
|
(!EnumJobs (m_hPrinter, 0, dwNumJobsReqested, 2, (LPBYTE) pJobInfo, dwNeeded,
|
|
&dwNeeded, &dwNumJobs))) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the average Job size
|
|
|
|
// Find out if we can use page as the unit
|
|
for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
|
|
if (pJob->Status & BIT_IGNORED_JOB)
|
|
continue;
|
|
|
|
if (pJob->Size > 0 && pJob->TotalPages == 0)
|
|
break;
|
|
}
|
|
|
|
m_dwPendingJobCount = 0;
|
|
|
|
if (i == dwNumJobs) {
|
|
// All the jobs have the page information. Use page as the unit
|
|
m_dwAvgJobSizeUnit = PAGEPERJOB;
|
|
|
|
for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
|
|
if (pJob->Status & BIT_IGNORED_JOB)
|
|
continue;
|
|
m_dwPendingJobCount++;
|
|
fTotal += pJob->TotalPages;
|
|
}
|
|
}
|
|
else {
|
|
// Use byte as the unit
|
|
m_dwAvgJobSizeUnit = BYTEPERJOB;
|
|
for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
|
|
if (pJob->Status & BIT_IGNORED_JOB)
|
|
continue;
|
|
m_dwPendingJobCount++;
|
|
fTotal += ZeroIfNegative(pJob->Size);
|
|
}
|
|
}
|
|
|
|
// Calculate the averate job size
|
|
if (m_dwPendingJobCount) {
|
|
m_dwAvgJobSize = DWORD ((fTotal) / (float) m_dwPendingJobCount);
|
|
dwPrintRate = GetPPM();
|
|
|
|
if (dwPrintRate != DWERROR)
|
|
m_dwJobCompletionMinute = (DWORD) (fFactor * GetWaitingMinutes (dwPrintRate, pJobInfo, dwNumJobs));
|
|
}
|
|
else {
|
|
m_dwAvgJobSize = 0;
|
|
m_dwJobCompletionMinute = 0;
|
|
}
|
|
|
|
m_dwPendingJobCount = (DWORD) (m_dwPendingJobCount * fFactor);
|
|
}
|
|
else {
|
|
m_dwPendingJobCount = 0;
|
|
m_dwAvgJobSize = 0;
|
|
m_dwJobCompletionMinute = 0;
|
|
m_dwAvgJobSizeUnit = PAGEPERJOB;
|
|
}
|
|
|
|
m_bCalcJobETA = TRUE;
|
|
|
|
// Set the last error to ERROR_INVALID_DATA if the printer rate is not available for the current printer
|
|
// or if the printer status is not suitable to display the summary information
|
|
//
|
|
|
|
if (dwPrintRate == DWERROR ||
|
|
m_pInfo2->Status & ( PRINTER_STATUS_PAUSED |
|
|
PRINTER_STATUS_ERROR |
|
|
PRINTER_STATUS_PENDING_DELETION |
|
|
PRINTER_STATUS_PAPER_JAM |
|
|
PRINTER_STATUS_PAPER_OUT |
|
|
PRINTER_STATUS_OFFLINE )) {
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
m_dwJobCompletionMinute = DWERROR;
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
if (pJobInfo)
|
|
LocalFree(pJobInfo);
|
|
return bRet;
|
|
|
|
}
|
|
|
|
DWORD CPrinter::GetWaitingMinutes(DWORD dwPPM, PJOB_INFO_2 pJobInfo, DWORD dwNumJob)
|
|
{
|
|
DWORD dwWaitingTime = 0;
|
|
DWORD dwTotalPages = 0;
|
|
|
|
if (dwNumJob == 0)
|
|
return 0;
|
|
|
|
if (dwPPM == 0)
|
|
return DWERROR;
|
|
|
|
for (DWORD i = 0; i < dwNumJob; i++, pJobInfo++) {
|
|
if (pJobInfo->Status & BIT_IGNORED_JOB)
|
|
continue;
|
|
if (pJobInfo->Status & BIT_ERROR_JOB)
|
|
return DWERROR;
|
|
|
|
if (pJobInfo->TotalPages > 0) {
|
|
dwTotalPages += pJobInfo->TotalPages;
|
|
}
|
|
else {
|
|
if (pJobInfo->Size) {
|
|
dwTotalPages += 1 + ZeroIfNegative(pJobInfo->Size) / CHAR_PER_PAGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwTotalPages)
|
|
dwWaitingTime = 1 + dwTotalPages / dwPPM;
|
|
|
|
return dwWaitingTime;
|
|
}
|
|
|
|
|
|
DWORD CPrinter::GetPPM()
|
|
{
|
|
DWORD dwPrintRate;
|
|
DWORD dwPrintRateUnit;
|
|
|
|
// Get PrintRate
|
|
dwPrintRate = MyDeviceCapabilities(m_pInfo2->pPrinterName,
|
|
NULL,
|
|
DC_PRINTRATE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (dwPrintRate == DWERROR ) {
|
|
return dwPrintRate;
|
|
}
|
|
|
|
dwPrintRateUnit = MyDeviceCapabilities(m_pInfo2->pPrinterName,
|
|
NULL,
|
|
DC_PRINTRATEUNIT,
|
|
NULL,
|
|
NULL);
|
|
|
|
switch (dwPrintRateUnit) {
|
|
case PRINTRATEUNIT_PPM: // PagesPerMinute
|
|
break;
|
|
case PRINTRATEUNIT_CPS: // CharactersPerSecond
|
|
dwPrintRate = CPS2PPM (dwPrintRate);
|
|
break;
|
|
case PRINTRATEUNIT_LPM: // LinesPerMinute
|
|
dwPrintRate = LPM2PPM (dwPrintRate);
|
|
break;
|
|
case PRINTRATEUNIT_IPM: // InchesPerMinute
|
|
dwPrintRate = DWERROR;
|
|
break;
|
|
default: // Unknown
|
|
dwPrintRate = DWERROR;
|
|
break;
|
|
}
|
|
|
|
return dwPrintRate ;
|
|
}
|
|
|
|
BOOL CPrinter::AllocGetPrinterInfo2()
|
|
{
|
|
|
|
DWORD dwNeeded = 0;
|
|
PPRINTER_INFO_2 pPrinterInfo = NULL;
|
|
LPTSTR pszTmp;
|
|
|
|
|
|
if (m_hPrinter == NULL) {
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
// Get a PRINTER_INFO_2 structure filled up
|
|
|
|
if (GetPrinter(m_hPrinter, 2, NULL, 0, &dwNeeded) ||
|
|
(GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
|
|
(NULL == (pPrinterInfo = (PPRINTER_INFO_2)LocalAlloc(LPTR, dwNeeded))) ||
|
|
(!GetPrinter(m_hPrinter, 2, (byte *)pPrinterInfo, dwNeeded, &dwNeeded))) {
|
|
|
|
if (pPrinterInfo)
|
|
LocalFree(pPrinterInfo);
|
|
|
|
if (! GetLastError())
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
// Mark the offline status if the attribute says offline
|
|
if (pPrinterInfo->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) {
|
|
pPrinterInfo->Status |= PRINTER_STATUS_OFFLINE;
|
|
}
|
|
|
|
// Extract the first port for the case of pooled printing. i.e. we don't support pooled printing.
|
|
if ( pPrinterInfo->pPortName) {
|
|
if( pszTmp = _tcschr( pPrinterInfo->pPortName, TEXT(',')))
|
|
*pszTmp = TEXT('\0');
|
|
}
|
|
|
|
if (m_pInfo2) {
|
|
LocalFree (m_pInfo2);
|
|
}
|
|
|
|
m_pInfo2 = pPrinterInfo;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CPrinter::AllocGetPrinterInfo4()
|
|
{
|
|
|
|
DWORD dwNeeded = 0;
|
|
PPRINTER_INFO_4 pPrinterInfo = NULL;
|
|
|
|
if (m_hPrinter == NULL) {
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
// Get a PRINTER_INFO_4 structure filled up
|
|
|
|
if (GetPrinter(m_hPrinter, 4, NULL, 0, &dwNeeded) ||
|
|
(GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
|
|
(NULL == (pPrinterInfo = (PPRINTER_INFO_4)LocalAlloc(LPTR, dwNeeded))) ||
|
|
(!GetPrinter(m_hPrinter, 4, (byte *)pPrinterInfo, dwNeeded, &dwNeeded))) {
|
|
|
|
if (pPrinterInfo)
|
|
LocalFree(pPrinterInfo);
|
|
|
|
if (! (GetLastError()))
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_pInfo4) {
|
|
LocalFree (m_pInfo4);
|
|
}
|
|
m_pInfo4 = pPrinterInfo;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CPrinter::AllocGetDriverInfo6()
|
|
{
|
|
|
|
DWORD dwNeeded = 0;
|
|
PDRIVER_INFO_6 pDriverInfo = NULL;
|
|
|
|
if (m_hPrinter == NULL) {
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
// Get a DRIVER_INFO_6 structure filled up
|
|
|
|
if (GetPrinterDriver(m_hPrinter, NULL, 6, NULL, 0, &dwNeeded) ||
|
|
(GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
|
|
(NULL == (pDriverInfo = (PDRIVER_INFO_6)LocalAlloc(LPTR, dwNeeded))) ||
|
|
(!GetPrinterDriver(m_hPrinter, NULL, 6, (LPBYTE)pDriverInfo, dwNeeded, &dwNeeded))) {
|
|
|
|
if (pDriverInfo)
|
|
LocalFree(pDriverInfo);
|
|
|
|
if (! (GetLastError()))
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_pDriverInfo6) {
|
|
LocalFree (m_pDriverInfo6);
|
|
}
|
|
m_pDriverInfo6 = pDriverInfo;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PPRINTER_INFO_2 CPrinter::GetPrinterInfo2()
|
|
{
|
|
if (m_pInfo2 == NULL) {
|
|
if (! AllocGetPrinterInfo2())
|
|
return NULL;
|
|
}
|
|
|
|
return m_pInfo2;
|
|
}
|
|
|
|
PDRIVER_INFO_6 CPrinter::GetDriverInfo6()
|
|
{
|
|
if (m_pDriverInfo6 == NULL) {
|
|
if (! AllocGetDriverInfo6()) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return m_pDriverInfo6;
|
|
}
|
|
|
|
|
|
DWORD CPrinter::GetWaitingTime()
|
|
{
|
|
if (!m_bCalcJobETA) {
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
return m_dwJobCompletionMinute;
|
|
}
|
|
|
|
BOOL CPrinter::GetJobEtaData (DWORD & dwWaitingTime, DWORD &dwJobCount, DWORD &dwJobSize, DWORD &dwJob)
|
|
{
|
|
if (!m_bCalcJobETA) {
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
dwJobCount = m_dwPendingJobCount;
|
|
dwJobSize = m_dwAvgJobSize;
|
|
dwWaitingTime = m_dwJobCompletionMinute;
|
|
dwJob = m_dwAvgJobSizeUnit;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LPTSTR CPrinter::GetPrinterWebUrl(void)
|
|
{
|
|
static const TCHAR c_szHttp[] = TEXT("http://");
|
|
static const TCHAR c_szHttps[] = TEXT("https://");
|
|
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
DWORD dwLen = 0;
|
|
TCHAR szBuffer[MAX_COMPUTERNAME_LENGTH+1];
|
|
DWORD dwBufferSize;
|
|
DWORD dwAttributes;
|
|
LPCTSTR pszServerName;
|
|
LPTSTR pszShareName;
|
|
LPTSTR pszSplServerName;
|
|
LPTSTR pszSplPrinterName;
|
|
LPTSTR pszSplShareName;
|
|
|
|
//
|
|
// Get printer info 4 to fetch the attribute.
|
|
//
|
|
bReturn = AllocGetPrinterInfo4();
|
|
|
|
if (!bReturn) {
|
|
|
|
if (GetLastError () == ERROR_INVALID_LEVEL ) {
|
|
//
|
|
// Most likely it is a remote printers folder, no support for level4, so
|
|
// we have to use level 2 instead.
|
|
//
|
|
if (! AllocGetPrinterInfo2())
|
|
goto Cleanup;
|
|
}
|
|
else {
|
|
//
|
|
// The call fails with other reasons
|
|
//
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
else{
|
|
|
|
if (m_pInfo4->Attributes & PRINTER_ATTRIBUTE_LOCAL) {
|
|
// Check if the local flag is on. If so, try to get printer info2 for more information
|
|
if (! AllocGetPrinterInfo2())
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Assume failure
|
|
//
|
|
bReturn = FALSE;
|
|
|
|
|
|
if (m_pInfo2) {
|
|
dwAttributes = m_pInfo2->Attributes;
|
|
pszSplServerName = m_pInfo2->pServerName;
|
|
pszSplPrinterName = m_pInfo2->pPrinterName;
|
|
pszSplShareName = m_pInfo2->pShareName;
|
|
}
|
|
else
|
|
{
|
|
dwAttributes = m_pInfo4->Attributes;
|
|
pszSplServerName = m_pInfo4->pServerName;
|
|
pszSplPrinterName = m_pInfo4->pPrinterName;
|
|
pszSplShareName = NULL;
|
|
}
|
|
|
|
//
|
|
// Check if it is a printer connected to an http port
|
|
// then the port name is the url.
|
|
//
|
|
if( m_pInfo2 )
|
|
{
|
|
|
|
if( m_pInfo2->pPortName )
|
|
{
|
|
//
|
|
// Compare the port name prefex to see if it is an HTTP port.
|
|
//
|
|
if( !_tcsnicmp( m_pInfo2->pPortName, c_szHttp, _tcslen( c_szHttp ) ) ||
|
|
!_tcsnicmp( m_pInfo2->pPortName, c_szHttps, _tcslen( c_szHttps ) ) )
|
|
{
|
|
//
|
|
// We always use portname as the URL
|
|
//
|
|
dwLen = 1 + lstrlen( m_pInfo2->pPortName );
|
|
|
|
if (! (m_pszUrlBuffer = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
lstrcpy( m_pszUrlBuffer, m_pInfo2->pPortName );
|
|
|
|
bReturn = TRUE;
|
|
goto Cleanup;
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If it is an unshared printer, return false
|
|
//
|
|
if ( !(dwAttributes & PRINTER_ATTRIBUTE_SHARED) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if it is a connection or a local printer or a masq printer
|
|
// which is not connected over http, then build the url
|
|
// from the \\server name\share name.
|
|
//
|
|
if( !pszSplServerName )
|
|
{
|
|
dwBufferSize = COUNTOF( szBuffer );
|
|
|
|
if( !GetComputerName( szBuffer, &dwBufferSize ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
pszServerName = szBuffer;
|
|
}
|
|
//
|
|
// Server name was provided then set our pointer to just
|
|
// after the two leading wacks.
|
|
//
|
|
else
|
|
{
|
|
if( pszSplServerName[0] == TEXT('\\') &&
|
|
pszSplServerName[1] == TEXT('\\') )
|
|
{
|
|
pszServerName = pszSplServerName + 2;
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ( !IsWebServerInstalled(pszSplServerName) ) {
|
|
|
|
dwLastError = ERROR_NO_BROWSER_SERVERS_FOUND;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Build the URL - http://server/printers/ipp_0004.asp?printer=ShareName
|
|
//
|
|
if (pszSplShareName)
|
|
{
|
|
pszShareName = pszSplShareName;
|
|
}
|
|
else {
|
|
//
|
|
// Parse the sharename/printername from the printer name
|
|
//
|
|
if(pszSplPrinterName) {
|
|
if (pszSplPrinterName[0] == TEXT ('\\') && pszSplPrinterName[1] == TEXT ('\\') )
|
|
{
|
|
pszShareName = _tcschr (pszSplPrinterName + 2, TEXT ('\\'));
|
|
pszShareName++;
|
|
}
|
|
else
|
|
pszShareName = pszSplPrinterName;
|
|
}
|
|
else
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
GetWebUIUrl (pszServerName, pszShareName, NULL, &dwLen);
|
|
|
|
if (GetLastError () != ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (! (m_pszUrlBuffer = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!GetWebUIUrl (pszServerName, pszShareName, m_pszUrlBuffer, &dwLen))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Indicate success.
|
|
//
|
|
bReturn = TRUE;
|
|
|
|
//
|
|
// Clean any opened or allocated resources.
|
|
//
|
|
Cleanup:
|
|
|
|
|
|
//
|
|
// If this routine failed then set the last error.
|
|
//
|
|
if( !bReturn )
|
|
{
|
|
//
|
|
// If the last error was not set then a called routine may
|
|
// have set the last error. We don't want to clear the
|
|
// last error.
|
|
//
|
|
if( dwLastError != ERROR_SUCCESS )
|
|
{
|
|
SetLastError( dwLastError );
|
|
}
|
|
}
|
|
return m_pszUrlBuffer;
|
|
}
|
|
|
|
BOOL CPrinter::GetDriverData(
|
|
DriverData dwDriverData,
|
|
LPTSTR &pszData)
|
|
{
|
|
static const ULONG_PTR ulpOffset[LastDriverData] = {
|
|
// This has the offsets into the DRIVER_INFO_6 structure.....
|
|
ULOFFSET( PDRIVER_INFO_6, pszOEMUrl ) ,
|
|
ULOFFSET( PDRIVER_INFO_6, pszHardwareID ) ,
|
|
ULOFFSET( PDRIVER_INFO_6, pszMfgName)
|
|
};
|
|
|
|
LPTSTR pszDataString = NULL;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwSize;
|
|
|
|
ASSERT( (int)dwDriverData >= 0 && (int)dwDriverData < LastDriverData );
|
|
|
|
if (! GetDriverInfo6() )
|
|
goto Cleanup;
|
|
|
|
pszDataString = *(LPTSTR *)(((ULONG_PTR) m_pDriverInfo6) + ulpOffset[dwDriverData] );
|
|
|
|
if (pszDataString == NULL || *pszDataString == NULL)
|
|
goto Cleanup;
|
|
|
|
dwSize = sizeof(TCHAR) * (lstrlen( pszDataString ) + 1);
|
|
|
|
if (! (pszData = (LPTSTR)LocalAlloc(LPTR, dwSize)))
|
|
goto Cleanup;
|
|
|
|
lstrcpy( pszData, pszDataString);
|
|
|
|
bRet = TRUE;
|
|
Cleanup:
|
|
return bRet;
|
|
}
|
|
|
|
BOOL CPrinter::ParseUrlPattern(
|
|
LPTSTR pSrc,
|
|
LPTSTR pDest,
|
|
DWORD &dwDestLen)
|
|
{
|
|
const dwMaxMacroLen = 255;
|
|
enum {
|
|
NORMALTEXT, STARTMACRO
|
|
} URL_PATTERN_STATE;
|
|
|
|
|
|
BOOL bRet = FALSE;
|
|
DWORD dwLen = 0;
|
|
DWORD dwMacroLen = 0;
|
|
DWORD dwAvailbleSize;
|
|
DWORD dwState = NORMALTEXT;
|
|
int i;
|
|
TCHAR ch;
|
|
TCHAR szMacroName [dwMaxMacroLen + 1];
|
|
LPTSTR pMacroValue = NULL;
|
|
|
|
LPTSTR pszMacroList[] = {
|
|
TEXT ("MODEL"),
|
|
TEXT ("HARDWAREID"),
|
|
};
|
|
|
|
|
|
while (ch = *pSrc++) {
|
|
switch (dwState) {
|
|
case NORMALTEXT:
|
|
if (ch == TEXT ('%')) {
|
|
// Start a macro
|
|
dwState = STARTMACRO;
|
|
dwMacroLen = 0;
|
|
szMacroName[0] = 0;
|
|
}
|
|
else {
|
|
if (dwLen >= dwDestLen) {
|
|
dwLen ++;
|
|
}
|
|
else {
|
|
pDest[dwLen++] = ch;
|
|
}
|
|
}
|
|
|
|
break;
|
|
case STARTMACRO:
|
|
if (ch == TEXT ('%')) {
|
|
szMacroName[dwMacroLen] = 0;
|
|
// Replace Macro
|
|
for (int i = 0; i < sizeof (pszMacroList) / sizeof (pszMacroList[0]); i++) {
|
|
if (!lstrcmpi (szMacroName, pszMacroList[i])) {
|
|
|
|
pMacroValue = 0;
|
|
switch (i) {
|
|
case 0:
|
|
AssignString (pMacroValue, m_pInfo2->pDriverName);
|
|
break;
|
|
case 1:
|
|
GetDriverData (HardwareID , pMacroValue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pMacroValue) {
|
|
|
|
if (dwDestLen > dwLen)
|
|
dwAvailbleSize = dwDestLen - dwLen;
|
|
else
|
|
dwAvailbleSize = 0;
|
|
|
|
TCHAR szPlaceHolder[1];
|
|
DWORD dwBufSize = sizeof (szPlaceHolder) / sizeof (TCHAR);
|
|
if (!InternetCanonicalizeUrl (pMacroValue, szPlaceHolder, &dwBufSize, 0)) {
|
|
if (dwBufSize < dwAvailbleSize ) {
|
|
if (!InternetCanonicalizeUrl (pMacroValue, pDest + dwLen, &dwBufSize, 0)) {
|
|
LocalFree (pMacroValue);
|
|
return bRet;
|
|
}
|
|
else {
|
|
dwLen = lstrlen (pDest);
|
|
}
|
|
}
|
|
else {
|
|
dwLen += dwBufSize;
|
|
}
|
|
}
|
|
LocalFree (pMacroValue);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwState = NORMALTEXT;
|
|
}
|
|
else {
|
|
if (dwMacroLen < dwMaxMacroLen) {
|
|
szMacroName[dwMacroLen ++] = ch;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwState == STARTMACRO) {
|
|
SetLastError ( ERROR_INVALID_DATA );
|
|
}
|
|
else {
|
|
if (dwLen >= dwDestLen) {
|
|
SetLastError (ERROR_INSUFFICIENT_BUFFER);
|
|
dwDestLen = dwLen + 1;
|
|
}
|
|
else {
|
|
pDest[dwLen] = 0;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
LPTSTR CPrinter::GetOemUrl(
|
|
LPTSTR & pszManufacturer)
|
|
{
|
|
LPTSTR pszOemUrlPattern = NULL;
|
|
DWORD dwLen = 0;
|
|
LPTSTR pszUrl = NULL;
|
|
|
|
if (!GetPrinterInfo2 () )
|
|
goto Cleanup;
|
|
|
|
if (GetDriverData (OEMUrlPattern, pszOemUrlPattern)) {
|
|
|
|
if (! ParseUrlPattern (pszOemUrlPattern, NULL, dwLen)
|
|
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
m_pszOemUrl = (LPTSTR) LocalAlloc (LPTR, sizeof (TCHAR) * dwLen);
|
|
if (m_pszOemUrl) {
|
|
|
|
if (!ParseUrlPattern (pszOemUrlPattern, m_pszOemUrl, dwLen))
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
if (GetDriverData (Manufacturer, m_pszManufacturer)) {
|
|
pszManufacturer = m_pszManufacturer;
|
|
pszUrl = m_pszOemUrl;
|
|
}
|
|
|
|
Cleanup:
|
|
if (pszOemUrlPattern) {
|
|
LocalFree ( pszOemUrlPattern);
|
|
}
|
|
|
|
return pszUrl;
|
|
}
|
|
|