Source code of Windows XP (NT5)
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

/*++
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;
}