mirror of https://github.com/tongzx/nt5src
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.
2776 lines
73 KiB
2776 lines
73 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
prndata.c
|
|
|
|
Abstract:
|
|
|
|
This module provides all the public exported APIs relating to Printer
|
|
and Job management for the Local Print Providor
|
|
|
|
Author:
|
|
|
|
Dave Snipp (DaveSn) 15-Mar-1991
|
|
|
|
Revision History:
|
|
|
|
mattfe Apr 5 95 - we keep the driver data key open
|
|
and then just do the read / write operations here.
|
|
|
|
Steve Wilson (SWilson) Jan 11 96 - Added Server handle functionality to Get & setprinterdata
|
|
and pretty much changed everything in the process.
|
|
|
|
Steve Wilson (SWilson) May 31 96 - Added SplEnumPrinterData and SplDeletePrinterData
|
|
Steve Wilson (SWilson) Dec 96 - Added SetPrinterDataEx, GetPrinterDataEx, EnumPrinterDataEx,
|
|
EnumPrinterKey, DeletePrinterDataEx, and DeleteKey
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#include "clusspl.h"
|
|
#include "filepool.hxx"
|
|
#include <lmcons.h>
|
|
#include <lmwksta.h>
|
|
#include <lmerr.h>
|
|
#include <lmapibuf.h>
|
|
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
|
|
#define OPEN_PORT_TIMEOUT_VALUE 3000 // 3 seconds
|
|
#define DELETE_PRINTER_DATA 0
|
|
#define SET_PRINTER_DATA 1
|
|
#define DELETE_PRINTER_KEY 2
|
|
extern DWORD dwMajorVersion;
|
|
extern DWORD dwMinorVersion;
|
|
extern BOOL gbRemoteFax;
|
|
|
|
extern HANDLE ghDsUpdateThread;
|
|
extern DWORD gdwDsUpdateThreadId;
|
|
|
|
DWORD
|
|
SetPrinterDataPrinter(
|
|
HANDLE hPrinter,
|
|
HKEY hParentKey,
|
|
HKEY hKey,
|
|
LPWSTR pValueName,
|
|
DWORD Type,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
DWORD bSet
|
|
);
|
|
|
|
|
|
|
|
typedef enum {
|
|
REG_PRINT,
|
|
REG_PRINTERS,
|
|
REG_PROVIDERS
|
|
} REG_PRINT_KEY;
|
|
|
|
|
|
DWORD
|
|
GetServerKeyHandle(
|
|
PINISPOOLER pIniSpooler,
|
|
REG_PRINT_KEY eKey,
|
|
HKEY *hPrintKey,
|
|
PINISPOOLER* ppIniSpoolerOut
|
|
);
|
|
|
|
|
|
DWORD
|
|
CloseServerKeyHandle(
|
|
REG_PRINT_KEY eKey,
|
|
HKEY hPrintKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
NonRegDsPresent(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
|
|
DWORD
|
|
NonRegDsPresentForUser(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
|
|
DWORD
|
|
NonRegGetDNSMachineName(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
|
|
DWORD
|
|
PrinterNonRegGetDefaultSpoolDirectory(
|
|
PSPOOL pSpool,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
|
|
DWORD
|
|
PrinterNonRegGetChangeId(
|
|
PSPOOL pSpool,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
|
|
DWORD
|
|
RegSetDefaultSpoolDirectory(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetPortThreadPriority(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetSchedulerThreadPriority(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetNoRemoteDriver(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetNetPopupToComputer(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
|
|
DWORD
|
|
RegSetRestartJobOnPoolError(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetRestartJobOnPoolEnabled(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
|
|
DWORD
|
|
RegSetBeepEnabled(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetEventLog(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetNetPopup(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD
|
|
RegSetRetryPopup(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
DWORD dwDefaultServerThreadPriority = DEFAULT_SERVER_THREAD_PRIORITY;
|
|
DWORD dwDefaultSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
|
|
OSVERSIONINFO OsVersionInfo;
|
|
OSVERSIONINFOEX OsVersionInfoEx;
|
|
|
|
typedef struct {
|
|
LPWSTR pValue;
|
|
BOOL (*pSet) ( LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY *hKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
REG_PRINT_KEY eKey;
|
|
} SERVER_DATA, *PSERVER_DATA;
|
|
|
|
|
|
typedef struct {
|
|
LPWSTR pValue;
|
|
LPBYTE pData;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
} NON_REGISTRY_DATA, *PNON_REGISTRY_DATA;
|
|
|
|
typedef struct {
|
|
PWSTR pValue;
|
|
DWORD (*pGet)( PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
} NON_REGISTRY_FCN, *PNON_REGISTRY_FCN;
|
|
|
|
typedef struct {
|
|
PWSTR pValue;
|
|
DWORD (*pGet)( PSPOOL pSpool,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
);
|
|
} PRINTER_NON_REGISTRY_FCN, *PPRINTER_NON_REGISTRY_FCN;
|
|
|
|
|
|
SERVER_DATA gpServerRegistry[] = {{SPLREG_DEFAULT_SPOOL_DIRECTORY, RegSetDefaultSpoolDirectory, REG_PRINTERS},
|
|
{SPLREG_PORT_THREAD_PRIORITY, RegSetPortThreadPriority, REG_PRINT},
|
|
{SPLREG_SCHEDULER_THREAD_PRIORITY, RegSetSchedulerThreadPriority, REG_PRINT},
|
|
{SPLREG_BEEP_ENABLED, RegSetBeepEnabled, REG_PRINT},
|
|
{SPLREG_NET_POPUP, RegSetNetPopup, REG_PROVIDERS},
|
|
{SPLREG_RETRY_POPUP, RegSetRetryPopup, REG_PROVIDERS},
|
|
{SPLREG_EVENT_LOG, RegSetEventLog, REG_PROVIDERS},
|
|
{SPLREG_NO_REMOTE_PRINTER_DRIVERS, RegSetNoRemoteDriver, REG_PRINT},
|
|
{SPLREG_NET_POPUP_TO_COMPUTER, RegSetNetPopupToComputer, REG_PROVIDERS},
|
|
{SPLREG_RESTART_JOB_ON_POOL_ERROR, RegSetRestartJobOnPoolError, REG_PROVIDERS},
|
|
{SPLREG_RESTART_JOB_ON_POOL_ENABLED, RegSetRestartJobOnPoolEnabled, REG_PROVIDERS},
|
|
{0,0,0}};
|
|
|
|
NON_REGISTRY_DATA gpNonRegistryData[] = {{SPLREG_PORT_THREAD_PRIORITY_DEFAULT, (LPBYTE)&dwDefaultServerThreadPriority, REG_DWORD, sizeof(DWORD)},
|
|
{SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT, (LPBYTE)&dwDefaultSchedulerThreadPriority, REG_DWORD, sizeof(DWORD)},
|
|
{SPLREG_ARCHITECTURE, (LPBYTE)&LOCAL_ENVIRONMENT, REG_SZ, 0},
|
|
{SPLREG_MAJOR_VERSION, (LPBYTE)&dwMajorVersion, REG_DWORD, sizeof(DWORD)},
|
|
{SPLREG_MINOR_VERSION, (LPBYTE)&dwMinorVersion, REG_DWORD, sizeof(DWORD)},
|
|
{SPLREG_W3SVCINSTALLED, (LPBYTE)&fW3SvcInstalled, REG_DWORD, sizeof(DWORD)},
|
|
{SPLREG_OS_VERSION, (LPBYTE)&OsVersionInfo, REG_BINARY, sizeof(OsVersionInfo)},
|
|
{SPLREG_OS_VERSIONEX, (LPBYTE)&OsVersionInfoEx, REG_BINARY, sizeof(OsVersionInfoEx)},
|
|
{SPLREG_REMOTE_FAX, (LPBYTE)&gbRemoteFax, REG_BINARY, sizeof(gbRemoteFax)},
|
|
{0,0,0,0}};
|
|
|
|
NON_REGISTRY_FCN gpNonRegistryFcn[] = { {SPLREG_DS_PRESENT, NonRegDsPresent},
|
|
{SPLREG_DS_PRESENT_FOR_USER, NonRegDsPresentForUser},
|
|
{SPLREG_DNS_MACHINE_NAME, NonRegGetDNSMachineName},
|
|
{0,0}};
|
|
|
|
PRINTER_NON_REGISTRY_FCN gpPrinterNonRegistryFcn[] =
|
|
{
|
|
{ SPLREG_DEFAULT_SPOOL_DIRECTORY, PrinterNonRegGetDefaultSpoolDirectory },
|
|
{ SPLREG_CHANGE_ID, PrinterNonRegGetChangeId },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
extern WCHAR *szPrinterData;
|
|
|
|
BOOL
|
|
AvailableBidiPort(
|
|
PINIPORT pIniPort,
|
|
PINIMONITOR pIniLangMonitor
|
|
)
|
|
{
|
|
//
|
|
// File ports and ports with no monitor are useless
|
|
//
|
|
if ( (pIniPort->Status & PP_FILE) || !(pIniPort->Status & PP_MONITOR) )
|
|
return FALSE;
|
|
|
|
//
|
|
// If no LM then PM should support pfnGetPrinterDataFromPort
|
|
//
|
|
if ( !pIniLangMonitor &&
|
|
!pIniPort->pIniMonitor->Monitor2.pfnGetPrinterDataFromPort )
|
|
return FALSE;
|
|
|
|
//
|
|
// A port with no jobs or same monitor is printing then it is ok
|
|
//
|
|
return !pIniPort->pIniJob ||
|
|
pIniLangMonitor == pIniPort->pIniLangMonitor;
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetPrinterDataFromPort(
|
|
PINIPRINTER pIniPrinter,
|
|
LPWSTR pszValueName,
|
|
LPBYTE pData,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Tries to use GetPrinterDataFromPort monitor function to satisfy a
|
|
GetPrinterData call
|
|
|
|
Arguments:
|
|
pIniPrinter - Points to an INIPRINTER
|
|
|
|
Return Value:
|
|
Win32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD rc = ERROR_INVALID_PARAMETER;
|
|
DWORD i, dwFirstPortWithNoJobs, dwFirstPortHeld;
|
|
PINIMONITOR pIniLangMonitor = NULL;
|
|
PINIPORT pIniPort;
|
|
|
|
SplInSem();
|
|
//
|
|
// Is the printer bidi enabled with the LM supporting
|
|
// pfnGetPrinterDataFromPort? (Note: even PM can support this function)
|
|
//
|
|
if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI ) {
|
|
|
|
pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
|
|
// SPLASSERT(pIniLangMonitor);
|
|
|
|
if ( pIniLangMonitor &&
|
|
!pIniLangMonitor->Monitor2.pfnGetPrinterDataFromPort )
|
|
pIniLangMonitor = NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize to max
|
|
//
|
|
dwFirstPortWithNoJobs = dwFirstPortHeld = pIniPrinter->cPorts;
|
|
|
|
for ( i = 0 ; i < pIniPrinter->cPorts ; ++i ) {
|
|
|
|
pIniPort = pIniPrinter->ppIniPorts[i];
|
|
|
|
//
|
|
// Skip ports that can't be used
|
|
//
|
|
if ( !AvailableBidiPort(pIniPort, pIniLangMonitor) )
|
|
continue;
|
|
|
|
//
|
|
// Port does not need closing?
|
|
//
|
|
if ( pIniLangMonitor == pIniPort->pIniLangMonitor ) {
|
|
|
|
//
|
|
// If no jobs also then great let's use it
|
|
//
|
|
if ( !pIniPort->pIniJob )
|
|
goto PortFound;
|
|
|
|
if ( dwFirstPortHeld == pIniPrinter->cPorts ) {
|
|
|
|
dwFirstPortHeld = i;
|
|
}
|
|
} else if ( !pIniPort->pIniJob &&
|
|
dwFirstPortWithNoJobs == pIniPrinter->cPorts ) {
|
|
|
|
dwFirstPortWithNoJobs = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If all ports need closing as well as have jobs let's quit
|
|
//
|
|
if ( dwFirstPortWithNoJobs == pIniPrinter->cPorts &&
|
|
dwFirstPortHeld == pIniPrinter->cPorts ) {
|
|
|
|
return rc; //Didn't leave CS and did not unset event
|
|
}
|
|
|
|
//
|
|
// We will prefer a port with no jobs (even thought it requires closing)
|
|
//
|
|
if ( dwFirstPortWithNoJobs < pIniPrinter->cPorts )
|
|
pIniPort = pIniPrinter->ppIniPorts[dwFirstPortWithNoJobs];
|
|
else
|
|
pIniPort = pIniPrinter->ppIniPorts[dwFirstPortHeld];
|
|
|
|
PortFound:
|
|
|
|
SPLASSERT(AvailableBidiPort(pIniPort, pIniLangMonitor));
|
|
|
|
INCPORTREF(pIniPort);
|
|
LeaveSplSem();
|
|
SplOutSem();
|
|
|
|
//
|
|
// By unsetting the event for the duration of the GetPrinterDataFromPort
|
|
// we make sure even if a job requiring different monitor got assigned
|
|
// to the port it can't open/close the port.
|
|
//
|
|
// Since GetPrinterDataFromPort is supposed to come back fast it is ok
|
|
//
|
|
if ( WAIT_OBJECT_0 != WaitForSingleObject(pIniPort->hWaitToOpenOrClose,
|
|
OPEN_PORT_TIMEOUT_VALUE) ) {
|
|
|
|
DBGMSG(DBG_WARNING,
|
|
("GetPrinterDataFromPort: WaitForSingleObject timed-out\n"));
|
|
goto CleanupFromOutsideSplSem; //Left CS did not unset the event
|
|
}
|
|
|
|
//
|
|
// Port needs to be opened?
|
|
//
|
|
if ( pIniPort->pIniLangMonitor != pIniLangMonitor ||
|
|
!pIniPort->hPort ) {
|
|
|
|
LPTSTR pszPrinter;
|
|
TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
|
|
|
|
//
|
|
// A job got assigned after we left the CS and before the event
|
|
// was reset?
|
|
//
|
|
if ( pIniPort->pIniJob ) {
|
|
|
|
SetEvent(pIniPort->hWaitToOpenOrClose);
|
|
goto CleanupFromOutsideSplSem; //Outside CS did set event
|
|
}
|
|
|
|
if( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
|
|
|
|
pszPrinter = szFullPrinter;
|
|
|
|
wsprintf( szFullPrinter,
|
|
L"%ws\\%ws",
|
|
pIniPrinter->pIniSpooler->pMachineName,
|
|
pIniPrinter->pName );
|
|
} else {
|
|
pszPrinter = pIniPrinter->pName;
|
|
}
|
|
|
|
EnterSplSem();
|
|
if ( !OpenMonitorPort(pIniPort,
|
|
&pIniLangMonitor,
|
|
pszPrinter,
|
|
FALSE) ) {
|
|
|
|
SetEvent(pIniPort->hWaitToOpenOrClose);
|
|
goto Cleanup; //Inside CS but already set the event
|
|
}
|
|
|
|
LeaveSplSem();
|
|
}
|
|
|
|
SplOutSem();
|
|
|
|
if ( !pIniLangMonitor )
|
|
pIniLangMonitor = pIniPort->pIniMonitor;
|
|
|
|
if ( (*pIniLangMonitor->Monitor2.pfnGetPrinterDataFromPort)(
|
|
pIniPort->hPort,
|
|
0,
|
|
pszValueName,
|
|
NULL,
|
|
0,
|
|
(LPWSTR)pData,
|
|
cbBuf,
|
|
pcbNeeded) ) {
|
|
|
|
rc = ERROR_SUCCESS;
|
|
} else {
|
|
|
|
//
|
|
// If monitor fails the call but did not do a SetLastError()
|
|
// we do not want to corrupt the registry
|
|
//
|
|
if ( (rc = GetLastError()) == ERROR_SUCCESS ) {
|
|
|
|
ASSERT(rc != ERROR_SUCCESS);
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point we do not care if someone tries to open/close the port
|
|
// we can set the event before entering the splsem
|
|
//
|
|
SetEvent(pIniPort->hWaitToOpenOrClose);
|
|
|
|
CleanupFromOutsideSplSem:
|
|
EnterSplSem();
|
|
|
|
Cleanup:
|
|
SplInSem();
|
|
DECPORTREF(pIniPort);
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
SplGetPrintProcCaps(
|
|
PSPOOL pSpool,
|
|
LPWSTR pDatatype,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
/*++
|
|
Function Description: SplGetPrintProcCaps calls the GetPrintProcCaps function of the
|
|
Print processor that supports the given datatype.
|
|
|
|
Parameters: pSpool -- handle to the printer
|
|
pDatatype -- string containing the datatype
|
|
pData -- pointer to buffer
|
|
nSize -- size of the buffer
|
|
pcbNeeded -- pointer to the variable to store the required size of
|
|
buffer.
|
|
|
|
Return Value: Error Code
|
|
--*/
|
|
{
|
|
PINIPRINTPROC pIniPrintProc;
|
|
PINIPRINTER pIniPrinter;
|
|
DWORD dwAttributes, dwIndex, dwReturn;
|
|
|
|
// Find the print processor that supports this datatype
|
|
pIniPrintProc = pSpool->pIniPrintProc ? pSpool->pIniPrintProc
|
|
: pSpool->pIniPrinter->pIniPrintProc;
|
|
|
|
pIniPrintProc = FindDatatype( pIniPrintProc, pDatatype);
|
|
|
|
if (!pIniPrintProc)
|
|
{
|
|
return ERROR_INVALID_DATATYPE;
|
|
}
|
|
|
|
// Get the features supported by that print processor
|
|
if (!pIniPrintProc->GetPrintProcCaps)
|
|
{
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
dwAttributes = pIniPrinter->Attributes;
|
|
|
|
// Check for FILE: port which forces RAW spooling
|
|
for (dwIndex = 0;
|
|
dwIndex < pIniPrinter->cPorts;
|
|
++dwIndex)
|
|
{
|
|
if (!lstrcmpi(pIniPrinter->ppIniPorts[dwIndex]->pName,
|
|
L"FILE:"))
|
|
{
|
|
// Found a FILE: port
|
|
dwAttributes |= PRINTER_ATTRIBUTE_RAW_ONLY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Disable EMF simulated features for version < 3 drivers
|
|
if (pIniPrinter->pIniDriver &&
|
|
(pIniPrinter->pIniDriver->cVersion < 3))
|
|
{
|
|
dwAttributes |= PRINTER_ATTRIBUTE_RAW_ONLY;
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
dwReturn = (*(pIniPrintProc->GetPrintProcCaps))(pDatatype,
|
|
dwAttributes,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded);
|
|
|
|
EnterSplSem();
|
|
|
|
return dwReturn;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
SplGetNonRegData(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded,
|
|
PNON_REGISTRY_DATA pNonRegData
|
|
)
|
|
{
|
|
if ( pNonRegData->dwType == REG_SZ && pNonRegData->dwSize == 0 )
|
|
*pcbNeeded = wcslen((LPWSTR) pNonRegData->pData) * sizeof(WCHAR) + sizeof(WCHAR);
|
|
else
|
|
*pcbNeeded = pNonRegData->dwSize;
|
|
|
|
if ( *pcbNeeded > nSize )
|
|
return ERROR_MORE_DATA;
|
|
|
|
CopyMemory(pData, (LPBYTE)pNonRegData->pData, *pcbNeeded);
|
|
*pType = pNonRegData->dwType;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplGetPrinterData(
|
|
HANDLE hPrinter,
|
|
LPWSTR pValueName,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
DWORD dwResult;
|
|
PSERVER_DATA pRegistry; // points to table of Print Server registry entries
|
|
PNON_REGISTRY_DATA pNonReg;
|
|
PNON_REGISTRY_FCN pNonRegFcn;
|
|
HKEY hPrintKey;
|
|
PINIPRINTER pIniPrinter;
|
|
HKEY hKey = NULL;
|
|
DWORD dwType;
|
|
PINISPOOLER pIniSpoolerOut;
|
|
HANDLE hToken = NULL;
|
|
WCHAR szPrintProcKey[] = L"PrintProcCaps_";
|
|
LPWSTR pDatatype;
|
|
|
|
if (!ValidateSpoolHandle(pSpool, 0)) {
|
|
return rc;
|
|
}
|
|
|
|
if (!pValueName || !pcbNeeded) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
return rc;
|
|
}
|
|
|
|
if (pType)
|
|
dwType = *pType; // pType may be NULL
|
|
|
|
// Server Handle
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
|
|
|
|
// Check Registry Table
|
|
for (pRegistry = gpServerRegistry ; pRegistry->pValue ; ++pRegistry) {
|
|
|
|
if (!_wcsicmp(pRegistry->pValue, pValueName)) {
|
|
|
|
//
|
|
// Retrieve the handle for the Get.
|
|
if ((rc = GetServerKeyHandle(pSpool->pIniSpooler,
|
|
pRegistry->eKey,
|
|
&hPrintKey,
|
|
&pIniSpoolerOut)) == ERROR_SUCCESS) {
|
|
|
|
*pcbNeeded = nSize;
|
|
rc = SplRegQueryValue(hPrintKey, pValueName, pType, pData, pcbNeeded, pIniSpoolerOut);
|
|
|
|
CloseServerKeyHandle( pRegistry->eKey,
|
|
hPrintKey,
|
|
pIniSpoolerOut );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pRegistry->pValue) { // May be a non-registry entry
|
|
|
|
for (pNonReg = gpNonRegistryData ; pNonReg->pValue ; ++pNonReg) {
|
|
if (!_wcsicmp(pNonReg->pValue, pValueName)) {
|
|
|
|
rc = SplGetNonRegData(pSpool->pIniSpooler,
|
|
&dwType,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded,
|
|
pNonReg);
|
|
|
|
if (pType)
|
|
*pType = dwType;
|
|
|
|
goto FinishNonReg;
|
|
}
|
|
}
|
|
|
|
for (pNonRegFcn = gpNonRegistryFcn ; pNonRegFcn->pValue ; ++pNonRegFcn) {
|
|
if (!_wcsicmp(pNonRegFcn->pValue, pValueName)) {
|
|
|
|
rc = (*pNonRegFcn->pGet)(pSpool->pIniSpooler, &dwType, pData, nSize, pcbNeeded);
|
|
|
|
if (pType)
|
|
*pType = dwType;
|
|
|
|
goto FinishNonReg;
|
|
}
|
|
}
|
|
|
|
FinishNonReg:
|
|
|
|
if (!pNonReg->pValue && !pNonRegFcn->pValue) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
// Printer handle
|
|
} else {
|
|
|
|
PPRINTER_NON_REGISTRY_FCN pPrinterNonRegFcn;
|
|
|
|
EnterSplSem();
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
|
|
|
|
//
|
|
// If the pValueName is "PrintProcCaps_[datatype]" call the print processor which
|
|
// supports that datatype and return the options that it supports.
|
|
//
|
|
if (pValueName == wcsstr(pValueName, szPrintProcKey)) {
|
|
|
|
pDatatype = (LPWSTR) (pValueName+(wcslen(szPrintProcKey)));
|
|
if (!pDatatype) {
|
|
|
|
LeaveSplSem();
|
|
return ERROR_INVALID_DATATYPE;
|
|
} else {
|
|
|
|
rc = SplGetPrintProcCaps(pSpool,
|
|
pDatatype,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded);
|
|
LeaveSplSem();
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for PrinterNonReg calls.
|
|
//
|
|
for (pPrinterNonRegFcn = gpPrinterNonRegistryFcn ;
|
|
pPrinterNonRegFcn->pValue ;
|
|
++pPrinterNonRegFcn) {
|
|
|
|
if (!_wcsicmp(pPrinterNonRegFcn->pValue, pValueName)) {
|
|
|
|
rc = (*pPrinterNonRegFcn->pGet)( pSpool,
|
|
&dwType,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded );
|
|
|
|
if( pType ){
|
|
*pType = dwType;
|
|
}
|
|
LeaveSplSem();
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
|
|
LeaveSplSem();
|
|
rc = ERROR_INVALID_PRINTER_STATE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// During upgrade do not try to talk to the port since we
|
|
// will not be on the net
|
|
//
|
|
if ( dwUpgradeFlag == 0 &&
|
|
AccessGranted(SPOOLER_OBJECT_PRINTER,
|
|
PRINTER_ACCESS_ADMINISTER,
|
|
pSpool ) ) {
|
|
|
|
rc = GetPrinterDataFromPort(pIniPrinter,
|
|
pValueName,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded);
|
|
}
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
dwResult = OpenPrinterKey(pIniPrinter,
|
|
KEY_READ | KEY_WRITE,
|
|
&hKey,
|
|
szPrinterData,
|
|
FALSE);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
if (dwResult != ERROR_SUCCESS) {
|
|
LeaveSplSem();
|
|
return dwResult;
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
*pType = REG_BINARY;
|
|
|
|
(VOID)SetPrinterDataPrinter(hPrinter,
|
|
NULL,
|
|
hKey,
|
|
pValueName,
|
|
*pType,
|
|
pData,
|
|
*pcbNeeded,
|
|
SET_PRINTER_DATA);
|
|
|
|
} else if ( rc != ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
*pcbNeeded = nSize;
|
|
rc = SplRegQueryValue( hKey,
|
|
pValueName,
|
|
pType,
|
|
pData,
|
|
pcbNeeded,
|
|
pIniPrinter->pIniSpooler );
|
|
}
|
|
|
|
LeaveSplSem();
|
|
}
|
|
}
|
|
|
|
|
|
if (hKey)
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
|
|
SplOutSem();
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SplGetPrinterDataEx(
|
|
HANDLE hPrinter,
|
|
LPCWSTR pKeyName,
|
|
LPCWSTR pValueName,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
PSERVER_DATA pRegistry; // points to table of Print Server registry entries
|
|
PINIPRINTER pIniPrinter;
|
|
HKEY hKey = NULL;
|
|
HANDLE hToken = NULL;
|
|
|
|
|
|
if (!ValidateSpoolHandle(pSpool, 0)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!pValueName || !pcbNeeded) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
|
|
rc = SplGetPrinterData( hPrinter,
|
|
(LPWSTR) pValueName,
|
|
pType,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded);
|
|
|
|
} else {
|
|
|
|
if (!pKeyName || !*pKeyName) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
EnterSplSem();
|
|
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
INCPRINTERREF(pIniPrinter);
|
|
|
|
SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
|
|
|
|
if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
|
|
LeaveSplSem();
|
|
rc = ERROR_INVALID_PRINTER_STATE;
|
|
|
|
} else if (!_wcsicmp(pKeyName, szPrinterData)) {
|
|
LeaveSplSem();
|
|
rc = SplGetPrinterData( hPrinter,
|
|
(LPWSTR) pValueName,
|
|
pType,
|
|
pData,
|
|
nSize,
|
|
pcbNeeded);
|
|
} else {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, pKeyName, TRUE);
|
|
|
|
LeaveSplSem();
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
*pcbNeeded = nSize;
|
|
rc = SplRegQueryValue(hKey,
|
|
pValueName,
|
|
pType,
|
|
pData,
|
|
pcbNeeded,
|
|
pIniPrinter->pIniSpooler);
|
|
}
|
|
}
|
|
|
|
EnterSplSem();
|
|
if (hKey)
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
|
|
DECPRINTERREF(pIniPrinter);
|
|
LeaveSplSem();
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
SplOutSem();
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
SplEnumPrinterData(
|
|
HANDLE hPrinter,
|
|
DWORD dwIndex, // index of value to query
|
|
LPWSTR pValueName, // address of buffer for value string
|
|
DWORD cbValueName, // size of buffer for value string
|
|
LPDWORD pcbValueName, // address for size of value buffer
|
|
LPDWORD pType, // address of buffer for type code
|
|
LPBYTE pData, // address of buffer for value data
|
|
DWORD cbData, // size of buffer for value data
|
|
LPDWORD pcbData // address for size of data buffer
|
|
)
|
|
{
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HKEY hKey = NULL;
|
|
PINIPRINTER pIniPrinter;
|
|
HANDLE hToken = NULL;
|
|
|
|
|
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
return rc;
|
|
}
|
|
|
|
if (!pValueName || !pcbValueName) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
return rc;
|
|
}
|
|
|
|
|
|
EnterSplSem();
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
|
|
|
|
if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
|
|
LeaveSplSem();
|
|
rc = ERROR_INVALID_PRINTER_STATE;
|
|
|
|
} else {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_READ, &hKey, szPrinterData, TRUE);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
LeaveSplSem();
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
if (!cbValueName && !cbData) { // Both sizes are NULL, so user wants to get buffer sizes
|
|
|
|
rc = SplRegQueryInfoKey( hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pcbValueName,
|
|
pcbData,
|
|
NULL,
|
|
NULL,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
} else {
|
|
*pcbValueName = cbValueName/sizeof(WCHAR);
|
|
*pcbData = cbData;
|
|
rc = SplRegEnumValue( hKey,
|
|
dwIndex,
|
|
pValueName,
|
|
pcbValueName,
|
|
pType,
|
|
pData,
|
|
pcbData,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
*pcbValueName = (*pcbValueName + 1)*sizeof(WCHAR);
|
|
}
|
|
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplEnumPrinterDataEx(
|
|
HANDLE hPrinter,
|
|
LPCWSTR pKeyName, // key name
|
|
LPBYTE pEnumValueStart,
|
|
DWORD cbEnumValues,
|
|
LPDWORD pcbEnumValues,
|
|
LPDWORD pnEnumValues // number of values returned
|
|
)
|
|
{
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
BOOL bRet = FALSE;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
PINIPRINTER pIniPrinter;
|
|
HKEY hKey = NULL;
|
|
DWORD i;
|
|
LPWSTR pNextValueName, pValueName = NULL;
|
|
LPBYTE pData = NULL;
|
|
PPRINTER_ENUM_VALUES pEnumValue;
|
|
DWORD cchValueName, cbData, cchValueNameTemp, cbDataTemp;
|
|
DWORD dwType, cbSourceDir=0, cbTargetDir=0;
|
|
HANDLE hToken = NULL;
|
|
LPWSTR pszSourceDir = NULL, pszTargetDir = NULL;
|
|
|
|
EnterSplSem();
|
|
|
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
LeaveSplSem();
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
if (!pKeyName || !*pKeyName) {
|
|
LeaveSplSem();
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pcbEnumValues = 0;
|
|
*pnEnumValues = 0;
|
|
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
|
|
|
|
if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
|
|
LeaveSplSem();
|
|
rc = ERROR_INVALID_PRINTER_STATE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// open specified key
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, pKeyName, TRUE);
|
|
|
|
LeaveSplSem();
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
do {
|
|
// Get the max size
|
|
rc = SplRegQueryInfoKey( hKey,
|
|
NULL,
|
|
NULL,
|
|
pnEnumValues,
|
|
&cchValueName,
|
|
&cbData,
|
|
NULL,
|
|
NULL,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
cchValueName = (cchValueName + 1);
|
|
cbData = (cbData + 1) & ~1;
|
|
|
|
// Allocate temporary buffers to determine true required size
|
|
if (!(pValueName = AllocSplMem(cchValueName * sizeof (WCHAR)))) {
|
|
rc = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!(pData = AllocSplMem(cbData))) {
|
|
rc = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Run through Values and accumulate sizes
|
|
for (i = 0 ; rc == ERROR_SUCCESS && i < *pnEnumValues ; ++i) {
|
|
|
|
cchValueNameTemp = cchValueName;
|
|
cbDataTemp = cbData;
|
|
|
|
rc = SplRegEnumValue( hKey,
|
|
i,
|
|
pValueName,
|
|
&cchValueNameTemp,
|
|
&dwType,
|
|
pData,
|
|
&cbDataTemp,
|
|
pIniPrinter->pIniSpooler);
|
|
|
|
*pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
|
|
(cchValueNameTemp + 1)*sizeof(WCHAR);
|
|
|
|
*pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, dwType) +
|
|
cbDataTemp;
|
|
}
|
|
|
|
//
|
|
// If the key is a sub key of "CopyFiles" we need to generate
|
|
// the paths for the source/target directories if the call is remote
|
|
//
|
|
if ( (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_DATA) &&
|
|
!wcsncmp(pKeyName, L"CopyFiles\\", wcslen(L"CopyFiles\\")) ) {
|
|
|
|
if ( !GenerateDirectoryNamesForCopyFilesKey(pSpool,
|
|
hKey,
|
|
&pszSourceDir,
|
|
&pszTargetDir,
|
|
cchValueName*sizeof (WCHAR)) ) {
|
|
|
|
rc = GetLastError();
|
|
goto Cleanup;
|
|
|
|
} else {
|
|
|
|
SPLASSERT(pszSourceDir && pszTargetDir);
|
|
|
|
if ( pszSourceDir ) {
|
|
|
|
cbSourceDir = (wcslen(pszSourceDir) + 1)*sizeof(WCHAR);
|
|
|
|
*pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
|
|
sizeof(L"SourceDir") + sizeof(WCHAR);
|
|
|
|
*pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
|
|
cbSourceDir;
|
|
|
|
(*pnEnumValues)++;
|
|
}
|
|
if ( pszTargetDir ) {
|
|
|
|
cbTargetDir = (wcslen(pszTargetDir) + 1)*sizeof(WCHAR);
|
|
|
|
*pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
|
|
sizeof(L"TargetDir") + sizeof(WCHAR);
|
|
|
|
*pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
|
|
cbTargetDir;
|
|
|
|
(*pnEnumValues)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pcbEnumValues += sizeof(PRINTER_ENUM_VALUES)**pnEnumValues;
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
if (*pcbEnumValues > cbEnumValues) {
|
|
rc = ERROR_MORE_DATA;
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Adjust pointers & Get data
|
|
pEnumValue = (PPRINTER_ENUM_VALUES) pEnumValueStart;
|
|
|
|
pNextValueName = (LPWSTR) (pEnumValueStart + *pnEnumValues*sizeof(PRINTER_ENUM_VALUES));
|
|
|
|
pNextValueName = (LPWSTR) AlignToRegType((ULONG_PTR)pNextValueName, REG_SZ);
|
|
|
|
for(i = 0 ; rc == ERROR_SUCCESS && i < *pnEnumValues ; ++i, ++pEnumValue) {
|
|
|
|
// bytes left in the allocated buffer
|
|
DWORD cbRemaining = (DWORD)(pEnumValueStart + cbEnumValues - (LPBYTE)pNextValueName);
|
|
|
|
pEnumValue->pValueName = pNextValueName;
|
|
// use minimum of cbRemaining and max size
|
|
pEnumValue->cbValueName = (cbRemaining < cchValueName*sizeof (WCHAR))
|
|
? cbRemaining : cchValueName*sizeof (WCHAR);
|
|
pEnumValue->cbData = cbData;
|
|
|
|
if ( i == *pnEnumValues - 2 && cbSourceDir ) {
|
|
|
|
pEnumValue->dwType = REG_SZ;
|
|
|
|
pEnumValue->cbData = cbSourceDir;
|
|
|
|
pEnumValue->cbValueName = sizeof(L"SourceDir") + sizeof(WCHAR);
|
|
|
|
pEnumValue->pData = (LPBYTE) pEnumValue->pValueName +
|
|
pEnumValue->cbValueName;
|
|
|
|
pEnumValue->pData = (LPBYTE) AlignToRegType((ULONG_PTR)pEnumValue->pData,
|
|
pEnumValue->dwType);
|
|
|
|
wcscpy(pEnumValue->pValueName, L"SourceDir");
|
|
|
|
wcscpy((LPWSTR)pEnumValue->pData, pszSourceDir);
|
|
|
|
} else if ( i == *pnEnumValues - 1 && cbTargetDir ) {
|
|
|
|
pEnumValue->dwType = REG_SZ;
|
|
|
|
pEnumValue->cbData = cbTargetDir;
|
|
|
|
pEnumValue->cbValueName = sizeof(L"TargetDir") +
|
|
sizeof(WCHAR);
|
|
|
|
pEnumValue->pData = (LPBYTE) pEnumValue->pValueName +
|
|
pEnumValue->cbValueName;
|
|
|
|
pEnumValue->pData = (LPBYTE) AlignToRegType((ULONG_PTR )pEnumValue->pData,
|
|
pEnumValue->dwType);
|
|
|
|
wcscpy(pEnumValue->pValueName, L"TargetDir");
|
|
|
|
wcscpy((LPWSTR)pEnumValue->pData, pszTargetDir);
|
|
|
|
} else {
|
|
DWORD cchValueName = pEnumValue->cbValueName / sizeof (WCHAR);
|
|
|
|
// adjust to count of characters
|
|
rc = SplRegEnumValue(hKey,
|
|
i,
|
|
pEnumValue->pValueName,
|
|
&cchValueName,
|
|
&pEnumValue->dwType,
|
|
pData,
|
|
&pEnumValue->cbData,
|
|
pIniPrinter->pIniSpooler);
|
|
|
|
pEnumValue->cbValueName = (cchValueName + 1)*sizeof(WCHAR);
|
|
|
|
pEnumValue->pData = (LPBYTE) pEnumValue->pValueName + pEnumValue->cbValueName;
|
|
|
|
pEnumValue->pData = (LPBYTE) AlignToRegType((ULONG_PTR)pEnumValue->pData,
|
|
pEnumValue->dwType);
|
|
|
|
CopyMemory(pEnumValue->pData, pData, pEnumValue->cbData);
|
|
}
|
|
|
|
if (i + 1 < *pnEnumValues) {
|
|
pNextValueName = (LPWSTR) AlignToRegType((ULONG_PTR)(pEnumValue->pData +
|
|
pEnumValue->cbData), REG_SZ);
|
|
}
|
|
|
|
if (pEnumValue->cbData == 0) {
|
|
pEnumValue->pData = NULL;
|
|
}
|
|
|
|
}
|
|
if (rc == ERROR_NO_MORE_ITEMS)
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
FreeSplMem(pValueName);
|
|
FreeSplMem(pData);
|
|
pValueName = (LPWSTR) pData = NULL;
|
|
|
|
} while(rc == ERROR_MORE_DATA);
|
|
|
|
if ( rc == ERROR_SUCCESS )
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
SplOutSem();
|
|
|
|
FreeSplStr(pszTargetDir);
|
|
FreeSplStr(pszSourceDir);
|
|
|
|
FreeSplMem(pValueName);
|
|
FreeSplMem(pData);
|
|
|
|
// Close handle
|
|
if (hKey)
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
if ( !bRet && rc == ERROR_SUCCESS ) {
|
|
|
|
// SPLASSERT(dwLastError == ERROR_SUCCESS); -- after ICM is fixed
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplEnumPrinterKey(
|
|
HANDLE hPrinter,
|
|
LPCWSTR pKeyName, // key name
|
|
LPWSTR pSubKey, // address of buffer for value string
|
|
DWORD cbSubKey, // size of buffer for value string
|
|
LPDWORD pcbSubKey // address for size of value buffer
|
|
)
|
|
{
|
|
HKEY hKey = NULL;
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
PINIPRINTER pIniPrinter;
|
|
PINISPOOLER pIniSpooler;
|
|
LPWSTR pRootKeyName;
|
|
DWORD cbSubKeyMax;
|
|
DWORD cwSubKeyMax;
|
|
DWORD cwSubKey, cwSubKeyTotal, cbSubKeyTotal, cwSubKeyOutput;
|
|
DWORD dwIndex;
|
|
DWORD nSubKeys;
|
|
LPWSTR pKeys = NULL;
|
|
HANDLE hToken = NULL;
|
|
|
|
|
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
if (!pKeyName || !pcbSubKey) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
EnterSplSem();
|
|
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
|
|
|
|
if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
|
|
LeaveSplSem();
|
|
rc = ERROR_INVALID_PRINTER_STATE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// open specified key
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, pKeyName, TRUE);
|
|
|
|
LeaveSplSem();
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
do {
|
|
|
|
// Get the max size
|
|
rc = SplRegQueryInfoKey( hKey, // Key
|
|
&nSubKeys, // lpcSubKeys
|
|
&cwSubKeyMax, // lpcbMaxSubKeyLen
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
|
|
++cwSubKeyMax; // Add terminating NULL
|
|
cbSubKeyMax = (cwSubKeyMax + 1)*sizeof(WCHAR);
|
|
|
|
if (!(pKeys = AllocSplMem(cbSubKeyMax))) {
|
|
rc = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
// Enumerate keys to get exact size
|
|
for(dwIndex = cwSubKeyTotal = 0 ; dwIndex < nSubKeys && rc == ERROR_SUCCESS ; ++dwIndex) {
|
|
|
|
cwSubKey = cwSubKeyMax;
|
|
|
|
rc = SplRegEnumKey( hKey,
|
|
dwIndex,
|
|
pKeys,
|
|
&cwSubKey,
|
|
NULL,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
cwSubKeyTotal += cwSubKey + 1;
|
|
}
|
|
|
|
//
|
|
// cwSubKeyTotal is being reset in the initialization list of the foor loop. Thus
|
|
// its value is not accurate if we do not enter the loop at all (when nSubKeys is 0)
|
|
//
|
|
*pcbSubKey = nSubKeys ? cwSubKeyTotal*sizeof(WCHAR) + sizeof(WCHAR) : 2*sizeof(WCHAR);
|
|
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
if(*pcbSubKey > cbSubKey) {
|
|
rc = ERROR_MORE_DATA;
|
|
break;
|
|
|
|
} else {
|
|
|
|
//
|
|
// cwSubKeyOutput is the size of the output buffer in wchar
|
|
//
|
|
cwSubKeyOutput = cbSubKey/sizeof(WCHAR);
|
|
|
|
for(dwIndex = cwSubKeyTotal = 0 ; dwIndex < nSubKeys && rc == ERROR_SUCCESS ; ++dwIndex) {
|
|
|
|
//
|
|
// Calculate the remaining output buffer size in characters.
|
|
// If we're out of room, exit with ERROR_MORE_DATA.
|
|
// This is needed since it is possible the registry has changed.
|
|
//
|
|
if (cwSubKeyOutput < cwSubKeyTotal + 1) {
|
|
rc = ERROR_MORE_DATA;
|
|
break;
|
|
}
|
|
cwSubKey = cwSubKeyOutput - cwSubKeyTotal;
|
|
|
|
rc = SplRegEnumKey( hKey,
|
|
dwIndex,
|
|
pSubKey + cwSubKeyTotal,
|
|
&cwSubKey,
|
|
NULL,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
cwSubKeyTotal += cwSubKey + 1;
|
|
}
|
|
|
|
//
|
|
// cwSubKeyTotal is being reset in the initialization list of the foor loop. Thus
|
|
// its value is not accurate if we do not enter the loop at all (when nSubKeys is 0)
|
|
// If we don't enter the for loop, then we don't need to update *pcbSubKey
|
|
//
|
|
if (nSubKeys && (dwIndex == nSubKeys || rc == ERROR_NO_MORE_ITEMS)) {
|
|
//
|
|
// Get the most recent data size just in case something changed
|
|
//
|
|
*pcbSubKey = cwSubKeyTotal*sizeof(WCHAR) + sizeof(WCHAR);
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
FreeSplMem(pKeys);
|
|
pKeys = NULL;
|
|
|
|
} while(rc == ERROR_MORE_DATA);
|
|
|
|
Cleanup:
|
|
|
|
// Close handles
|
|
if (hKey)
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
|
|
FreeSplMem(pKeys);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplDeletePrinterData(
|
|
HANDLE hPrinter,
|
|
LPWSTR pValueName
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HKEY hKey = NULL;
|
|
HANDLE hToken = NULL;
|
|
|
|
EnterSplSem();
|
|
|
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE, &hKey, szPrinterData, FALSE);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
rc = SetPrinterDataPrinter( hPrinter,
|
|
NULL,
|
|
hKey,
|
|
pValueName,
|
|
0, NULL, 0, DELETE_PRINTER_DATA);
|
|
|
|
SplRegCloseKey(hKey, pSpool->pIniPrinter->pIniSpooler);
|
|
}
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplDeletePrinterDataEx(
|
|
HANDLE hPrinter,
|
|
LPCWSTR pKeyName,
|
|
LPCWSTR pValueName
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HANDLE hToken = NULL;
|
|
HKEY hKey = NULL;
|
|
|
|
if (!pKeyName || !*pKeyName) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
EnterSplSem();
|
|
|
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE, &hKey, pKeyName, TRUE);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = SetPrinterDataPrinter(hPrinter,
|
|
NULL,
|
|
hKey,
|
|
(LPWSTR) pValueName,
|
|
0, NULL, 0, DELETE_PRINTER_DATA);
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
if (hKey)
|
|
SplRegCloseKey(hKey, pSpool->pIniSpooler);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplDeletePrinterKey(
|
|
HANDLE hPrinter,
|
|
LPCWSTR pKeyName
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HANDLE hToken = NULL;
|
|
HKEY hKey = NULL, hPrinterKey = NULL;
|
|
|
|
if (!pKeyName)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
EnterSplSem();
|
|
|
|
if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE | KEY_READ, &hKey, pKeyName, TRUE);
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE | KEY_READ, &hPrinterKey, NULL, TRUE);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
rc = SetPrinterDataPrinter(hPrinter,
|
|
hPrinterKey,
|
|
hKey,
|
|
(LPWSTR) pKeyName,
|
|
0, NULL, 0, DELETE_PRINTER_KEY);
|
|
|
|
}
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
if (hPrinterKey)
|
|
SplRegCloseKey(hPrinterKey, pSpool->pIniSpooler);
|
|
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplSetPrinterData(
|
|
HANDLE hPrinter,
|
|
LPWSTR pValueName,
|
|
DWORD Type,
|
|
LPBYTE pData,
|
|
DWORD cbData
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HANDLE hToken = NULL;
|
|
HKEY hKey = NULL;
|
|
|
|
EnterSplSem();
|
|
|
|
if (!ValidateSpoolHandle(pSpool, 0)) {
|
|
LeaveSplSem();
|
|
return rc;
|
|
}
|
|
|
|
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
|
|
|
|
if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
|
|
SERVER_ACCESS_ADMINISTER,
|
|
NULL, NULL, pSpool->pIniSpooler)) {
|
|
|
|
rc = ERROR_ACCESS_DENIED;
|
|
|
|
} else {
|
|
|
|
rc = SetPrinterDataServer(pSpool->pIniSpooler, pValueName, Type, pData, cbData);
|
|
}
|
|
} else {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_READ | KEY_WRITE, &hKey, szPrinterData, FALSE);
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
rc = SetPrinterDataPrinter( hPrinter,
|
|
NULL,
|
|
hKey,
|
|
pValueName,
|
|
Type, pData, cbData, SET_PRINTER_DATA);
|
|
|
|
SplRegCloseKey(hKey, pSpool->pIniPrinter->pIniSpooler);
|
|
}
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SplSetPrinterDataEx(
|
|
HANDLE hPrinter,
|
|
LPCWSTR pKeyName,
|
|
LPCWSTR pValueName,
|
|
DWORD Type,
|
|
LPBYTE pData,
|
|
DWORD cbData
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HANDLE hToken = NULL;
|
|
PINIPRINTER pIniPrinter;
|
|
PINIJOB pIniJob;
|
|
HKEY hKey = NULL;
|
|
PINISPOOLER pIniSpooler;
|
|
LPWSTR pPrinterKeyName;
|
|
DWORD DsUpdate = 0;
|
|
|
|
|
|
if (!ValidateSpoolHandle(pSpool, 0)){
|
|
goto Done;
|
|
}
|
|
|
|
if (!pValueName) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
|
|
return SplSetPrinterData(hPrinter, (LPWSTR) pValueName, Type, pData, cbData);
|
|
}
|
|
|
|
if (!pKeyName || !*pKeyName) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
if (!_wcsicmp(szPrinterData, pKeyName)) {
|
|
return SplSetPrinterData(hPrinter, (LPWSTR) pValueName, Type, pData, cbData);
|
|
}
|
|
|
|
EnterSplSem();
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
pIniSpooler = pIniPrinter->pIniSpooler;
|
|
|
|
DBGMSG( DBG_EXEC, ("SetPrinterDataEx: %ws %ws %ws %d cbSize=cbData\n",
|
|
pIniPrinter->pName,
|
|
pKeyName,
|
|
pValueName,
|
|
Type,
|
|
cbData ));
|
|
|
|
SPLASSERT(pIniPrinter &&
|
|
pIniPrinter->signature == IP_SIGNATURE);
|
|
|
|
if ( !AccessGranted( SPOOLER_OBJECT_PRINTER,
|
|
PRINTER_ACCESS_ADMINISTER,
|
|
pSpool ) ) {
|
|
|
|
rc = ERROR_ACCESS_DENIED;
|
|
goto DoneFromSplSem;
|
|
}
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
// If this is a DS Key then parse out OID, if any, and write to Registry
|
|
// Also check that data type is correct
|
|
if (!wcscmp(pKeyName, SPLDS_SPOOLER_KEY)){
|
|
DsUpdate = DS_KEY_SPOOLER;
|
|
} else if (!wcscmp(pKeyName, SPLDS_DRIVER_KEY)){
|
|
DsUpdate = DS_KEY_DRIVER;
|
|
} else if (!wcscmp(pKeyName, SPLDS_USER_KEY)){
|
|
DsUpdate = DS_KEY_USER;
|
|
}
|
|
|
|
if (DsUpdate) {
|
|
if (Type != REG_SZ && Type != REG_MULTI_SZ && Type != REG_DWORD && !(Type == REG_BINARY && cbData == 1)) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
goto DoneFromSplSem;
|
|
}
|
|
}
|
|
|
|
// Open or Create the key
|
|
// Create the hPrinterKey if it doesn't exist
|
|
rc = OpenPrinterKey(pIniPrinter,
|
|
KEY_READ | KEY_WRITE,
|
|
&hKey,
|
|
pKeyName,
|
|
FALSE);
|
|
if (rc != ERROR_SUCCESS)
|
|
goto DoneFromSplSem;
|
|
|
|
|
|
// Set the value
|
|
rc = SplRegSetValue(hKey,
|
|
pValueName,
|
|
Type,
|
|
pData,
|
|
cbData,
|
|
pIniPrinter->pIniSpooler );
|
|
if (rc != ERROR_SUCCESS)
|
|
goto DoneFromSplSem;
|
|
|
|
//
|
|
// Set Data succeeded. If the color profiles assocaiated with the
|
|
// print queue were updated we send a notification. TS listens for it
|
|
// and saves print queues settings. Updating color profiles implies
|
|
// touching 4 regitry keys. We want to send the notify only after the
|
|
// last key is updated.
|
|
//
|
|
if (!_wcsicmp(pKeyName, L"CopyFiles\\ICM") &&
|
|
!_wcsicmp(pValueName, L"Module"))
|
|
{
|
|
UpdatePrinterIni(pIniPrinter, CHANGEID_ONLY);
|
|
|
|
SetPrinterChange(pIniPrinter,
|
|
NULL,
|
|
NULL,
|
|
PRINTER_CHANGE_SET_PRINTER_DRIVER,
|
|
pSpool->pIniSpooler );
|
|
}
|
|
|
|
|
|
if (hToken) {
|
|
ImpersonatePrinterClient(hToken);
|
|
hToken = NULL;
|
|
}
|
|
|
|
if (ghDsUpdateThread && gdwDsUpdateThreadId == GetCurrentThreadId()) {
|
|
// We are in the background thread
|
|
pIniPrinter->DsKeyUpdate |= DsUpdate;
|
|
} else {
|
|
pIniPrinter->DsKeyUpdateForeground |= DsUpdate;
|
|
}
|
|
UpdatePrinterIni(pIniPrinter, UPDATE_DS_ONLY);
|
|
|
|
DoneFromSplSem:
|
|
|
|
if (hToken) {
|
|
ImpersonatePrinterClient(hToken);
|
|
}
|
|
|
|
LeaveSplSem();
|
|
|
|
if ( rc == ERROR_SUCCESS &&
|
|
!wcsncmp(pKeyName, L"CopyFiles\\", wcslen(L"CopyFiles\\")) ) {
|
|
|
|
(VOID)SplCopyFileEvent(pSpool,
|
|
(LPWSTR)pKeyName,
|
|
COPYFILE_EVENT_SET_PRINTER_DATAEX);
|
|
}
|
|
|
|
Done:
|
|
|
|
DBGMSG( DBG_EXEC, ("SetPrinterDataEx: return %d\n", rc));
|
|
|
|
if (hKey) {
|
|
SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
// SetPrinterDataServer - also called during initialization
|
|
DWORD
|
|
SetPrinterDataServer(
|
|
PINISPOOLER pIniSpooler,
|
|
LPWSTR pValueName,
|
|
DWORD Type,
|
|
LPBYTE pData,
|
|
DWORD cbData
|
|
)
|
|
{
|
|
LPWSTR pKeyName;
|
|
DWORD rc;
|
|
HANDLE hToken = NULL;
|
|
PINIPRINTER pIniPrinter;
|
|
PINIJOB pIniJob;
|
|
PSERVER_DATA pRegistry; // points to table of Print Server registry entries
|
|
HKEY hKey;
|
|
PINISPOOLER pIniSpoolerOut;
|
|
|
|
|
|
// Server Handle
|
|
|
|
if (!pValueName) {
|
|
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
for (pRegistry = gpServerRegistry ; pRegistry->pValue ; ++pRegistry) {
|
|
|
|
if (!_wcsicmp(pRegistry->pValue, pValueName)) {
|
|
|
|
if ((rc = GetServerKeyHandle( pIniSpooler,
|
|
pRegistry->eKey,
|
|
&hKey,
|
|
&pIniSpoolerOut)) == ERROR_SUCCESS) {
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
if (pRegistry->pSet) {
|
|
rc = (*pRegistry->pSet)(pValueName, Type, pData, cbData, hKey, pIniSpoolerOut);
|
|
}
|
|
else {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
CloseServerKeyHandle( pRegistry->eKey,
|
|
hKey,
|
|
pIniSpoolerOut );
|
|
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pRegistry->pValue) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SetPrinterDataPrinter(
|
|
HANDLE hPrinter,
|
|
HKEY hParentKey,
|
|
HKEY hKey,
|
|
LPWSTR pValueName,
|
|
DWORD Type,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
DWORD dwSet // SET_PRINTER_DATA, DELETE_PRINTER_DATA, or DELETE_PRINTER_KEY
|
|
)
|
|
{
|
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
|
LPWSTR pKeyName;
|
|
DWORD rc = ERROR_INVALID_HANDLE;
|
|
HANDLE hToken = NULL;
|
|
PINIPRINTER pIniPrinter;
|
|
PINIJOB pIniJob;
|
|
|
|
SplInSem();
|
|
|
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )){
|
|
goto Done;
|
|
}
|
|
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
SPLASSERT(pIniPrinter &&
|
|
pIniPrinter->signature == IP_SIGNATURE && hKey);
|
|
|
|
if ( !AccessGranted( SPOOLER_OBJECT_PRINTER,
|
|
PRINTER_ACCESS_ADMINISTER,
|
|
pSpool ) ) {
|
|
|
|
rc = ERROR_ACCESS_DENIED;
|
|
goto Done;
|
|
}
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
if (dwSet == SET_PRINTER_DATA) {
|
|
|
|
rc = SplRegSetValue(hKey,
|
|
pValueName,
|
|
Type,
|
|
pData,
|
|
cbData,
|
|
pIniPrinter->pIniSpooler );
|
|
|
|
} else if (dwSet == DELETE_PRINTER_DATA) {
|
|
|
|
rc = SplRegDeleteValue(hKey, pValueName, pIniPrinter->pIniSpooler );
|
|
|
|
} else if (dwSet == DELETE_PRINTER_KEY) {
|
|
|
|
rc = SplDeleteThisKey(hParentKey,
|
|
hKey,
|
|
pValueName,
|
|
FALSE,
|
|
pIniPrinter->pIniSpooler);
|
|
}
|
|
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
UpdatePrinterIni(pIniPrinter, CHANGEID_ONLY);
|
|
|
|
SetPrinterChange(pIniPrinter,
|
|
NULL,
|
|
NULL,
|
|
PRINTER_CHANGE_SET_PRINTER_DRIVER,
|
|
pSpool->pIniSpooler );
|
|
}
|
|
|
|
//
|
|
// Now if there are any Jobs waiting for these changes because of
|
|
// DevQueryPrint fix them as well
|
|
//
|
|
pIniJob = pIniPrinter->pIniFirstJob;
|
|
while (pIniJob) {
|
|
if (pIniJob->Status & JOB_BLOCKED_DEVQ) {
|
|
pIniJob->Status &= ~JOB_BLOCKED_DEVQ;
|
|
FreeSplStr(pIniJob->pStatus);
|
|
pIniJob->pStatus = NULL;
|
|
|
|
SetPrinterChange(pIniJob->pIniPrinter,
|
|
pIniJob,
|
|
NVJobStatusAndString,
|
|
PRINTER_CHANGE_SET_JOB,
|
|
pIniJob->pIniPrinter->pIniSpooler );
|
|
}
|
|
pIniJob = pIniJob->pIniNextJob;
|
|
}
|
|
|
|
CHECK_SCHEDULER();
|
|
|
|
|
|
Done:
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
GetServerKeyHandle(
|
|
PINISPOOLER pIniSpooler,
|
|
REG_PRINT_KEY eKey,
|
|
HKEY *phKey,
|
|
PINISPOOLER* ppIniSpoolerOut
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
HANDLE hToken;
|
|
*ppIniSpoolerOut = NULL;
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
switch (eKey) {
|
|
case REG_PRINT:
|
|
|
|
*phKey = pIniSpooler->hckRoot;
|
|
*ppIniSpoolerOut = pIniSpooler;
|
|
|
|
break;
|
|
|
|
case REG_PRINTERS:
|
|
|
|
*phKey = pIniSpooler->hckPrinters;
|
|
*ppIniSpoolerOut = pIniSpooler;
|
|
|
|
break;
|
|
|
|
case REG_PROVIDERS:
|
|
|
|
rc = SplRegCreateKey( pIniSpooler->hckRoot,
|
|
pIniSpooler->pszRegistryProviders,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
phKey,
|
|
NULL,
|
|
pIniSpooler);
|
|
|
|
*ppIniSpoolerOut = pIniSpooler;
|
|
|
|
break;
|
|
|
|
default:
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CloseServerKeyHandle(
|
|
REG_PRINT_KEY eKey,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
HANDLE hToken = NULL;
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
switch (eKey) {
|
|
case REG_PRINT:
|
|
break;
|
|
|
|
case REG_PRINTERS:
|
|
break;
|
|
|
|
case REG_PROVIDERS:
|
|
SplRegCloseKey( hKey, pIniSpooler );
|
|
break;
|
|
|
|
default:
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetDefaultSpoolDirectory(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
LPWSTR pszNewSpoolDir = NULL;
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
|
|
if ( pIniSpooler == NULL )
|
|
{
|
|
//
|
|
// This check is probably not needed.
|
|
// Old code was checking for NULL so instead of just removing it I
|
|
// changed it to an assert and fail gracefully w/o crash
|
|
//
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
SPLASSERT(pIniSpooler != NULL);
|
|
}
|
|
else if (!pData || wcslen((LPWSTR)pData) > MAX_PATH - 12)
|
|
{
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else if ( !(pszNewSpoolDir = AllocSplStr((LPWSTR) pData)) )
|
|
{
|
|
rc = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// Create the directory with the proper security, or fail trying
|
|
//
|
|
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
if ( !CreateDirectory(pszNewSpoolDir, &SecurityAttributes) )
|
|
{
|
|
rc = GetLastError();
|
|
//
|
|
// If the directory already exists it is not a failure
|
|
//
|
|
if ( rc == ERROR_ALREADY_EXISTS )
|
|
{
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
else if ( rc == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// Don't rely on last error being set
|
|
//
|
|
rc = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
LocalFree(SecurityAttributes.lpSecurityDescriptor);
|
|
}
|
|
|
|
if ( rc == ERROR_SUCCESS )
|
|
{
|
|
EnterSplSem();
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
FreeSplStr(pIniSpooler->pDefaultSpoolDir);
|
|
pIniSpooler->pDefaultSpoolDir = pszNewSpoolDir;
|
|
pszNewSpoolDir = NULL;
|
|
|
|
if ( pIniSpooler->hFilePool != INVALID_HANDLE_VALUE )
|
|
{
|
|
(VOID) ChangeFilePoolBasePath(pIniSpooler->hFilePool,
|
|
pIniSpooler->pDefaultSpoolDir);
|
|
}
|
|
}
|
|
LeaveSplSem();
|
|
}
|
|
|
|
FreeSplStr(pszNewSpoolDir);
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetPortThreadPriority(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD))) {
|
|
|
|
dwPortThreadPriority = *(LPDWORD)pData;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetSchedulerThreadPriority(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD))) {
|
|
|
|
dwSchedulerThreadPriority = *(LPDWORD)pData;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetBeepEnabled(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->dwBeepEnabled = *(LPDWORD)pData;
|
|
|
|
// Make it 1 or 0
|
|
pIniSpooler->dwBeepEnabled = !!pIniSpooler->dwBeepEnabled;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetRetryPopup(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->bEnableRetryPopups = *(LPDWORD) pData;
|
|
// Make it 1 or 0
|
|
pIniSpooler->bEnableRetryPopups = !!pIniSpooler->bEnableRetryPopups;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetNetPopup(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->bEnableNetPopups = *(LPDWORD) pData;
|
|
// Make it 1 or 0
|
|
pIniSpooler->bEnableNetPopups = !!pIniSpooler->bEnableNetPopups;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetEventLog(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->dwEventLogging = *(LPDWORD) pData;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RegSetNetPopupToComputer(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->bEnableNetPopupToComputer = *(LPDWORD) pData;
|
|
|
|
// Make it 1 or 0
|
|
pIniSpooler->bEnableNetPopupToComputer = !!pIniSpooler->bEnableNetPopupToComputer;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RegSetRestartJobOnPoolError(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->dwRestartJobOnPoolTimeout = *(LPDWORD) pData;
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetRestartJobOnPoolEnabled(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
BOOL rc;
|
|
|
|
rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
|
|
|
|
if ((rc == ERROR_SUCCESS) &&
|
|
(cbData >= sizeof(DWORD)) &&
|
|
pIniSpooler) {
|
|
|
|
pIniSpooler->bRestartJobOnPoolEnabled = *(LPDWORD) pData;
|
|
|
|
// Make it 1 or 0
|
|
pIniSpooler->bRestartJobOnPoolEnabled = !!pIniSpooler->bRestartJobOnPoolEnabled;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
RegSetNoRemoteDriver(
|
|
LPWSTR pValueName,
|
|
DWORD dwType,
|
|
LPBYTE pData,
|
|
DWORD cbData,
|
|
HKEY hKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
DWORD
|
|
PrinterNonRegGetDefaultSpoolDirectory(
|
|
PSPOOL pSpool,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
WCHAR szDefaultSpoolDirectory[MAX_PATH];
|
|
DWORD cch;
|
|
|
|
cch = GetPrinterDirectory( pSpool->pIniPrinter,
|
|
FALSE,
|
|
szDefaultSpoolDirectory,
|
|
COUNTOF(szDefaultSpoolDirectory),
|
|
pSpool->pIniSpooler );
|
|
if(!cch) {
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
*pcbNeeded = ( cch + 1 ) * sizeof( szDefaultSpoolDirectory[0] );
|
|
*pType = REG_SZ;
|
|
|
|
if( nSize < *pcbNeeded ){
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
wcscpy( (LPWSTR)pData, szDefaultSpoolDirectory );
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
PrinterNonRegGetChangeId(
|
|
PSPOOL pSpool,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
LPDWORD pdwChangeID = (LPDWORD)pData;
|
|
DWORD dwRetval = ERROR_INVALID_PARAMETER;
|
|
|
|
//
|
|
// We need a valid handle, piniPrinter
|
|
//
|
|
if (pSpool && pSpool->pIniPrinter)
|
|
{
|
|
if (pcbNeeded)
|
|
{
|
|
*pcbNeeded = sizeof(pSpool->pIniPrinter->cChangeID);
|
|
}
|
|
|
|
//
|
|
// The type is optional.
|
|
//
|
|
if (pType)
|
|
{
|
|
*pType = REG_DWORD;
|
|
}
|
|
|
|
//
|
|
// Is the provided buffer large enough.
|
|
//
|
|
if (nSize < sizeof(pSpool->pIniPrinter->cChangeID))
|
|
{
|
|
dwRetval = ERROR_MORE_DATA;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Is the provided buffer valid.
|
|
//
|
|
if (pdwChangeID)
|
|
{
|
|
//
|
|
// Get the printer change id. We really would like
|
|
// more granularity on this. Just knowing if something
|
|
// changed about this printer is very general.
|
|
//
|
|
*pdwChangeID = pSpool->pIniPrinter->cChangeID;
|
|
dwRetval = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwRetval;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NonRegGetDNSMachineName(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
DWORD cChars;
|
|
if(!pIniSpooler || !pIniSpooler->pszFullMachineName) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
cChars = wcslen(pIniSpooler->pszFullMachineName);
|
|
*pcbNeeded = ( cChars + 1 ) * sizeof( WCHAR );
|
|
*pType = REG_SZ;
|
|
|
|
if( nSize < *pcbNeeded ){
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
wcscpy( (LPWSTR)pData, _wcslwr(pIniSpooler->pszFullMachineName) );
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
NonRegDsPresent(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
HANDLE hToken = NULL;
|
|
|
|
*pcbNeeded = sizeof(DWORD);
|
|
*pType = REG_DWORD;
|
|
|
|
if (nSize < sizeof(DWORD))
|
|
return ERROR_MORE_DATA;
|
|
|
|
hToken = RevertToPrinterSelf();
|
|
|
|
*(PDWORD) pData = IsDsPresent();
|
|
|
|
if (hToken)
|
|
ImpersonatePrinterClient(hToken);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDsPresent(
|
|
)
|
|
{
|
|
DOMAIN_CONTROLLER_INFO *pDCI = NULL;
|
|
BOOL bDsPresent;
|
|
DWORD dwRet;
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
|
|
|
|
|
|
// Get Domain name
|
|
dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole);
|
|
|
|
bDsPresent = (dwRet == ERROR_SUCCESS &&
|
|
pDsRole->MachineRole != DsRole_RoleStandaloneServer &&
|
|
pDsRole->MachineRole != DsRole_RoleStandaloneWorkstation);
|
|
|
|
if (pDsRole) {
|
|
DsRoleFreeMemory((PVOID) pDsRole);
|
|
}
|
|
|
|
if (bDsPresent) {
|
|
if (DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pDCI) == ERROR_SUCCESS)
|
|
bDsPresent = !!(pDCI->Flags & DS_DS_FLAG);
|
|
else
|
|
bDsPresent = FALSE;
|
|
|
|
if (pDCI)
|
|
NetApiBufferFree(pDCI);
|
|
}
|
|
|
|
return bDsPresent;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NonRegDsPresentForUser(
|
|
PINISPOOLER pIniSpooler,
|
|
LPDWORD pType,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
WCHAR pUserName[MAX_PATH + 1];
|
|
PWSTR pszUserName = pUserName;
|
|
DWORD cchUserName = MAX_PATH + 1;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PWSTR pszDomain;
|
|
DOMAIN_CONTROLLER_INFO *pDCI = NULL;
|
|
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
|
|
*pcbNeeded = sizeof(DWORD);
|
|
*pType = REG_DWORD;
|
|
|
|
if (nSize < sizeof(DWORD))
|
|
return ERROR_MORE_DATA;
|
|
|
|
|
|
// GetUserNameEx returns "Domain\User" in pszUserName (e.g.: NTDEV\swilson)
|
|
if (!GetUserNameEx(NameSamCompatible, pszUserName, &cchUserName)) {
|
|
if (cchUserName > MAX_PATH + 1) {
|
|
|
|
pszUserName = AllocSplMem(cchUserName);
|
|
if (!pszUserName || !GetUserNameEx(NameSamCompatible, pszUserName, &cchUserName)) {
|
|
dwError = GetLastError();
|
|
goto error;
|
|
}
|
|
|
|
} else {
|
|
dwError = GetLastError();
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
// Chop off user name
|
|
pszDomain = wcschr(pszUserName, L'\\');
|
|
|
|
SPLASSERT(pszDomain);
|
|
|
|
if (pszDomain) { // pszDomain should never be NULL, but just in case...
|
|
*pszDomain = L'\0';
|
|
} else {
|
|
*(PDWORD) pData = 0;
|
|
goto error;
|
|
}
|
|
|
|
// If domain is same a machine name, then we're logged on locally
|
|
nSize = COUNTOF(szComputerName);
|
|
if (GetComputerName(szComputerName, &nSize) && !wcscmp(szComputerName, pszUserName)) {
|
|
*(PDWORD) pData = 0;
|
|
goto error;
|
|
}
|
|
|
|
pszDomain = pszUserName;
|
|
|
|
if (DsGetDcName(NULL, pszDomain, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pDCI) == ERROR_SUCCESS)
|
|
*(PDWORD) pData = !!(pDCI->Flags & DS_DS_FLAG);
|
|
|
|
error:
|
|
|
|
if (pDCI)
|
|
NetApiBufferFree(pDCI);
|
|
|
|
if (pszUserName != pUserName)
|
|
FreeSplMem(pszUserName);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|