windows-nt/Source/XPSP1/NT/printscan/print/spooler/spoolss/client/pubprn.cxx
2020-09-26 16:20:57 +08:00

1095 lines
29 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Abstract:
This module provides functionality for publishing printers
Author:
Steve Wilson (NT) November 1997
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "pubprn.hxx"
#include "varconv.hxx"
#include "property.hxx"
#include "dsutil.hxx"
#include "client.h"
#define PPM_FACTOR 48
BOOL
PublishPrinterW(
HWND hwnd,
PCWSTR pszUNCName,
PCWSTR pszDN,
PCWSTR pszCN,
PWSTR *ppszDN,
DWORD dwAction
)
{
PRINTER_DEFAULTS Defaults;
HANDLE hPrinter = NULL;
HANDLE hServer = NULL;
PWSTR pszServerName = NULL;
PWSTR pszPrinterName = NULL;
PPRINTER_INFO_2 pInfo2 = NULL;
DWORD dwRet = ERROR_SUCCESS;
DWORD dwType;
DWORD dwMajorVersion;
DWORD dwDsPresent;
DWORD cbNeeded;
DWORD dwLength;
HRESULT hr;
WCHAR szDNSMachineName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
WCHAR szFullUNCName[MAX_UNC_PRINTER_NAME];
WCHAR szShortServerName[MAX_PATH+1];
PWSTR pszFullUNCName;
PWSTR pszShortServerName;
PWSTR pszFullServerName;
if (InCSRProcess()) {
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
hr = CoInitialize(NULL);
if (hr != S_OK && hr != S_FALSE) {
SetLastError((DWORD)((HRESULT_FACILITY(hr) == FACILITY_WIN32) ? HRESULT_CODE(hr) : hr));
return FALSE;
}
if (ppszDN)
*ppszDN = NULL;
// Get server name
if (dwRet = UNC2Server(pszUNCName, &pszServerName))
goto error;
if(!OpenPrinter(pszServerName, &hServer, NULL)) {
dwMajorVersion = 0;
} else {
dwRet = GetPrinterData( hServer,
SPLREG_MAJOR_VERSION,
&dwType,
(PBYTE) &dwMajorVersion,
sizeof dwMajorVersion,
&cbNeeded);
if (dwRet != ERROR_SUCCESS) {
dwMajorVersion = 0;
dwRet = ERROR_SUCCESS; // ignore errors and assume lowest version
}
if (dwMajorVersion >= WIN2000_SPOOLER_VERSION) {
hr = MachineIsInMyForest(pszServerName);
if (FAILED(hr)) {
dwRet = HRESULT_CODE(hr);
goto error;
} else if(HRESULT_CODE(hr) == 1) {
// Machine is in my forest and is NT5+
dwRet = ERROR_INVALID_LEVEL;
goto error;
} else {
// Downgrade the version for NT5+ printers published in a non-DS domain
dwMajorVersion = WIN2000_SPOOLER_VERSION;
}
}
}
Defaults.pDatatype = NULL;
Defaults.pDevMode = NULL;
Defaults.DesiredAccess = PRINTER_ACCESS_USE;
if (!OpenPrinter((PWSTR) pszUNCName, &hPrinter, &Defaults)) {
dwRet = GetLastError();
goto error;
}
hr = GetPrinterInfo2(hPrinter, &pInfo2);
if (FAILED(hr)) {
dwRet = HRESULT_CODE(hr);
goto error;
}
if (dwRet = UNC2Printer(pInfo2->pPrinterName, &pszPrinterName))
goto error;
if( dwMajorVersion >= WIN2000_SPOOLER_VERSION){
if(dwRet = GetPrinterData( hServer,
SPLREG_DNS_MACHINE_NAME,
&dwType,
(PBYTE) szDNSMachineName,
(INTERNET_MAX_HOST_NAME_LENGTH + 1) * sizeof(WCHAR),
&cbNeeded) != ERROR_SUCCESS ) {
goto error;
}
wsprintf( szFullUNCName, L"\\\\%s\\%s", szDNSMachineName, pszPrinterName );
dwLength = MAX_PATH + 1;
if (!DnsHostnameToComputerName(pszServerName,
szShortServerName,
&dwLength)) {
dwRet = GetLastError();
goto error;
}
pszFullUNCName = szFullUNCName;
pszFullServerName = szDNSMachineName;
pszShortServerName = szShortServerName+2;
} else {
pszFullUNCName = (PWSTR)pszUNCName;
pszFullServerName = pszServerName+2;
pszShortServerName = pszServerName+2;
}
// Verify PrintQueue doesn't already exist
if (dwAction != PUBLISHPRINTER_IGNORE_DUPLICATES) {
if(dwRet = PrintQueueExists(hwnd, hPrinter, pszFullUNCName, dwAction, (PWSTR) pszDN, (PWSTR *) ppszDN))
goto error;
}
if (dwRet = PublishDownlevelPrinter(hPrinter,
(PWSTR) pszDN,
(PWSTR) pszCN,
pszFullServerName,
pszShortServerName,
pszFullUNCName,
pszPrinterName,
dwMajorVersion,
ppszDN))
goto error;
error:
if (hPrinter != NULL)
ClosePrinter(hPrinter);
if (hServer != NULL)
ClosePrinter(hServer);
if (pszServerName)
FreeSplMem(pszServerName);
if (pszPrinterName)
FreeSplMem(pszPrinterName);
FreeSplMem(pInfo2);
if (dwRet != ERROR_SUCCESS) {
SetLastError(dwRet);
return FALSE;
}
CoUninitialize();
return TRUE;
}
DWORD
PublishNT5Printer(
HANDLE hPrinter,
PWSTR pszDN,
PWSTR pszCN,
PWSTR *ppszObjectDN
)
{
PRINTER_INFO_7 Info7;
DWORD dwRet = ERROR_SUCCESS;
BYTE Data[(100 + sizeof(PRINTER_INFO_7))*sizeof(WCHAR)]; // GUIDs don't have well-defined size
PPRINTER_INFO_7 pInfo7 = NULL;
DWORD cbNeeded;
// Disable NT5+ publishing because it is inconsistent with SetPrinter.
// Also, NT5 duplicate printer must be deleted via SetPrinter, not via DS. If it is
// deleted via DS then subsequent SetPrinter to publish will take a long time since
// it discovers GUID no longer exists and spins background thread to delete & republish.
// This, combined with replication delays, causes PublishNT5Printer to fail because getting
// the ppszObjectDN because the object may not be published yet.
return ERROR_INVALID_LEVEL;
Info7.dwAction = DSPRINT_PUBLISH;
if (!SetPrinter(hPrinter, 7, (PBYTE) &Info7, 0)) {
dwRet = GetLastError();
goto error;
}
if (!GetPrinter(hPrinter, 7, (PBYTE) Data, sizeof(Data), &cbNeeded)) {
if ((dwRet = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
goto error;
if (!(pInfo7 = (PPRINTER_INFO_7) AllocSplMem(cbNeeded)))
goto error;
if (!GetPrinter(hPrinter, 7, (PBYTE) pInfo7, cbNeeded, &cbNeeded)) {
dwRet = GetLastError();
goto error;
}
} else {
pInfo7 = (PPRINTER_INFO_7) Data;
}
if (!(dwRet = MovePrintQueue(pInfo7->pszObjectGUID, pszDN, pszCN)))
goto error;
if (dwRet = GetADsPathFromGUID(pInfo7->pszObjectGUID, ppszObjectDN))
goto error;
error:
if (pInfo7 && pInfo7 != (PPRINTER_INFO_7) Data)
FreeSplMem(pInfo7);
if (dwRet != ERROR_SUCCESS) {
FreeGlobalStr(*ppszObjectDN);
}
return dwRet;
}
DWORD
PublishDownlevelPrinter(
HANDLE hPrinter,
PWSTR pszDN,
PWSTR pszCN,
PWSTR pszServerName,
PWSTR pszShortServerName,
PWSTR pszUNCName,
PWSTR pszPrinterName,
DWORD dwVersion,
PWSTR *ppszObjectDN
)
{
HRESULT hr = S_OK;
DWORD dwRet = ERROR_SUCCESS;
IADs *pPrintQueue = NULL;
IADsContainer *pADsContainer = NULL;
IDispatch *pDispatch = NULL;
PWSTR pszCommonName = pszCN;
BSTR bstrADsPath = NULL;
PWSTR pszDNWithDC = NULL;
if (ppszObjectDN)
*ppszObjectDN = NULL;
// If pszCN is not supplied, generate default common name
if (!pszCommonName || !*pszCommonName) {
dwRet = GetCommonName(hPrinter, &pszCommonName);
if (dwRet != ERROR_SUCCESS) {
hr = dw2hr(dwRet);
BAIL_ON_FAILURE(hr);
}
}
// Stick DC in DN
if (!(pszDNWithDC = GetDNWithServer(pszDN))) {
pszDNWithDC = pszDN;
}
// Get container
hr = ADsGetObject(pszDNWithDC, IID_IADsContainer, (void **) &pADsContainer);
BAIL_ON_FAILURE(hr);
// Create printqueue
hr = pADsContainer->Create(SPLDS_PRINTER_CLASS, pszCommonName, &pDispatch);
BAIL_ON_FAILURE(hr);
hr = pDispatch->QueryInterface(IID_IADs, (void **) &pPrintQueue);
BAIL_ON_FAILURE(hr);
// Set properties
hr = SetProperties( hPrinter,
pszServerName,
pszShortServerName,
pszUNCName,
pszPrinterName,
dwVersion,
pPrintQueue);
BAIL_ON_FAILURE(hr);
// Get ADsPath to printQueue
if (ppszObjectDN) {
hr = pPrintQueue->get_ADsPath(&bstrADsPath);
BAIL_ON_FAILURE(hr);
if (!(*ppszObjectDN = AllocGlobalStr(bstrADsPath))) {
dwRet = GetLastError();
hr = dw2hr(dwRet);
BAIL_ON_FAILURE(hr);
}
}
error:
if (pszDNWithDC != pszDN)
FreeSplMem(pszDNWithDC);
if (bstrADsPath)
SysFreeString(bstrADsPath);
if (pszCommonName != pszCN)
FreeSplMem(pszCommonName);
if (pADsContainer)
pADsContainer->Release();
if (pDispatch)
pDispatch->Release();
if (pPrintQueue)
pPrintQueue->Release();
if (FAILED(hr) && ppszObjectDN && *ppszObjectDN)
FreeGlobalStr(*ppszObjectDN);
return hr2dw(hr);
}
HRESULT
SetProperties(
HANDLE hPrinter,
PWSTR pszServerName,
PWSTR pszShortServerName,
PWSTR pszUNCName,
PWSTR pszPrinterName,
DWORD dwVersion,
IADs *pPrintQueue
)
{
HRESULT hr;
hr = SetMandatoryProperties(pszServerName,
pszShortServerName,
pszUNCName,
pszPrinterName,
dwVersion,
pPrintQueue);
BAIL_ON_FAILURE(hr);
SetSpoolerProperties(hPrinter, pPrintQueue, dwVersion);
SetDriverProperties(hPrinter, pPrintQueue);
error:
return hr;
}
HRESULT
SetMandatoryProperties(
PWSTR pszServerName,
PWSTR pszShortServerName,
PWSTR pszUNCName,
PWSTR pszPrinterName,
DWORD dwVersion,
IADs *pPrintQueue
)
{
HRESULT hr;
// ServerName
hr = put_BSTR_Property(pPrintQueue, SPLDS_SERVER_NAME, pszServerName);
BAIL_ON_FAILURE(hr);
// ShortServerName
hr = put_BSTR_Property(pPrintQueue, SPLDS_SHORT_SERVER_NAME, pszShortServerName);
BAIL_ON_FAILURE(hr);
// UNC Name
hr = put_BSTR_Property(pPrintQueue, SPLDS_UNC_NAME, pszUNCName);
BAIL_ON_FAILURE(hr);
// PrinterName
hr = put_BSTR_Property(pPrintQueue, SPLDS_PRINTER_NAME, pszPrinterName);
BAIL_ON_FAILURE(hr);
// versionNumber
hr = put_DWORD_Property(pPrintQueue, SPLDS_VERSION_NUMBER, &dwVersion);
BAIL_ON_FAILURE(hr);
hr = pPrintQueue->SetInfo();
if (FAILED(hr))
pPrintQueue->GetInfo();
error:
return hr;
}
HRESULT
SetSpoolerProperties(
HANDLE hPrinter,
IADs *pPrintQueue,
DWORD dwVersion
)
{
HRESULT hr = S_OK;
PPRINTER_INFO_2 pInfo2 = NULL;
DWORD cbNeeded;
BYTE Byte;
PWSTR psz;
// Get PRINTER_INFO_2 properties
if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, 0, &cbNeeded)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
hr = dw2hr(GetLastError());
goto error;
}
if (!(pInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded))) {
hr = dw2hr(GetLastError());
goto error;
}
if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, cbNeeded, &cbNeeded)) {
hr = dw2hr(GetLastError());
goto error;
}
}
// Description
hr = PublishDsData( pPrintQueue,
SPLDS_DESCRIPTION,
REG_SZ,
(PBYTE) pInfo2->pComment);
// Driver-Name
hr = PublishDsData( pPrintQueue,
SPLDS_DRIVER_NAME,
REG_SZ,
(PBYTE) pInfo2->pDriverName);
// Location
hr = PublishDsData( pPrintQueue,
SPLDS_LOCATION,
REG_SZ,
(PBYTE) pInfo2->pLocation);
// portName (Port1,Port2,Port3)
if (pInfo2->pPortName) {
PWSTR pszPortName;
// copy comma delimited strings to Multi-sz format
pszPortName = DelimString2MultiSz(pInfo2->pPortName, L',');
if (pszPortName) {
hr = PublishDsData( pPrintQueue,
SPLDS_PORT_NAME,
REG_MULTI_SZ,
(PBYTE) pszPortName);
FreeSplMem(pszPortName);
}
}
// startTime
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_START_TIME,
REG_DWORD,
(PBYTE) &pInfo2->StartTime);
// endTime
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_END_TIME,
REG_DWORD,
(PBYTE) &pInfo2->UntilTime);
// keepPrintedJobs
Byte = pInfo2->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS ? 1 : 0;
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_KEEP_PRINTED_JOBS,
REG_BINARY,
(PBYTE) &Byte );
// printSeparatorFile
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_SEPARATOR_FILE,
REG_SZ,
(PBYTE) pInfo2->pSepFile);
// printShareName
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_SHARE_NAME,
REG_SZ,
(PBYTE) pInfo2->pShareName);
// printSpooling
if (pInfo2->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
psz = L"PrintDirect";
} else if (pInfo2->Attributes & PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST) {
psz = L"PrintAfterSpooled";
} else {
psz = L"PrintWhileSpooling";
}
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_SPOOLING,
REG_SZ,
(PBYTE) psz);
// priority
hr = PublishDsData( pPrintQueue,
SPLDS_PRIORITY,
REG_DWORD,
(PBYTE) &pInfo2->Priority);
//
// Non-Info2 properties
// URL - downlevel machines don't support http printers, so don't publish useless url
//
if (dwVersion >= WIN2000_SPOOLER_VERSION) {
DWORD dwRet, dwType;
PWSTR pszUrl = NULL;
//
// Get the url from the print server
//
dwRet = GetPrinterDataEx( hPrinter,
SPLDS_SPOOLER_KEY,
SPLDS_URL,
&dwType,
(PBYTE) pszUrl,
0,
&cbNeeded);
if (dwRet == ERROR_MORE_DATA) {
if ((pszUrl = (PWSTR) AllocSplMem(cbNeeded))) {
dwRet = GetPrinterDataEx( hPrinter,
SPLDS_SPOOLER_KEY,
SPLDS_URL,
&dwType,
(PBYTE) pszUrl,
cbNeeded,
&cbNeeded);
if (dwRet == ERROR_SUCCESS && dwType == REG_SZ) {
hr = PublishDsData( pPrintQueue,
SPLDS_URL,
REG_SZ,
(PBYTE) pszUrl);
}
FreeSplMem(pszUrl);
}
}
}
error:
FreeSplMem(pInfo2);
return hr;
}
HRESULT
SetDriverProperties(
HANDLE hPrinter,
IADs *pPrintQueue
)
{
DWORD i, cbBytes, dwCount;
LPWSTR pStr;
DWORD dwResult;
LPWSTR pOutput = NULL, pTemp = NULL, pTemp1 = NULL;
DWORD cOutputBytes, cTempBytes;
POINTS point;
WCHAR pBuf[100];
BOOL bInSplSem = TRUE;
DWORD dwTemp, dwPrintRate, dwPrintRateUnit, dwPrintPPM;
HRESULT hr = S_OK;
PPRINTER_INFO_2 pInfo2 = NULL;
PWSTR pszUNCName;
// Get UNCName
hr = GetPrinterInfo2(hPrinter, &pInfo2);
BAIL_ON_FAILURE(hr);
if (!pInfo2) {
hr = dw2hr(GetLastError());
goto error;
}
pszUNCName = pInfo2->pPrinterName;
// *** DeviceCapability properties ***
pOutput = (PWSTR) AllocSplMem(cOutputBytes = 200);
if (!pOutput) {
hr = dw2hr(GetLastError());
goto error;
}
pTemp = (PWSTR) AllocSplMem(cTempBytes = 200);
if (!pTemp) {
hr = dw2hr(GetLastError());
goto error;
}
// printBinNames
DevCapMultiSz( pszUNCName,
pPrintQueue,
DC_BINNAMES,
24,
SPLDS_PRINT_BIN_NAMES);
// printCollate (awaiting DC_COLLATE)
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_COLLATE,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_COLLATE,
REG_BINARY,
(PBYTE) &dwResult);
}
// printColor
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_COLORDEVICE,
NULL,
NULL);
if (dwResult == GDI_ERROR) {
// Try alternative method
dwResult = ThisIsAColorPrinter(pszUNCName);
}
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_COLOR,
REG_BINARY,
(PBYTE) &dwResult);
// printDuplexSupported
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_DUPLEX,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_DUPLEX_SUPPORTED,
REG_BINARY,
(PBYTE) &dwResult);
}
// printStaplingSupported
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_STAPLE,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_STAPLING_SUPPORTED,
REG_BINARY,
(PBYTE) &dwResult);
}
// printMaxXExtent & printMaxYExtent
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_MAXEXTENT,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
*((DWORD *) &point) = dwResult;
dwTemp = (DWORD) point.x;
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_MAX_X_EXTENT,
REG_DWORD,
(PBYTE) &dwTemp);
dwTemp = (DWORD) point.y;
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_MAX_Y_EXTENT,
REG_DWORD,
(PBYTE) &dwTemp);
}
// printMinXExtent & printMinYExtent
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_MINEXTENT,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
*((DWORD *) &point) = dwResult;
dwTemp = (DWORD) point.x;
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_MIN_X_EXTENT,
REG_DWORD,
(PBYTE) &dwTemp);
dwTemp = (DWORD) point.y;
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_MIN_Y_EXTENT,
REG_DWORD,
(PBYTE) &dwTemp);
}
// printMediaSupported
DevCapMultiSz( pszUNCName,
pPrintQueue,
DC_PAPERNAMES,
64,
SPLDS_PRINT_MEDIA_SUPPORTED);
// printMediaReady
DevCapMultiSz( pszUNCName,
pPrintQueue,
DC_MEDIAREADY,
64,
SPLDS_PRINT_MEDIA_READY);
// printNumberUp
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_NUP,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
// DS NUp is boolean
dwResult = !!dwResult;
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_DUPLEX_SUPPORTED,
REG_DWORD,
(PBYTE) &dwResult);
}
// printMemory
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_PRINTERMEM,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_MEMORY,
REG_DWORD,
(PBYTE) &dwResult);
}
// printOrientationsSupported
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_ORIENTATION,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
if (dwResult == 90 || dwResult == 270) {
wcscpy(pBuf, L"PORTRAIT");
wcscpy(pStr = pBuf + wcslen(pBuf) + 1, L"LANDSCAPE");
}
else {
wcscpy(pStr = pBuf, L"PORTRAIT");
}
pStr += wcslen(pStr) + 1;
*pStr++ = L'\0';
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_ORIENTATIONS_SUPPORTED,
REG_MULTI_SZ,
(PBYTE) pBuf);
}
// printMaxResolutionSupported
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_ENUMRESOLUTIONS,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
if (cOutputBytes < dwResult*2*sizeof(DWORD)) {
if(!(pTemp1 = (PWSTR) ReallocSplMem(pOutput, 0, cOutputBytes = dwResult*2*sizeof(DWORD))))
goto error;
pOutput = pTemp1;
}
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_ENUMRESOLUTIONS,
pOutput,
NULL);
if (dwResult == GDI_ERROR)
goto error;
// Find the maximum resolution: we have dwResult*2 resolutions to check
for(i = dwTemp = 0 ; i < dwResult*2 ; ++i) {
if (((DWORD *) pOutput)[i] > dwTemp)
dwTemp = ((DWORD *) pOutput)[i];
}
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED,
REG_DWORD,
(PBYTE) &dwTemp);
}
// printLanguage
DevCapMultiSz( pszUNCName,
pPrintQueue,
DC_PERSONALITY,
32,
SPLDS_PRINT_LANGUAGE);
// printRate
// NOTE: If PrintRate is 0, no value is published
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_PRINTRATE,
NULL,
NULL);
dwPrintRate = dwResult ? dwResult : GDI_ERROR;
if (dwPrintRate != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_RATE,
REG_DWORD,
(PBYTE) &dwPrintRate);
}
// printRateUnit
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_PRINTRATEUNIT,
NULL,
NULL);
dwPrintRateUnit = dwResult;
if (dwPrintRateUnit != GDI_ERROR) {
switch (dwPrintRateUnit) {
case PRINTRATEUNIT_PPM:
pStr = L"PagesPerMinute";
break;
case PRINTRATEUNIT_CPS:
pStr = L"CharactersPerSecond";
break;
case PRINTRATEUNIT_LPM:
pStr = L"LinesPerMinute";
break;
case PRINTRATEUNIT_IPM:
pStr = L"InchesPerMinute";
break;
default:
pStr = L"";
break;
}
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_RATE_UNIT,
REG_SZ,
(PBYTE) pStr);
}
// printPagesPerMinute
// DevCap returns 0 if there is no entry in GPD
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_PRINTRATEPPM,
NULL,
NULL);
if (dwResult == GDI_ERROR)
dwResult = 0;
dwPrintPPM = dwResult;
// If dwPrintPPM == 0, then calculate PPM from PrintRate
if (dwPrintPPM == 0) {
if (dwPrintRate == GDI_ERROR) {
dwPrintPPM = GDI_ERROR;
} else {
switch (dwPrintRateUnit) {
case PRINTRATEUNIT_PPM:
dwPrintPPM = dwPrintRate;
break;
case PRINTRATEUNIT_CPS:
case PRINTRATEUNIT_LPM:
dwPrintPPM = dwPrintRate/PPM_FACTOR;
if (dwPrintPPM == 0)
dwPrintPPM = 1; // min PPM is 1
break;
default:
dwPrintPPM = GDI_ERROR;
break;
}
}
}
if (dwPrintPPM != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_PRINT_PAGES_PER_MINUTE,
REG_DWORD,
(PBYTE) &dwPrintPPM);
}
// printDriverVersion
dwResult = DeviceCapabilities( pszUNCName,
NULL,
DC_VERSION,
NULL,
NULL);
if (dwResult != GDI_ERROR) {
hr = PublishDsData( pPrintQueue,
SPLDS_DRIVER_VERSION,
REG_DWORD,
(PBYTE) &dwResult);
}
error:
FreeSplMem(pInfo2);
if (pOutput)
FreeSplMem(pOutput);
if (pTemp)
FreeSplMem(pTemp);
return hr;
}
HRESULT
PublishDsData(
IADs *pADs,
PWSTR pValue,
DWORD dwType,
PBYTE pData
)
{
HRESULT hr;
BOOL bCreated = FALSE;
switch (dwType) {
case REG_SZ:
hr = put_BSTR_Property(pADs, pValue, (LPWSTR) pData);
break;
case REG_MULTI_SZ:
hr = put_MULTISZ_Property(pADs, pValue, (LPWSTR) pData);
break;
case REG_DWORD:
hr = put_DWORD_Property(pADs, pValue, (DWORD *) pData);
break;
case REG_BINARY:
hr = put_BOOL_Property(pADs, pValue, (BOOL *) pData);
break;
default:
hr = dw2hr(ERROR_INVALID_PARAMETER);
}
BAIL_ON_FAILURE(hr);
hr = pADs->SetInfo();
if (FAILED(hr))
pADs->GetInfo();
error:
return hr;
}