You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1485 lines
38 KiB
1485 lines
38 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
winspool.c
|
|
|
|
Abstract:
|
|
|
|
This module provides all the public exported APIs relating to Printer
|
|
and Job management for the Print Providor Routing layer
|
|
|
|
Author:
|
|
|
|
Dave Snipp (DaveSn) 15-Mar-1991
|
|
|
|
[Notes:]
|
|
|
|
optional-notes
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "local.h"
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
LPPROVIDOR pLocalProvidor;
|
|
MODULE_DEBUG_INIT( DBG_ERROR, DBG_ERROR );
|
|
|
|
LPWSTR szRegistryProvidors = L"System\\CurrentControlSet\\Control\\Print\\Providers";
|
|
LPWSTR szPrintKey = L"System\\CurrentControlSet\\Control\\Print";
|
|
LPWSTR szLocalSplDll = L"localspl.dll";
|
|
LPWSTR szOrder = L"Order";
|
|
LPWSTR szEnvironment = LOCAL_ENVIRONMENT;
|
|
|
|
|
|
//
|
|
// Strings for handling the AddPrinterDrivers policy
|
|
//
|
|
LPWSTR szLanManProvider = L"LanMan Print Services";
|
|
LPWSTR szAPDRelPath = L"LanMan Print Services\\Servers";
|
|
LPWSTR szAPDValueName = L"AddPrinterDrivers";
|
|
|
|
BOOL
|
|
AddPrinterDriverW(
|
|
LPWSTR pName,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpAddPrinterDriver) (pName, Level, pDriverInfo)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if (GetLastError() != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
AddPrinterDriverExW(
|
|
LPWSTR pName,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo,
|
|
DWORD dwFileCopyFlags
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpAddPrinterDriverEx) (pName,
|
|
Level,
|
|
pDriverInfo,
|
|
dwFileCopyFlags)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if (GetLastError() != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
AddDriverCatalog(
|
|
HANDLE hPrinter,
|
|
DWORD dwLevel,
|
|
VOID *pvDriverInfCatInfo,
|
|
DWORD dwCatalogCopyFlags
|
|
)
|
|
{
|
|
HRESULT hRetval = E_FAIL;
|
|
LPPRINTHANDLE pPrintHandle = (LPPRINTHANDLE)hPrinter;
|
|
|
|
hRetval = pPrintHandle && (PRINTHANDLE_SIGNATURE == pPrintHandle->signature) ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
hRetval = (*pPrintHandle->pProvidor->PrintProvidor.fpAddDriverCatalog) (pPrintHandle->hPrinter,
|
|
dwLevel, pvDriverInfCatInfo, dwCatalogCopyFlags);
|
|
}
|
|
|
|
if (FAILED(hRetval))
|
|
{
|
|
SetLastError(HRESULT_CODE(hRetval));
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
BOOL
|
|
EnumPrinterDriversW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pDrivers,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
PROVIDOR *pProvidor;
|
|
|
|
if ((pDrivers == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if (!(*pProvidor->PrintProvidor.fpEnumPrinterDrivers) (pName, pEnvironment, Level,
|
|
pDrivers, cbBuf,
|
|
pcbNeeded, pcReturned)) {
|
|
|
|
if (GetLastError() != ERROR_INVALID_NAME)
|
|
return FALSE;
|
|
|
|
} else
|
|
|
|
return TRUE;
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
GetPrinterDriverDirectoryW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
DWORD Error;
|
|
|
|
if ((pDriverInfo == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpGetPrinterDriverDirectory)
|
|
(pName, pEnvironment, Level, pDriverInfo,
|
|
cbBuf, pcbNeeded)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if ((Error=GetLastError()) != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
DeletePrinterDriverW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
LPWSTR pDriverName
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
DWORD Error;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpDeletePrinterDriver)
|
|
(pName, pEnvironment, pDriverName)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if ((Error=GetLastError()) != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
DeletePrinterDriverExW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
LPWSTR pDriverName,
|
|
DWORD dwDeleteFlag,
|
|
DWORD dwVersionNum
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
while (pProvidor) {
|
|
if ((*pProvidor->PrintProvidor.fpDeletePrinterDriverEx)
|
|
(pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionNum)) {
|
|
return TRUE;
|
|
}
|
|
if (GetLastError() != ERROR_INVALID_NAME) {
|
|
return FALSE;
|
|
}
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
AddPrintProcessorW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
LPWSTR pPathName,
|
|
LPWSTR pPrintProcessorName
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpAddPrintProcessor) (pName, pEnvironment,
|
|
pPathName,
|
|
pPrintProcessorName)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if (GetLastError() != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
EnumPrintProcessorsW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pPrintProcessors,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
|
|
if ((pPrintProcessors == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if (!(*pProvidor->PrintProvidor.fpEnumPrintProcessors) (pName, pEnvironment, Level,
|
|
pPrintProcessors, cbBuf,
|
|
pcbNeeded, pcReturned)) {
|
|
|
|
if (GetLastError() != ERROR_INVALID_NAME)
|
|
return FALSE;
|
|
|
|
} else
|
|
|
|
return TRUE;
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
GetPrintProcessorDirectoryW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pPrintProcessorInfo,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
DWORD Error;
|
|
|
|
if ((pPrintProcessorInfo == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpGetPrintProcessorDirectory)
|
|
(pName, pEnvironment, Level,
|
|
pPrintProcessorInfo,
|
|
cbBuf, pcbNeeded)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if ((Error=GetLastError()) != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
EnumPrintProcessorDatatypesW(
|
|
LPWSTR pName,
|
|
LPWSTR pPrintProcessorName,
|
|
DWORD Level,
|
|
LPBYTE pDatatypes,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
|
|
if ((pDatatypes == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if (!(*pProvidor->PrintProvidor.fpEnumPrintProcessorDatatypes)
|
|
(pName, pPrintProcessorName,
|
|
Level, pDatatypes, cbBuf,
|
|
pcbNeeded, pcReturned)) {
|
|
|
|
if (GetLastError() != ERROR_INVALID_NAME)
|
|
return FALSE;
|
|
|
|
} else
|
|
|
|
return TRUE;
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AddFormW(
|
|
HANDLE hPrinter,
|
|
DWORD Level,
|
|
LPBYTE pForm
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpAddForm) (pPrintHandle->hPrinter,
|
|
Level, pForm);
|
|
}
|
|
|
|
BOOL
|
|
DeleteFormW(
|
|
HANDLE hPrinter,
|
|
LPWSTR pFormName
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpDeleteForm) (pPrintHandle->hPrinter,
|
|
pFormName);
|
|
}
|
|
|
|
BOOL
|
|
GetFormW(
|
|
HANDLE hPrinter,
|
|
LPWSTR pFormName,
|
|
DWORD Level,
|
|
LPBYTE pForm,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pForm == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpGetForm) (pPrintHandle->hPrinter,
|
|
pFormName, Level, pForm,
|
|
cbBuf, pcbNeeded);
|
|
}
|
|
|
|
BOOL
|
|
SetFormW(
|
|
HANDLE hPrinter,
|
|
LPWSTR pFormName,
|
|
DWORD Level,
|
|
LPBYTE pForm
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpSetForm) (pPrintHandle->hPrinter,
|
|
pFormName, Level, pForm);
|
|
}
|
|
|
|
BOOL
|
|
EnumFormsW(
|
|
HANDLE hPrinter,
|
|
DWORD Level,
|
|
LPBYTE pForm,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pForm == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpEnumForms) (pPrintHandle->hPrinter,
|
|
Level, pForm, cbBuf,
|
|
pcbNeeded, pcReturned);
|
|
}
|
|
|
|
|
|
BOOL
|
|
DeletePrintProcessorW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
LPWSTR pPrintProcessorName
|
|
)
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
DWORD Error;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
pProvidor = pLocalProvidor;
|
|
|
|
while (pProvidor) {
|
|
|
|
if ((*pProvidor->PrintProvidor.fpDeletePrintProcessor)
|
|
(pName, pEnvironment, pPrintProcessorName)) {
|
|
|
|
return TRUE;
|
|
|
|
} else if ((Error=GetLastError()) != ERROR_INVALID_NAME) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pProvidor = pProvidor->pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LPPROVIDOR FindProvidor(
|
|
HKEY hProvidors,
|
|
LPWSTR pName
|
|
)
|
|
|
|
/*++
|
|
Function Description: Retrieves providor struct for a providor name.
|
|
|
|
Parameters: hProvidors - handle to the Providors key
|
|
pName - name of the providor
|
|
|
|
Return Values: pProvidor if one is found; NULL otherwise
|
|
--*/
|
|
|
|
{
|
|
LPPROVIDOR pProvidor;
|
|
WCHAR szDllName[MAX_PATH];
|
|
DWORD dwError;
|
|
DWORD cbDllName;
|
|
HKEY hProvidor = NULL;
|
|
|
|
szDllName[0] = L'\0';
|
|
cbDllName = COUNTOF(szDllName);
|
|
|
|
// Search the registry for the DLL Name to compare with lpName
|
|
if ((dwError = RegOpenKeyEx(hProvidors, pName, 0, KEY_READ, &hProvidor)) ||
|
|
|
|
(dwError = RegQueryValueEx(hProvidor, L"Name", NULL, NULL,
|
|
(LPBYTE)szDllName, &cbDllName)))
|
|
{
|
|
SetLastError(dwError);
|
|
if (hProvidor)
|
|
{
|
|
RegCloseKey(hProvidor);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
RegCloseKey(hProvidor);
|
|
|
|
// Loop thru the list of providors for the name of the dll
|
|
for (pProvidor = pLocalProvidor;
|
|
pProvidor;
|
|
pProvidor = pProvidor->pNext)
|
|
{
|
|
if (!_wcsicmp(pProvidor->lpName, szDllName))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return pProvidor;
|
|
}
|
|
|
|
// Struct to maintain the new order of the providors
|
|
typedef struct _ProvidorList {
|
|
struct _ProvidorList *pNext;
|
|
LPPROVIDOR pProvidor;
|
|
} ProvidorList;
|
|
|
|
BOOL AddNodeToProvidorList(
|
|
LPPROVIDOR pProvidor,
|
|
ProvidorList **pStart
|
|
)
|
|
|
|
/*++
|
|
Function Description: Adds a node to the list of providors. Avoids duplicate entries in
|
|
the list
|
|
|
|
Parameters: pProvidor - providor to be added
|
|
pStart - pointer to the pointer to the start of the list
|
|
|
|
Return Values: TRUE if successful; FALSE otherwise
|
|
--*/
|
|
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
ProvidorList **pTemp, *pNew;
|
|
|
|
// No providor found
|
|
if (!pProvidor) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
for (pTemp = pStart; *pTemp; pTemp = &((*pTemp)->pNext))
|
|
{
|
|
if ((*pTemp)->pProvidor == pProvidor)
|
|
{
|
|
// Duplicates in the order string is an error
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
// Add new node
|
|
if (pNew = AllocSplMem(sizeof(ProvidorList)))
|
|
{
|
|
pNew->pNext = NULL;
|
|
pNew->pProvidor = pProvidor;
|
|
*pTemp = pNew;
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL UpdateProvidorOrder(
|
|
HKEY hProvidors,
|
|
LPWSTR pOrder
|
|
)
|
|
|
|
/*++
|
|
Function Description: Updates the order of the providors in spooler and the registry.
|
|
|
|
Parameters: hProvidors - handle to Providors registry key
|
|
pOrder - multisz order of providors
|
|
|
|
Return Values: TRUE if successful; FALSE otherwise
|
|
--*/
|
|
|
|
{
|
|
BOOL bReturn = FALSE, bRegChange = FALSE;
|
|
DWORD dwError, dwRequired, dwBytes, dwOldCount, dwNewCount;
|
|
LPWSTR pOldOrder = NULL, pStr;
|
|
LPPROVIDOR pProvidor;
|
|
|
|
// Maintain a list of the new order, so that error recovery is quick
|
|
ProvidorList *pStart = NULL, *pTemp;
|
|
|
|
// Loop thru the providor names in the new order
|
|
for (pStr = pOrder, dwBytes = 0;
|
|
pStr && *pStr;
|
|
pStr += (wcslen(pStr) + 1))
|
|
{
|
|
pProvidor = FindProvidor(hProvidors, pStr);
|
|
|
|
if (!AddNodeToProvidorList(pProvidor, &pStart)) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
dwBytes += (wcslen(pStr) + 1) * sizeof(WCHAR);
|
|
}
|
|
// Add the sizeof the last NULL char
|
|
dwBytes += sizeof(WCHAR);
|
|
|
|
// Make sure that all the providors are present in the list
|
|
for (dwOldCount = 0, pProvidor = pLocalProvidor;
|
|
pProvidor;
|
|
++dwOldCount, pProvidor = pProvidor->pNext) ;
|
|
|
|
// Add 1 for the local providor which does not appear on the list
|
|
for (dwNewCount = 1, pTemp = pStart;
|
|
pTemp;
|
|
++dwNewCount, pTemp = pTemp->pNext) ;
|
|
|
|
if (dwNewCount == dwOldCount) {
|
|
|
|
// Update the registry
|
|
if (dwError = RegSetValueEx(hProvidors, szOrder, 0,
|
|
REG_MULTI_SZ, (LPBYTE)pOrder, dwBytes))
|
|
{
|
|
SetLastError(dwError);
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Change the order in the spooler structure
|
|
for (pTemp = pStart, pProvidor = pLocalProvidor;
|
|
pTemp;
|
|
pTemp = pTemp->pNext, pProvidor = pProvidor->pNext)
|
|
{
|
|
pProvidor->pNext = pTemp->pProvidor;
|
|
}
|
|
|
|
pProvidor->pNext = NULL;
|
|
|
|
bReturn = TRUE;
|
|
|
|
} else {
|
|
|
|
// All the providors are not listed in the order
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
CleanUp:
|
|
// Free the temp list
|
|
while (pTemp = pStart) {
|
|
pStart = pTemp->pNext;
|
|
FreeSplMem(pTemp);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL AddNewProvidor(
|
|
HKEY hProvidors,
|
|
PPROVIDOR_INFO_1W pProvidorInfo
|
|
)
|
|
|
|
/*++
|
|
Function Description: This function updates the registry with the new providor info and the
|
|
new providor order. The new providor is appended to the current order.
|
|
This order can be changed by calling AddPrintProvidor with
|
|
Providor_info_2. The providor is immediately used for routing.
|
|
|
|
Parameters: hProvidors - providors registry key
|
|
pProvidorInfo - ProvidorInfo1 struct
|
|
|
|
Return Values: TRUE if successful; FALSE otherwise
|
|
--*/
|
|
|
|
{
|
|
BOOL bReturn = FALSE, bOrderUpdated = FALSE, bPresent = FALSE;
|
|
DWORD dwError, dwRequired, dwReturned, dwOldSize, dwDisposition = 0;
|
|
DWORD cchProvidorNameLen = MAX_PATH+COUNTOF(szRegistryProvidors);
|
|
WCHAR szProvidorName[MAX_PATH+COUNTOF(szRegistryProvidors)];
|
|
LPWSTR pOldOrder = NULL, pNewOrder = NULL;
|
|
HKEY hNewProvidor = NULL;
|
|
|
|
LPPROVIDOR pNewProvidor, pProvidor, pLastProvidor;
|
|
|
|
if (!pProvidorInfo->pName || !pProvidorInfo->pDLLName ||
|
|
!(*pProvidorInfo->pName) || !(*pProvidorInfo->pDLLName)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto CleanUp;
|
|
}
|
|
|
|
for (pProvidor = pLocalProvidor; // Local Providor is always present
|
|
pProvidor;
|
|
pProvidor = pProvidor->pNext)
|
|
{
|
|
pLastProvidor = pProvidor;
|
|
if (!lstrcmpi(pProvidor->lpName, pProvidorInfo->pDLLName))
|
|
{
|
|
//
|
|
// This should return error, but it breaks some programs that
|
|
// assume they can always add a provider
|
|
//
|
|
//SetLastError(ERROR_ALREADY_EXISTS);
|
|
bReturn = TRUE;
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
// Update the registry with new providor key
|
|
if ((dwError = RegCreateKeyEx(hProvidors, pProvidorInfo->pName, 0, NULL, 0,
|
|
KEY_ALL_ACCESS, NULL, &hNewProvidor, &dwDisposition)) ||
|
|
|
|
(dwError = RegSetValueEx(hNewProvidor, L"Name", 0, REG_SZ,
|
|
(LPBYTE)pProvidorInfo->pDLLName,
|
|
(wcslen(pProvidorInfo->pDLLName)+1) * sizeof(WCHAR))))
|
|
{
|
|
SetLastError(dwError);
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Close the handle
|
|
RegCloseKey(hNewProvidor);
|
|
hNewProvidor = NULL;
|
|
|
|
// Append to the order value
|
|
dwRequired = 0;
|
|
dwError = RegQueryValueEx(hProvidors, szOrder, NULL, NULL, NULL, &dwRequired);
|
|
|
|
switch (dwError) {
|
|
|
|
case ERROR_SUCCESS:
|
|
if ((dwOldSize = dwRequired) &&
|
|
(pOldOrder = AllocSplMem(dwRequired)) &&
|
|
!(dwError = RegQueryValueEx(hProvidors, szOrder, NULL, NULL,
|
|
(LPBYTE) pOldOrder, &dwRequired)))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (dwError) {
|
|
SetLastError(dwError);
|
|
}
|
|
goto CleanUp;
|
|
}
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
break;
|
|
|
|
default:
|
|
|
|
SetLastError(dwError);
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Append the new providor to the current order
|
|
pNewOrder = (LPWSTR)AppendOrderEntry(pOldOrder, dwRequired,
|
|
pProvidorInfo->pName, &dwReturned);
|
|
if (!pNewOrder ||
|
|
(dwError = RegSetValueEx(hProvidors, szOrder, 0,
|
|
REG_MULTI_SZ, (LPBYTE)pNewOrder, dwReturned)))
|
|
{
|
|
if (dwError) {
|
|
SetLastError(dwError);
|
|
}
|
|
goto CleanUp;
|
|
}
|
|
|
|
bOrderUpdated = TRUE;
|
|
|
|
// Initialize the providor and update the spooler structure
|
|
StringCchPrintf(szProvidorName,
|
|
cchProvidorNameLen,
|
|
L"%ws\\%ws",
|
|
szRegistryProvidors,
|
|
pProvidorInfo->pName);
|
|
|
|
pNewProvidor = InitializeProvidor(pProvidorInfo->pDLLName, szProvidorName);
|
|
|
|
if (pNewProvidor)
|
|
{
|
|
pNewProvidor->pNext = NULL;
|
|
pLastProvidor->pNext = pNewProvidor;
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
// Roll back if anything fails
|
|
if (!bReturn)
|
|
{
|
|
// Remove the new providor key if it was created
|
|
if (dwDisposition == REG_CREATED_NEW_KEY)
|
|
{
|
|
DeleteSubKeyTree(hProvidors, pProvidorInfo->pName);
|
|
RegDeleteKey(hProvidors, pProvidorInfo->pName);
|
|
}
|
|
|
|
// Restore the old order if it has been changed
|
|
if (bOrderUpdated) {
|
|
if (pOldOrder)
|
|
{
|
|
RegSetValueEx(hProvidors, szOrder, 0,
|
|
REG_MULTI_SZ, (LPBYTE)pOldOrder, dwOldSize);
|
|
}
|
|
else
|
|
{
|
|
RegDeleteValue(hProvidors, szOrder);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free allocated memory
|
|
if (pOldOrder) {
|
|
FreeSplMem(pOldOrder);
|
|
}
|
|
if (pNewOrder) {
|
|
FreeSplMem(pNewOrder);
|
|
}
|
|
if (hNewProvidor) {
|
|
RegCloseKey(hNewProvidor);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL AddPrintProvidorW(
|
|
LPWSTR pName,
|
|
DWORD dwLevel,
|
|
LPBYTE pProvidorInfo
|
|
)
|
|
|
|
/*++
|
|
Function Description: This function adds and initializes a print providor. It also updates the
|
|
registry and the order of print providors.
|
|
|
|
Parameters: pName - server name for routing (currently ignored)
|
|
dwLevel - providor info level
|
|
pProvidorInfo - providor info buffer
|
|
|
|
Return Values: TRUE if successful; FALSE otherwise
|
|
--*/
|
|
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
HANDLE hToken;
|
|
HKEY hProvidors = NULL;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
EnterRouterSem();
|
|
|
|
// Revert to spooler security context before accessing the registry
|
|
//
|
|
// This is a really bad idea, as it enables any user to get system
|
|
// priveleges without even trying.
|
|
//
|
|
// hToken = RevertToPrinterSelf();
|
|
|
|
// Check for invalid parameters
|
|
if (!pProvidorInfo)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (dwError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegistryProvidors, 0,
|
|
NULL, 0, KEY_ALL_ACCESS, NULL, &hProvidors, NULL))
|
|
{
|
|
SetLastError(dwError);
|
|
goto CleanUp;
|
|
}
|
|
|
|
switch (dwLevel) {
|
|
case 1:
|
|
bReturn = AddNewProvidor(hProvidors,
|
|
(PPROVIDOR_INFO_1W) pProvidorInfo);
|
|
break;
|
|
|
|
case 2:
|
|
bReturn = UpdateProvidorOrder(hProvidors,
|
|
((PPROVIDOR_INFO_2W) pProvidorInfo)->pOrder);
|
|
break;
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
if (hProvidors) {
|
|
RegCloseKey(hProvidors);
|
|
}
|
|
|
|
if (!bReturn && !GetLastError()) {
|
|
// Last error should be set by individual functions. In the event that something
|
|
// is not already set, return a placeholder error code
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
LeaveRouterSem();
|
|
|
|
// ImpersonatePrinterClient(hToken);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL DeletePrintProvidorW(
|
|
LPWSTR pName,
|
|
LPWSTR pEnvironment,
|
|
LPWSTR pProvidorName
|
|
)
|
|
|
|
/*++
|
|
Function Description: Deletes a print providor by updating the registry and the
|
|
removing it from the list of routing providors.
|
|
|
|
Parameters: pName - server name for routing (currently ignored)
|
|
pEnvironment - environment name (currently ignored)
|
|
pProvidorName - providor name
|
|
|
|
Return Values: TRUE if successful; FALSE otherwise
|
|
--*/
|
|
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwError = ERROR_SUCCESS, dwRequired, dwReturned;
|
|
LPWSTR pOldOrder = NULL, pNewOrder = NULL;
|
|
HANDLE hToken;
|
|
HKEY hProvidors = NULL;
|
|
BOOL bSaveAPDPolicy = FALSE;
|
|
DWORD APDValue;
|
|
|
|
LPPROVIDOR pProvidor, pTemp;
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
EnterRouterSem();
|
|
|
|
// Revert to spooler security context before accessing the registry
|
|
//
|
|
// Or rather, Don't.
|
|
//
|
|
//hToken = RevertToPrinterSelf();
|
|
|
|
// Check for invalid parameters
|
|
if (!pProvidorName || !*pProvidorName)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (dwError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegistryProvidors, 0,
|
|
NULL, 0, KEY_ALL_ACCESS, NULL, &hProvidors, NULL))
|
|
{
|
|
SetLastError(dwError);
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Save the pProvidor before deleting the registry entry
|
|
if (!(pProvidor = FindProvidor(hProvidors, pProvidorName)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Update the order
|
|
dwRequired = 0;
|
|
if (dwError = RegQueryValueEx(hProvidors, szOrder, NULL, NULL, NULL, &dwRequired))
|
|
{
|
|
SetLastError(dwError);
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (!dwRequired ||
|
|
!(pOldOrder = AllocSplMem(dwRequired)) ||
|
|
(dwError = RegQueryValueEx(hProvidors, szOrder, NULL, NULL,
|
|
(LPBYTE) pOldOrder, &dwRequired)))
|
|
{
|
|
if (dwError) {
|
|
SetLastError(dwError);
|
|
}
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Remove the providor from the current order
|
|
pNewOrder = (LPWSTR)RemoveOrderEntry(pOldOrder, dwRequired,
|
|
pProvidorName, &dwReturned);
|
|
if (!pNewOrder ||
|
|
(dwError = RegSetValueEx(hProvidors, szOrder, 0,
|
|
REG_MULTI_SZ, (LPBYTE)pNewOrder, dwReturned)))
|
|
{
|
|
if (dwError) {
|
|
SetLastError(dwError);
|
|
}
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// The AddPrinterDrivers policy has the registry value in the wrong place
|
|
// under the lanman print services key. The lanman provider is deleted
|
|
// during upgrade from Windows 2000 to XP. We save the AddPrinterDrivers
|
|
// value and restore it after we delete the registry tree for the provider.
|
|
//
|
|
if (!_wcsicmp(szLanManProvider, pProvidorName))
|
|
{
|
|
bSaveAPDPolicy = GetAPDPolicy(hProvidors,
|
|
szAPDRelPath,
|
|
szAPDValueName,
|
|
&APDValue) == ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Delete the registry key
|
|
//
|
|
DeleteSubKeyTree(hProvidors, pProvidorName);
|
|
|
|
//
|
|
// Restore the AddPrinterDrivers policy if needed.
|
|
//
|
|
if (bSaveAPDPolicy)
|
|
{
|
|
SetAPDPolicy(hProvidors,
|
|
szAPDRelPath,
|
|
szAPDValueName,
|
|
APDValue);
|
|
}
|
|
|
|
// Remove from the linked list of providors for routing
|
|
for (pTemp = pLocalProvidor;
|
|
pTemp->pNext; // Local Providor is always present and cant be deleted
|
|
pTemp = pTemp->pNext)
|
|
{
|
|
if (pTemp->pNext == pProvidor) {
|
|
// dont release the library and the struct since they may be used in
|
|
// other threads
|
|
pTemp->pNext = pProvidor->pNext;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
CleanUp:
|
|
|
|
if (!bReturn && !GetLastError()) {
|
|
// Last error should be set by individual functions. In the event that something
|
|
// is not already set, return a placeholder error code
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
// Free allocated memory
|
|
if (pOldOrder) {
|
|
FreeSplMem(pOldOrder);
|
|
}
|
|
if (pNewOrder) {
|
|
FreeSplMem(pNewOrder);
|
|
}
|
|
if (hProvidors) {
|
|
RegCloseKey(hProvidors);
|
|
}
|
|
|
|
LeaveRouterSem();
|
|
|
|
// ImpersonatePrinterClient(hToken);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
OldGetPrinterDriverW(
|
|
HANDLE hPrinter,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pDriverInfo == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinterDriver)
|
|
(pPrintHandle->hPrinter, pEnvironment,
|
|
Level, pDriverInfo, cbBuf, pcbNeeded);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
GetPrinterDriverExW(
|
|
HANDLE hPrinter,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
DWORD dwClientMajorVersion,
|
|
DWORD dwClientMinorVersion,
|
|
PDWORD pdwServerMajorVersion,
|
|
PDWORD pdwServerMinorVersion
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pDriverInfo == NULL) && (cbBuf != 0)) {
|
|
SetLastError(ERROR_INVALID_USER_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pEnvironment || !*pEnvironment)
|
|
pEnvironment = szEnvironment;
|
|
|
|
if (pPrintHandle->pProvidor->PrintProvidor.fpGetPrinterDriverEx) {
|
|
|
|
DBGMSG(DBG_TRACE, ("Calling the fpGetPrinterDriverEx function\n"));
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinterDriverEx)
|
|
(pPrintHandle->hPrinter, pEnvironment,
|
|
Level, pDriverInfo, cbBuf, pcbNeeded,
|
|
dwClientMajorVersion, dwClientMinorVersion,
|
|
pdwServerMajorVersion, pdwServerMinorVersion);
|
|
} else {
|
|
|
|
//
|
|
// The print providor does not support versioning of drivers
|
|
//
|
|
DBGMSG(DBG_TRACE, ("Calling the fpGetPrinterDriver function\n"));
|
|
*pdwServerMajorVersion = 0;
|
|
*pdwServerMinorVersion = 0;
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinterDriver)
|
|
(pPrintHandle->hPrinter, pEnvironment,
|
|
Level, pDriverInfo, cbBuf, pcbNeeded);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
GetPrinterDriverW(
|
|
HANDLE hPrinter,
|
|
LPWSTR pEnvironment,
|
|
DWORD Level,
|
|
LPBYTE pDriverInfo,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
DWORD dwServerMajorVersion;
|
|
DWORD dwServerMinorVersion;
|
|
|
|
return GetPrinterDriverExW( hPrinter,
|
|
pEnvironment,
|
|
Level,
|
|
pDriverInfo,
|
|
cbBuf,
|
|
pcbNeeded,
|
|
(DWORD)-1,
|
|
(DWORD)-1,
|
|
&dwServerMajorVersion,
|
|
&dwServerMinorVersion );
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
XcvDataW(
|
|
HANDLE hXcv,
|
|
PCWSTR pszDataName,
|
|
PBYTE pInputData,
|
|
DWORD cbInputData,
|
|
PBYTE pOutputData,
|
|
DWORD cbOutputData,
|
|
PDWORD pcbOutputNeeded,
|
|
PDWORD pdwStatus
|
|
)
|
|
{
|
|
LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hXcv;
|
|
|
|
if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
return (*pPrintHandle->pProvidor->PrintProvidor.fpXcvData)( pPrintHandle->hPrinter,
|
|
pszDataName,
|
|
pInputData,
|
|
cbInputData,
|
|
pOutputData,
|
|
cbOutputData,
|
|
pcbOutputNeeded,
|
|
pdwStatus);
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
GetJobAttributes
|
|
|
|
Routine Description:
|
|
|
|
GetJobAttributes gets information about the job.
|
|
This includes nup and reverse printing options.
|
|
|
|
Arguments:
|
|
|
|
pPrinterName -- name of the printer.
|
|
pDevmode -- Devmode to be passed to the driver
|
|
pAttributeInfo -- buffer to place information about the job
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
GetJobAttributes(
|
|
LPWSTR pPrinterName,
|
|
LPDEVMODEW pDevmode,
|
|
PATTRIBUTE_INFO_3 pAttributeInfo
|
|
)
|
|
{
|
|
HANDLE hDrvPrinter = NULL;
|
|
BOOL bReturn = FALSE, bDefault = FALSE;
|
|
FARPROC pfnDrvQueryJobAttributes;
|
|
HINSTANCE hDrvLib = NULL;
|
|
fnWinSpoolDrv fnList;
|
|
|
|
// Get the pointer to the client side functions from the router
|
|
if (!SplInitializeWinSpoolDrv(&fnList)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Get a client side printer handle to pass to the driver
|
|
if (!(* (fnList.pfnOpenPrinter))(pPrinterName, &hDrvPrinter, NULL)) {
|
|
//ODS(("Open printer failed\nPrinter %ws\n",pPrinterName));
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Load the driver config file
|
|
if (!(hDrvLib = (* (fnList.pfnLoadPrinterDriver))(hDrvPrinter))) {
|
|
//ODS(("DriverDLL could not be loaded\n"));
|
|
goto CleanUp;
|
|
}
|
|
|
|
// Call the DrvQueryJobAtributes function in the driver
|
|
if (pfnDrvQueryJobAttributes = GetProcAddress(hDrvLib, "DrvQueryJobAttributes")) {
|
|
|
|
if (!(* pfnDrvQueryJobAttributes) (hDrvPrinter,
|
|
pDevmode,
|
|
3,
|
|
(LPBYTE) pAttributeInfo)) {
|
|
|
|
if (!(* pfnDrvQueryJobAttributes) (hDrvPrinter,
|
|
pDevmode,
|
|
2,
|
|
(LPBYTE) pAttributeInfo)) {
|
|
|
|
if (!(* pfnDrvQueryJobAttributes) (hDrvPrinter,
|
|
pDevmode,
|
|
1,
|
|
(LPBYTE) pAttributeInfo)) {
|
|
|
|
bDefault = TRUE;
|
|
|
|
} else {
|
|
|
|
pAttributeInfo->dwColorOptimization = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
pAttributeInfo->dmPrintQuality = pDevmode->dmPrintQuality;
|
|
pAttributeInfo->dmYResolution = pDevmode->dmYResolution;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
bDefault = TRUE;
|
|
}
|
|
|
|
if (bDefault) {
|
|
// Set default values for old drivers that don't export the function
|
|
pAttributeInfo->dwJobNumberOfPagesPerSide = 1;
|
|
pAttributeInfo->dwDrvNumberOfPagesPerSide = 1;
|
|
pAttributeInfo->dwNupBorderFlags = 0;
|
|
pAttributeInfo->dwJobPageOrderFlags = 0;
|
|
pAttributeInfo->dwDrvPageOrderFlags = 0;
|
|
pAttributeInfo->dwJobNumberOfCopies = pDevmode->dmCopies;
|
|
pAttributeInfo->dwDrvNumberOfCopies = pDevmode->dmCopies;
|
|
pAttributeInfo->dwColorOptimization = 0;
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
CleanUp:
|
|
|
|
if (hDrvPrinter) {
|
|
(* (fnList.pfnClosePrinter))(hDrvPrinter);
|
|
}
|
|
if (hDrvLib) {
|
|
(* (fnList.pfnRefCntUnloadDriver))(hDrvLib, TRUE);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|