1095 lines
29 KiB
C++
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;
|
|
}
|
|
|
|
|
|
|