NT4/private/windows/spooler/localspl/prndata.c
2020-09-30 17:12:29 +02:00

994 lines
25 KiB
C

/*++
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
--*/
#include <precomp.h>
#define OPEN_PORT_TIMEOUT_VALUE 3000 // 3 seconds
#define DELETE_PRINTER_DATA 0
#define SET_PRINTER_DATA 1
DWORD
SetPrinterDataPrinter(
HANDLE hPrinter,
LPWSTR pValueName,
DWORD Type,
LPBYTE pData,
DWORD cbData,
BOOL bSet
);
typedef enum {
REG_PRINT,
REG_PRINTERS,
REG_PROVIDERS
} REG_PRINT_KEY;
DWORD
GetServerKeyHandle(
PINISPOOLER pIniSpooler,
REG_PRINT_KEY eKey,
HKEY *hPrintKey
);
DWORD
RegSetDefaultSpoolDirectory(
LPWSTR pValueName,
DWORD dwType,
LPBYTE pData,
DWORD cbData,
HKEY hKey
);
DWORD
RegSetBasic(
LPWSTR pValueName,
DWORD dwType,
LPBYTE pData,
DWORD cbData,
HKEY hKey
);
DWORD
NonRegGetSchedulerThreadPriorityDefault(
PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
);
DWORD
NonRegGetPortThreadPriorityDefault(
PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
);
DWORD
NonRegGetArchitecture(
PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
);
typedef struct {
LPWSTR pValue;
BOOL (*pSet) ( LPWSTR pValueName,
DWORD dwType,
LPBYTE pData,
DWORD cbData,
HKEY *hKey
);
REG_PRINT_KEY eKey;
} SERVER_DATA, *PSERVER_DATA;
typedef struct {
LPWSTR pValue;
DWORD (*pGet)( PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
);
} NON_REGISTRY_DATA, *PNON_REGISTRY_DATA;
SERVER_DATA gpServerRegistry[] = {{SPLREG_DEFAULT_SPOOL_DIRECTORY, RegSetDefaultSpoolDirectory, REG_PRINTERS},
{SPLREG_PORT_THREAD_PRIORITY, RegSetBasic, REG_PRINT},
{SPLREG_SCHEDULER_THREAD_PRIORITY, RegSetBasic, REG_PRINT},
{SPLREG_BEEP_ENABLED, RegSetBasic, REG_PRINT},
{SPLREG_NET_POPUP, RegSetBasic, REG_PROVIDERS},
{SPLREG_EVENT_LOG, RegSetBasic, REG_PROVIDERS},
{SPLREG_MAJOR_VERSION, NULL, REG_PRINT},
{SPLREG_MINOR_VERSION, NULL, REG_PRINT},
{SPLREG_NO_REMOTE_PRINTER_DRIVERS, RegSetBasic, REG_PRINT},
{0,0,0}};
NON_REGISTRY_DATA gpNonRegistryData[] = {{SPLREG_PORT_THREAD_PRIORITY_DEFAULT, NonRegGetPortThreadPriorityDefault},
{SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT, NonRegGetSchedulerThreadPriorityDefault},
{SPLREG_ARCHITECTURE, NonRegGetArchitecture},
{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->fn.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->fn.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 ) {
//
// 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
}
EnterSplSem();
if ( !OpenMonitorPort(pIniPort, pIniLangMonitor,
pIniPrinter->pName, FALSE) ) {
SetEvent(pIniPort->hWaitToOpenOrClose);
goto Cleanup; //Inside CS but already set the event
}
LeaveSplSem();
}
SplOutSem();
if ( !pIniLangMonitor )
pIniLangMonitor = pIniPort->pIniMonitor;
if ( (*pIniLangMonitor->fn.pfnGetPrinterDataFromPort)(pIniPort->hPort,
0,
pszValueName,
NULL,
0,
(LPWSTR)pData,
cbBuf,
pcbNeeded) ) {
rc = ERROR_SUCCESS;
} else {
rc = GetLastError();
}
//
// 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
SplGetPrinterData(
HANDLE hPrinter,
LPWSTR 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
PNON_REGISTRY_DATA pNonReg;
HKEY hPrintKey;
PINIPRINTER pIniPrinter;
HKEY hKey;
DWORD dwType;
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)) {
if ((rc = GetServerKeyHandle(pSpool->pIniSpooler, pRegistry->eKey, &hPrintKey)) == ERROR_SUCCESS) {
*pcbNeeded = nSize;
rc = RegQueryValueEx(hPrintKey, pValueName, 0, pType, pData, pcbNeeded);
RegCloseKey(hPrintKey);
}
break;
}
}
if (!pRegistry->pValue) { // May be a non-registry entry
for (pNonReg = gpNonRegistryData ; pNonReg->pValue ; ++pNonReg) {
if (!_wcsicmp(pNonReg->pValue, pValueName)) {
rc = (*pNonReg->pGet)(pSpool->pIniSpooler, &dwType, pData, nSize, pcbNeeded);
if (pType)
*pType = dwType;
break;
}
}
if (!pNonReg->pValue) {
rc = ERROR_INVALID_PARAMETER;
}
}
// Printer handle
} else {
EnterSplSem();
pIniPrinter = pSpool->pIniPrinter;
SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
LeaveSplSem();
rc = ERROR_INVALID_PRINTER_STATE;
} else {
SPLASSERT(pIniPrinter->hPrinterDataKey);
if ( AccessGranted(SPOOLER_OBJECT_PRINTER,
PRINTER_ACCESS_ADMINISTER,
pSpool ) ) {
rc = GetPrinterDataFromPort(pIniPrinter,
pValueName,
pData,
nSize,
pcbNeeded);
}
hKey = pSpool->pIniPrinter->hPrinterDataKey;
LeaveSplSem();
if ( rc == ERROR_SUCCESS ) {
*pType = REG_BINARY;
(VOID)SetPrinterDataPrinter(hPrinter,
pValueName,
*pType,
pData,
*pcbNeeded,
SET_PRINTER_DATA);
} else if ( rc != ERROR_INSUFFICIENT_BUFFER ) {
*pcbNeeded = nSize;
rc = RegQueryValueEx(hKey, pValueName, 0, pType, pData, pcbNeeded);
}
}
}
SplOutSem();
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;
PINIPRINTER pIniPrinter;
if (!ValidateSpoolHandle(pSpool, 0)) {
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 {
SPLASSERT(pIniPrinter->hPrinterDataKey);
hKey = pSpool->pIniPrinter->hPrinterDataKey;
LeaveSplSem();
if (!cbValueName && !cbData) { // Both sizes are NULL, so user wants to get buffer sizes
rc = RegQueryInfoKey( hKey, // Key
NULL, // lpClass
NULL, // lpcbClass
NULL, // lpReserved
NULL, // lpcSubKeys
NULL, // lpcbMaxSubKeyLen
NULL, // lpcbMaxClassLen
NULL, // lpcValues
pcbValueName, // lpcbMaxValueNameLen
pcbData, // lpcbMaxValueLen
NULL, // lpcbSecurityDescriptor
NULL // lpftLastWriteTime
);
*pcbValueName = (*pcbValueName + 1)*sizeof(WCHAR);
} else {
*pcbValueName = cbValueName/sizeof(WCHAR);
*pcbData = cbData;
rc = RegEnumValue( hKey,
dwIndex,
pValueName,
pcbValueName,
NULL,
pType,
pData,
pcbData
);
*pcbValueName = (*pcbValueName + 1)*sizeof(WCHAR);
}
}
return rc;
}
DWORD
SplDeletePrinterData(
HANDLE hPrinter,
LPWSTR pValueName
)
{
PSPOOL pSpool = (PSPOOL)hPrinter;
DWORD rc = ERROR_INVALID_HANDLE;
if (!ValidateSpoolHandle(pSpool, 0)) {
return rc;
}
rc = SetPrinterDataPrinter(hPrinter, pValueName, 0, NULL, 0, DELETE_PRINTER_DATA);
return rc;
}
DWORD
SplSetPrinterData(
HANDLE hPrinter,
LPWSTR pValueName,
DWORD Type,
LPBYTE pData,
DWORD cbData
)
{
PSPOOL pSpool = (PSPOOL)hPrinter;
DWORD rc = ERROR_INVALID_HANDLE;
if (!ValidateSpoolHandle(pSpool, 0)) {
return rc;
}
if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
SERVER_ACCESS_ADMINISTER,
NULL, pSpool->pIniSpooler)) {
rc = ERROR_ACCESS_DENIED;
} else {
rc = SetPrinterDataServer(pSpool->pIniSpooler, pValueName, Type, pData, cbData);
}
} else {
rc = SetPrinterDataPrinter(hPrinter, pValueName, Type, pData, cbData, SET_PRINTER_DATA);
}
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;
PINIPRINTER pIniPrinter;
PINIJOB pIniJob;
PSERVER_DATA pRegistry; // points to table of Print Server registry entries
HKEY hKey;
// 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)) == ERROR_SUCCESS) {
hToken = RevertToPrinterSelf();
if (pRegistry->pSet) {
rc = (*pRegistry->pSet)(pValueName, Type, pData, cbData, hKey);
}
else {
rc = ERROR_INVALID_PARAMETER;
}
RegCloseKey(hKey);
ImpersonatePrinterClient(hToken);
}
break;
}
}
if (!pRegistry->pValue) {
rc = ERROR_INVALID_PARAMETER;
}
}
return rc;
}
DWORD
SetPrinterDataPrinter(
HANDLE hPrinter,
LPWSTR pValueName,
DWORD Type,
LPBYTE pData,
DWORD cbData,
BOOL bSet // SET_PRINTER_DATA or DELETE_PRINTER_DATA
)
{
PSPOOL pSpool = (PSPOOL)hPrinter;
LPWSTR pKeyName;
DWORD rc = ERROR_INVALID_HANDLE;
HANDLE hToken;
PINIPRINTER pIniPrinter;
PINIJOB pIniJob;
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )){
goto Done;
}
EnterSplSem();
pIniPrinter = pSpool->pIniPrinter;
SPLASSERT(pIniPrinter &&
pIniPrinter->signature == IP_SIGNATURE &&
pIniPrinter->hPrinterDataKey);
if ( !AccessGranted( SPOOLER_OBJECT_PRINTER,
PRINTER_ACCESS_ADMINISTER,
pSpool ) ) {
rc = ERROR_ACCESS_DENIED;
goto DoneFromSplSem;
}
hToken = RevertToPrinterSelf();
if (bSet == SET_PRINTER_DATA) {
rc = RegSetValueEx(pIniPrinter->hPrinterDataKey,
pValueName,
0,
Type,
pData,
cbData );
} else {
rc = RegDeleteValue(pIniPrinter->hPrinterDataKey, pValueName );
}
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();
DoneFromSplSem:
LeaveSplSem();
Done:
return rc;
}
DWORD
GetServerKeyHandle(
PINISPOOLER pIniSpooler,
REG_PRINT_KEY eKey,
HKEY *hKey
)
{
DWORD rc;
HANDLE hToken;
hToken = RevertToPrinterSelf();
switch (eKey) {
case REG_PRINT:
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryRoot, 0,
KEY_ALL_ACCESS, hKey);
break;
case REG_PRINTERS:
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryPrinters, 0,
KEY_ALL_ACCESS, hKey);
break;
case REG_PROVIDERS:
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryProviders, 0,
KEY_ALL_ACCESS, hKey);
break;
default:
rc = ERROR_INVALID_PARAMETER;
break;
}
ImpersonatePrinterClient(hToken);
return rc;
}
DWORD
RegSetDefaultSpoolDirectory(
LPWSTR pValueName,
DWORD dwType,
LPBYTE pData,
DWORD cbData,
HKEY hKey
)
{
DWORD rc;
BOOL bStatus;
SECURITY_ATTRIBUTES SecurityAttributes;
// Create the directory with the proper security, or fail trying
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
SecurityAttributes.bInheritHandle = FALSE;
// CreateDirectory returns FALSE if directory already exists.
bStatus = CreateDirectory((LPWSTR) pData, &SecurityAttributes);
if (bStatus) {
if (!RemoveDirectory((LPWSTR) pData)) { // Doesn't really matter if we can remove it or not
DBGMSG(DBG_WARNING, ("RemoveDirectory failed: %ws %d\n", pData, GetLastError()));
}
}
else {
rc = GetLastError(); // Get last error on CreateDirectory failure
if (rc != ERROR_ALREADY_EXISTS) {
DBGMSG(DBG_WARNING, ("PRNDATA: Could not create default spool directory %ws %d\n", pData, rc));
}
}
if (bStatus || rc == ERROR_ALREADY_EXISTS) {
rc = RegSetValueEx(hKey, pValueName, 0, dwType, pData, cbData);
}
LocalFree(SecurityAttributes.lpSecurityDescriptor);
if (rc == ERROR_SUCCESS) {
rc = ERROR_SUCCESS_RESTART_REQUIRED;
}
return rc;
}
DWORD
RegSetBasic(
LPWSTR pValueName,
DWORD dwType,
LPBYTE pData,
DWORD cbData,
HKEY hKey
)
{
BOOL rc;
rc = RegSetValueEx(hKey, pValueName, 0, dwType, pData, cbData);
if (rc == ERROR_SUCCESS) {
rc = ERROR_SUCCESS_RESTART_REQUIRED;
}
return rc;
}
DWORD
NonRegGetPortThreadPriorityDefault(
PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
)
{
DWORD rc;
if (nSize >= sizeof DEFAULT_PORT_THREAD_PRIORITY) {
*pData = DEFAULT_PORT_THREAD_PRIORITY;
*pcbNeeded = sizeof DEFAULT_PORT_THREAD_PRIORITY;
rc = ERROR_SUCCESS;
} else {
*pcbNeeded = sizeof DEFAULT_PORT_THREAD_PRIORITY;
rc = ERROR_MORE_DATA;
}
*pType = REG_DWORD;
return rc;
}
DWORD
NonRegGetSchedulerThreadPriorityDefault(
PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
)
{
DWORD rc;
if (nSize >= sizeof DEFAULT_SCHEDULER_THREAD_PRIORITY) {
*pData = DEFAULT_SCHEDULER_THREAD_PRIORITY;
*pcbNeeded = sizeof DEFAULT_SCHEDULER_THREAD_PRIORITY;
rc = ERROR_SUCCESS;
} else {
*pcbNeeded = sizeof DEFAULT_SCHEDULER_THREAD_PRIORITY;
rc = ERROR_MORE_DATA;
}
*pType = REG_DWORD;
return rc;
}
DWORD
NonRegGetArchitecture(
PINISPOOLER pIniSpooler,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
)
{
DWORD rc = ERROR_SUCCESS;
DWORD cbName = 0;
*pType = REG_SZ;
cbName = wcslen((LPWSTR) szEnvironment)*sizeof(WCHAR) + sizeof(WCHAR);
*pcbNeeded = cbName;
if (*pcbNeeded <= nSize) {
wcscpy((LPWSTR) pData, (LPWSTR) szEnvironment);
rc = ERROR_SUCCESS;
} else {
rc = ERROR_MORE_DATA;
}
return rc;
}