|
|
/*++
Copyright (c) 1990-1994 Microsoft Corporation All rights reserved
Module Name:
SplInit.c
Abstract:
Initialize the spooler.
Author:
Environment:
User Mode -Win32
Revision History:
4-Jan-1999 Khaleds Added Code for optimiziting the load time of the spooler by decoupling the startup dependency between spoolsv and spoolss
--*/
#include "precomp.h"
#pragma hdrstop
#include "local.h"
LPWSTR szDevice = L"Device"; LPWSTR szPrinters = L"Printers";
LPWSTR szDeviceOld = L"DeviceOld"; LPWSTR szNULL = L"";
LPWSTR szPorts=L"Ports";
LPWSTR szWinspool = L"winspool"; LPWSTR szNetwork = L"Ne"; LPWSTR szTimeouts = L",15,45";
LPWSTR szDotDefault = L".Default";
LPWSTR szRegDevicesPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices"; LPWSTR szRegWindowsPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; LPWSTR szRegPrinterPortsPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\PrinterPorts"; LPWSTR szCurrentVersionPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion"; LPWSTR szDevModes2Path = L"Printers\\DevModes2"; PrintSpoolerServerExports *gpServerExports = NULL;
typedef struct INIT_REG_USER {
HKEY hKeyUser; HKEY hKeyWindows; HKEY hKeyDevices; HKEY hKeyPrinterPorts; BOOL bFoundPrinter; BOOL bDefaultSearch; BOOL bDefaultFound; BOOL bFirstPrinterFound;
DWORD dwNetCounter;
WCHAR szFirstPrinter[MAX_PATH * 2]; WCHAR szDefaultPrinter[MAX_PATH * 2];
} INIT_REG_USER, *PINIT_REG_USER;
//
// Prototypes
//
BOOL SplRegCopy( PINIT_REG_USER pUser, HKEY hMcConnectionKey );
BOOL InitializeRegUser( LPWSTR szSubKey, PINIT_REG_USER pUser );
VOID FreeRegUser( PINIT_REG_USER pUser );
BOOL SetupRegForUsers( PINIT_REG_USER pUsers, DWORD cUsers );
VOID UpdateUsersDefaultPrinter( IN PINIT_REG_USER pUser, IN BOOL bFindDefault );
HRESULT IsUsersDefaultPrinter( IN PINIT_REG_USER pUser, IN PCWSTR pszPrinterName );
DWORD ReadPrinters( PINIT_REG_USER pUser, DWORD Flags, PDWORD pcbPrinters, LPBYTE* ppPrinters );
BOOL UpdatePrinterInfo( const PINIT_REG_USER pCurUser, LPCWSTR pPrinterName, LPCWSTR pPorts, PDWORD pdwNetId );
BOOL EnumerateConnectedPrinters( LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned, HKEY hKeyUser );
VOID RegClearKey( HKEY hKey );
LPWSTR CheckBadPortName( LPWSTR pszPort );
BOOL UpdateLogonTimeStamp( void );
BOOL SpoolerInitAll( VOID ) { DWORD dwError; WCHAR szClass[MAX_PATH]; WCHAR szSubKey[MAX_PATH]; DWORD cUsers; DWORD cSubKeys; DWORD cchMaxSubkey; DWORD cchMaxClass; DWORD cValues; DWORD cbMaxValueData; DWORD cbSecurityDescriptor; DWORD cchClass; DWORD cchMaxValueName; FILETIME ftLastWriteTime;
BOOL bSuccess; DWORD cchSubKey;
PINIT_REG_USER pUsers; PINIT_REG_USER pCurUser;
DWORD i;
cchClass = COUNTOF(szClass);
dwError = RegQueryInfoKey(HKEY_USERS, szClass, &cchClass, NULL, &cSubKeys, &cchMaxSubkey, &cchMaxClass, &cValues, &cchMaxValueName, &cbMaxValueData, &cbSecurityDescriptor, &ftLastWriteTime);
if (dwError) { SetLastError( dwError ); DBGMSG(DBG_WARNING, ("SpoolerIniAll failed RegQueryInfoKey HKEY_USERS error %d\n", dwError)); return FALSE; }
if (cSubKeys < 1) return TRUE;
pUsers = AllocSplMem(cSubKeys * sizeof(pUsers[0]));
if (!pUsers) { DBGMSG(DBG_WARNING, ("SpoolerIniAll failed to allocate pUsers error %d\n", dwError)); return FALSE; }
for (i=0, pCurUser=pUsers, cUsers=0; i< cSubKeys; i++) {
cchSubKey = COUNTOF(szSubKey);
dwError = RegEnumKeyEx(HKEY_USERS, i, szSubKey, &cchSubKey, NULL, NULL, NULL, &ftLastWriteTime); if ( dwError ) {
//
// We possibly should return an error here if we fail to initiatise a
// user.
//
DBGMSG( DBG_WARNING, ("SpoolerInitAll failed RegEnumKeyEx HKEY_USERS %ws %d %d\n", szSubKey, i, dwError)); SetLastError( dwError );
} else {
if (!_wcsicmp(szSubKey, szDotDefault) || wcschr(szSubKey, L'_')) { continue; }
if (InitializeRegUser(szSubKey, pCurUser)) {
pCurUser++; cUsers++; } } }
bSuccess = SetupRegForUsers(pUsers, cUsers);
for (i=0; i< cUsers; i++) FreeRegUser(&pUsers[i]);
//
// In case we are starting after the user has logged in, inform
// all applications that there may be printers now.
//
BroadcastMessage(BROADCAST_TYPE_CHANGEDEFAULT, 0, 0, 0);
FreeSplMem(pUsers);
if ( !bSuccess ) { DBGMSG( DBG_WARNING, ("SpoolerInitAll failed error %d\n", GetLastError() )); } else { DBGMSG( DBG_TRACE, ("SpoolerInitAll Success\n" )); }
return bSuccess; }
BOOL DeleteOldPerMcConnections( HKEY hConnectionKey, HKEY hMcConnectionKey )
/*++
Function Description - Deletes the existing permachine connections from hConnectionKey
Parameters - hConnectionKey - handle to hUserKey\Printers\Connections
Return Values - TRUE if success FALSE otherwise.
--*/
{ BOOL bReturn = TRUE; struct Node { struct Node *pNext; LPTSTR szPrinterName; } *phead = NULL,*ptemp = NULL;
LONG lstatus; DWORD dwRegIndex,dwNameSize,cbdata,dwquerylocal,dwType; WCHAR szPrinterName[MAX_UNC_PRINTER_NAME]; HKEY hPrinterKey;
// Before deleting the old permachine connections, we need to record all them into
// a list. This is required because, the subkeys should not be deleted while they
// are being enumerated.
// Identifying permachine connections and saving the printernames in a list.
for (dwRegIndex = 0;
dwNameSize = COUNTOF(szPrinterName), ((lstatus = RegEnumKeyEx(hConnectionKey, dwRegIndex, szPrinterName, &dwNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS);
++dwRegIndex) {
if (RegOpenKeyEx(hConnectionKey, szPrinterName, 0, KEY_READ, &hPrinterKey) != ERROR_SUCCESS) {
bReturn = FALSE; goto CleanUp; }
dwquerylocal = 0; cbdata = sizeof(dwquerylocal);
RegQueryValueEx(hPrinterKey, L"LocalConnection", NULL, &dwType, (LPBYTE)&dwquerylocal, &cbdata);
RegCloseKey(hPrinterKey);
//
// See if it's a LocalConnection, and if it exists on the current
// machine. We don't want to delete it if it is a per-machine
// connection, since we want to keep the associated per-user
// DevMode.
//
if( ERROR_SUCCESS == RegOpenKeyEx( hMcConnectionKey, szPrinterName, 0, KEY_READ, &hPrinterKey )) { //
// The per-machine key exists. Close it and don't bother
// deleting this connection.
//
RegCloseKey( hPrinterKey );
} else {
//
// It's not a per-machine connection. Prepare to delete it.
//
if (dwquerylocal == 1) { if (!(ptemp = (struct Node *) AllocSplMem(sizeof(struct Node)))) { bReturn = FALSE; goto CleanUp; } ptemp->pNext = phead; phead = ptemp; if (!(ptemp->szPrinterName = AllocSplStr(szPrinterName))) { bReturn = FALSE; goto CleanUp; } } } }
if (lstatus != ERROR_NO_MORE_ITEMS) { bReturn = FALSE; goto CleanUp; }
// Deleting old permachine connections. The printer names are stored in the
// list pointed to by phead.
for (ptemp = phead; ptemp != NULL; ptemp = ptemp->pNext) { if (RegDeleteKey(hConnectionKey,ptemp->szPrinterName) != ERROR_SUCCESS) { bReturn = FALSE; goto CleanUp; } }
CleanUp:
while (ptemp = phead) { phead = phead->pNext; if (ptemp->szPrinterName) FreeSplStr(ptemp->szPrinterName); FreeSplMem(ptemp); }
return bReturn;
}
BOOL AddNewPerMcConnections( HKEY hConnectionKey, HKEY hMcConnectionKey )
/*++
Function Description - Adds per-machine connections to the user hive if the connection does not already exist.
Parameters - hConnectionKey - handle to hUserKey\Printers\Connections hMcConnectionKey - handle to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Control\Print\Connections Return Values - TRUE if success FALSE otherwise. --*/
{ DWORD dwRegIndex,dwNameSize,cbdata,dwType,dwlocalconnection = 1; WCHAR szPrinterName[MAX_UNC_PRINTER_NAME]; WCHAR szConnData[MAX_UNC_PRINTER_NAME]; LONG lstatus; BOOL bReturn = TRUE; HKEY hNewConnKey = NULL, hPrinterKey = NULL;
for (dwRegIndex = 0;
dwNameSize = COUNTOF(szPrinterName), ((lstatus = RegEnumKeyEx(hMcConnectionKey, dwRegIndex, szPrinterName, &dwNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS);
++dwRegIndex) {
RegOpenKeyEx(hConnectionKey,szPrinterName,0,KEY_READ,&hNewConnKey);
if (hNewConnKey == NULL) {
// Connection does not exist. Add one.
if (RegCreateKeyEx(hConnectionKey, szPrinterName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hNewConnKey, NULL) || RegOpenKeyEx(hMcConnectionKey, szPrinterName, 0, KEY_READ, &hPrinterKey)) {
bReturn = FALSE; goto CleanUp; }
cbdata = sizeof(szConnData); if (RegQueryValueEx(hPrinterKey,L"Server",NULL,&dwType,(LPBYTE)szConnData,&cbdata) || RegSetValueEx(hNewConnKey,L"Server",0,dwType,(LPBYTE)szConnData,cbdata)) {
bReturn = FALSE; goto CleanUp; }
cbdata = sizeof(szConnData); if (RegQueryValueEx(hPrinterKey,L"Provider",NULL,&dwType,(LPBYTE)szConnData,&cbdata) || RegSetValueEx(hNewConnKey,L"Provider",0,dwType,(LPBYTE)szConnData,cbdata) || RegSetValueEx(hNewConnKey,L"LocalConnection",0,REG_DWORD, (LPBYTE)&dwlocalconnection,sizeof(dwlocalconnection))) {
bReturn = FALSE; goto CleanUp; }
RegCloseKey(hPrinterKey); hPrinterKey = NULL; }
RegCloseKey(hNewConnKey); hNewConnKey = NULL; }
if (lstatus != ERROR_NO_MORE_ITEMS) { bReturn = FALSE; }
CleanUp:
if (hNewConnKey) { RegCloseKey(hNewConnKey); } if (hPrinterKey) { RegCloseKey(hPrinterKey); }
return bReturn;
}
BOOL SplRegCopy( PINIT_REG_USER pUser, HKEY hMcConnectionKey)
/*++
Function Description - Removes old permachine connections for pUser and adds the new permachine connections from hMcConnectionKey
Parameters - pUser - pointer to INIT_REG_USER which contains hUserKey. hMcConnectionKey - handle to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Control\Print\Connections
Return Values - TRUE if success FALSE otherwise.
--*/
{ LONG lstatus; BOOL bReturn = TRUE; WCHAR szRegistryConnections[] = L"Printers\\Connections"; HKEY hConnectionKey = NULL;
// Create (if not already present) and open Connections subkey
lstatus = RegCreateKeyEx(pUser->hKeyUser, szRegistryConnections, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hConnectionKey, NULL);
if (lstatus != ERROR_SUCCESS) { bReturn = FALSE; goto CleanUp; }
if (!DeleteOldPerMcConnections(hConnectionKey,hMcConnectionKey) || !AddNewPerMcConnections(hConnectionKey,hMcConnectionKey)) { bReturn = FALSE; }
CleanUp:
if (hConnectionKey) { RegCloseKey(hConnectionKey); }
return bReturn; }
BOOL SetupRegForUsers( PINIT_REG_USER pUsers, DWORD cUsers) { DWORD cbPrinters; DWORD cPrinters; PBYTE pPrinters; HKEY hMcConnectionKey = NULL; WCHAR szMachineConnections[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Connections";
#define pPrinters2 ((PPRINTER_INFO_2)pPrinters)
#define pPrinters4 ((PPRINTER_INFO_4)pPrinters)
DWORD i, j; LPWSTR pszPort;
//
// Read in local printers.
//
cbPrinters = 1000; pPrinters = AllocSplMem(cbPrinters);
if (!pPrinters) return FALSE;
if (cPrinters = ReadPrinters(NULL, PRINTER_ENUM_LOCAL, &cbPrinters, &pPrinters)) {
for (i=0; i< cUsers; i++) {
for(j=0; j< cPrinters; j++) {
if( pPrinters2[j].Attributes & PRINTER_ATTRIBUTE_NETWORK ){
//
// Use NeXX:
//
pszPort = NULL;
} else {
pszPort = CheckBadPortName( pPrinters2[j].pPortName ); }
UpdatePrinterInfo( &pUsers[i], pPrinters2[j].pPrinterName, pszPort, &(pUsers[i].dwNetCounter)); } } }
// Open the Key containing the current list of per-machine connections.
RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMachineConnections, 0, KEY_READ , &hMcConnectionKey);
for (i=0; i< cUsers; i++) {
// Copy Per Machine Connections into the user hive
SplRegCopy(&pUsers[i], hMcConnectionKey);
if (cPrinters = ReadPrinters(&pUsers[i], PRINTER_ENUM_CONNECTIONS, &cbPrinters, &pPrinters)) {
for(j=0; j< cPrinters; j++) {
UpdatePrinterInfo(&pUsers[i], pPrinters4[j].pPrinterName, NULL, &(pUsers[i].dwNetCounter)); } } }
// Close the handle to Per Machine Connections.
if (hMcConnectionKey) RegCloseKey(hMcConnectionKey);
FreeSplMem(pPrinters);
for (i=0; i< cUsers; i++) {
UpdateUsersDefaultPrinter(&pUsers[i], FALSE); } return TRUE;
#undef pPrinters2
#undef pPrinters4
}
VOID UpdateUsersDefaultPrinter( IN PINIT_REG_USER pUser, IN BOOL bFindDefault ) /*++
Routine Description:
Updates the default printer using the information in the current users reg structure. If the bFindDefault flag is specified then a default printer is located. The method for this is first see if there is currently a default printer, then user this. If a default printer is not found then located the first printer in devices section, again if on exists.
Arguments:
pUser - Information about the current user, reg keys etc. This routine assumes that hKeyWindows and hKeyDevices are valid opened registry keys, with read access. bFindDefault - TRUE located a default printer, FALSE the default printer is already specified in the users reg structure.
Return Value:
Nothing.
--*/ { LPWSTR pszNewDefault = NULL;
//
// If a request to find the default printer.
//
if (bFindDefault) {
DWORD dwError = ERROR_SUCCESS; DWORD cbData = sizeof(pUser->szDefaultPrinter);
//
// Check if there is a default printer.
//
dwError = RegQueryValueEx(pUser->hKeyWindows, szDevice, NULL, NULL, (PBYTE)pUser->szDefaultPrinter, &cbData);
//
// If the device key was read and there is a non null string
// as the default printer name.
//
if (dwError == ERROR_SUCCESS && pUser->szDefaultPrinter[0] != L'\0') {
pUser->bDefaultFound = TRUE;
} else {
//
// Default was not found.
//
pUser->bDefaultFound = FALSE;
//
// If a first printer was not found.
//
if (!pUser->bFirstPrinterFound) { DWORD cchPrinterLen = 0; WCHAR szBuffer [MAX_PATH*2]; DWORD cbDataBuffer = sizeof(szBuffer);
DBGMSG(DBG_TRACE, ("UpdateUsersDefaultPrinter default printer not found.\n"));
cchPrinterLen = cbData = COUNTOF(pUser->szFirstPrinter);
//
// Default printer was not found, find any printer
// in the devices section of the registry.
//
dwError = RegEnumValue(pUser->hKeyDevices, 0, pUser->szFirstPrinter, &cbData, NULL, NULL, (PBYTE)szBuffer, &cbDataBuffer);
if (dwError == ERROR_SUCCESS) {
StringCchCat(pUser->szFirstPrinter, cchPrinterLen, L","); StringCchCat(pUser->szFirstPrinter, cchPrinterLen, szBuffer);
pUser->bFirstPrinterFound = TRUE;
} else {
DBGMSG(DBG_WARNING, ("UpdateUsersDefaultPrinter no printer found in devices section.\n"));
pUser->bFirstPrinterFound = FALSE; } } } }
//
// If default wasn't present, and we did get a first printer,
// make this the default.
//
if (!pUser->bDefaultFound) {
if (pUser->bFirstPrinterFound) {
pszNewDefault = pUser->szFirstPrinter; }
} else {
//
// Write out default.
//
pszNewDefault = pUser->szDefaultPrinter; }
if (pszNewDefault) {
RegSetValueEx(pUser->hKeyWindows, szDevice, 0, REG_SZ, (PBYTE)pszNewDefault, (wcslen(pszNewDefault) + 1) * sizeof(pszNewDefault[0])); } }
HRESULT IsUsersDefaultPrinter( IN PINIT_REG_USER pUser, IN PCWSTR pszPrinterName ) /*++
Routine Description:
Asks if the users default printer matched the specified printer name.
Arguments:
pCurUser - Information about the current user, reg keys etc. This routine assumes that hKeyWindows is a valid opened registry keys, with at least read access. pszPrinterName - Printer name to check if it is the default printer.
Return Value:
S_OK the printer name is the default, S_FALSE the printer is not the default, An HRESULT error code if an error occurrs attempting to determine the default printer.
--*/ { HRESULT hr = E_INVALIDARG;
if (pszPrinterName) {
WCHAR szBuffer[MAX_PATH*2]; DWORD dwError = ERROR_SUCCESS; DWORD cbData = sizeof(szBuffer);
//
// Read the default printer, if one exists.
//
dwError = RegQueryValueEx(pUser->hKeyWindows, szDevice, NULL, NULL, (PBYTE)szBuffer, &cbData);
if (dwError == ERROR_SUCCESS) {
PWSTR p = wcschr(szBuffer, L',');
if (p) {
*p = 0; }
hr = !_wcsicmp(pszPrinterName, szBuffer) ? S_OK : S_FALSE;
} else {
hr = HRESULT_FROM_WIN32(dwError);
} }
return hr; }
DWORD ReadPrinters( PINIT_REG_USER pUser, DWORD Flags, PDWORD pcbPrinters, LPBYTE* ppPrinters) { BOOL bSuccess = FALSE; DWORD cbNeeded = 0; DWORD cPrinters = 0; LPBYTE pPrinters = NULL;
if (Flags == PRINTER_ENUM_CONNECTIONS) {
bSuccess = EnumerateConnectedPrinters(*ppPrinters, *pcbPrinters, &cbNeeded, &cPrinters, pUser->hKeyUser); } else {
bSuccess = EnumPrinters(Flags, NULL, 2, (PBYTE)*ppPrinters, *pcbPrinters, &cbNeeded, &cPrinters); }
if (!bSuccess && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
//
// If not enough space, realloc.
//
if (pPrinters = ReallocSplMem(*ppPrinters, 0, cbNeeded)) { *ppPrinters = pPrinters; pPrinters = NULL; *pcbPrinters = cbNeeded; bSuccess = TRUE; } else { bSuccess = FALSE; }
if (bSuccess) { if (Flags == PRINTER_ENUM_CONNECTIONS) {
bSuccess = EnumerateConnectedPrinters(*ppPrinters, *pcbPrinters, &cbNeeded, &cPrinters, pUser->hKeyUser); } else {
bSuccess = EnumPrinters(Flags, NULL, 2, (PBYTE)*ppPrinters, *pcbPrinters, &cbNeeded, &cPrinters); } } } if (!bSuccess) { cPrinters = 0; }
return cPrinters; }
BOOL UpdatePrinterInfo( const PINIT_REG_USER pCurUser, LPCWSTR pszPrinterName, LPCWSTR pszPort, PDWORD pdwNetId ) /*++
Routine Description:
Updates the printer information in the registry win.ini.
Arguments:
pCurUser - Information about the user. The following fields are used by this routine:
hKeyDevices hKeyPrinterPorts bDefaultSearch (if true, read/writes to:) bDefaultFound szDefaultPrinter bFirstPrinterFound (if false, writes to:) szFirstPrinter
pszPort - Port name. If NULL, generates NetId.
pdwNetId - Pointer to NetId counter. This value will be incremented if the NetId is used.
Return Value:
--*/ { WCHAR szBuffer[MAX_PATH * 2]; LPWSTR p;
DWORD dwCount = 0; DWORD cbLen;
if (!pszPrinterName) return FALSE;
//
// Now we know the spooler is up, since the EnumPrinters succeeded.
// Update all sections.
//
StringCchPrintf(szBuffer, MAX_PATH*2, L"%s,", szWinspool);
dwCount = wcslen(szBuffer);
if( !pszPort ){
HANDLE hToken;
StringCchPrintf(&szBuffer[dwCount], MAX_PATH*2 - dwCount, L"%s%.2d:", szNetwork, *pdwNetId);
(*pdwNetId)++;
//
// !! HACK !!
//
// Works 3.0b expects the printer port entry in the
// [ports] section.
//
// This is in the per-machine part of the registry, but we
// are updating it for each user. Fix later.
//
// We never remove the NeXX: entries from [ports] but since
// the same entries will be used by all users, this is ok.
//
hToken = RevertToPrinterSelf();
WriteProfileString( szPorts, &szBuffer[dwCount], L"" );
if( hToken ){ ImpersonatePrinterClient( hToken ); } //
// End Works 3.0b HACK
//
} else {
StringCchCopy(&szBuffer[dwCount], MAX_PATH*2 - dwCount, pszPort);
//
// Get the first port only.
//
if ( p = wcschr(&szBuffer[dwCount], L',') ) *p = 0; }
cbLen = (wcslen(szBuffer)+1) * sizeof(szBuffer[0]);
RegSetValueEx(pCurUser->hKeyDevices, pszPrinterName, 0, REG_SZ, (PBYTE)szBuffer, cbLen);
//
// If the user has a default printer specified, then verify
// that it exists.
//
if (pCurUser->bDefaultSearch) {
pCurUser->bDefaultFound = !_wcsicmp(pszPrinterName, pCurUser->szDefaultPrinter);
if (pCurUser->bDefaultFound) {
StringCchPrintf(pCurUser->szDefaultPrinter, COUNTOF(pCurUser->szDefaultPrinter), L"%s,%s", pszPrinterName, szBuffer);
pCurUser->bDefaultSearch = FALSE; } }
if (!pCurUser->bFirstPrinterFound) {
StringCchPrintf(pCurUser->szFirstPrinter, COUNTOF(pCurUser->szFirstPrinter), L"%s,%s", pszPrinterName, szBuffer);
pCurUser->bFirstPrinterFound = TRUE; }
StringCchCat(szBuffer, COUNTOF(szBuffer), szTimeouts);
RegSetValueEx(pCurUser->hKeyPrinterPorts, pszPrinterName, 0, REG_SZ, (PBYTE)szBuffer, (wcslen(szBuffer)+1) * sizeof(szBuffer[0]));
return TRUE; }
VOID SpoolerInitAsync( PINIT_REG_USER pUser )
/*++
Routine Description: Asynchronously sets up the user's registry information
Arguments: pUser - pointer to INIT_REG_USER containing user keys
Return Values: NONE
--*/
{ if (InitializeRegUser(NULL, pUser)) { SetupRegForUsers(pUser, 1); }
BroadcastMessage(BROADCAST_TYPE_CHANGEDEFAULT,0,0,0); FreeRegUser(pUser); FreeSplMem(pUser); }
BOOL SpoolerInit( VOID )
/*++
Routine Description: Initializes just the current user.
Arguments: NONE
Return Value: TRUE if initialized or async init thread created successfully FALSE otherwise
--*/
{ BOOL bSuccess = FALSE; DWORD dwThreadId; HANDLE hThread; PINIT_REG_USER pUser;
UpdateLogonTimeStamp ();
if (!(pUser = AllocSplMem(sizeof(INIT_REG_USER)))) {
return FALSE; }
//
// Enum just the current user.
//
pUser->hKeyUser = GetClientUserHandle(KEY_READ|KEY_WRITE);
if (pUser->hKeyUser) { if (!Initialized) { //
// Process the user initialization asynchronously if the spooler
// hasn't completed it's initialization.
//
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SpoolerInitAsync, (LPVOID) pUser, 0, &dwThreadId);
if (hThread) { //
// We assume that the async thread will succeed.
//
CloseHandle(hThread); bSuccess = TRUE; } else { FreeRegUser(pUser); FreeSplMem(pUser); } } else { if (InitializeRegUser(NULL, pUser)) { bSuccess = SetupRegForUsers(pUser, 1); }
FreeRegUser(pUser); FreeSplMem(pUser); } }
return bSuccess; }
BOOL InitializeRegUser( LPWSTR pszSubKey, PINIT_REG_USER pUser ) /*++
Routine Description:
Initialize a single users structure based on a HKEY_USERS subkey.
Arguments:
pszSubKey - if non-NULL initialize hKeyUser to this key
pUser - structure to initialize
Return Value:
--*/ { HKEY hKey; LPWSTR p; BOOL bSecurityLoaded = FALSE, rc = FALSE; DWORD cbData, cbSD = 0, dwError, dwDisposition; PSECURITY_DESCRIPTOR pSD = NULL;
HANDLE hToken = NULL;
if (pszSubKey) {
if (RegOpenKeyEx(HKEY_USERS, pszSubKey, 0, KEY_READ|KEY_WRITE, &pUser->hKeyUser) != ERROR_SUCCESS) {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegOpenKeyEx failed\n")); goto Fail; } }
//
// Now attempt to set the security on these two keys to
// their parent key.
//
dwError = RegOpenKeyEx(pUser->hKeyUser, szCurrentVersionPath, 0, KEY_READ, &hKey);
if (!dwError) {
dwError = RegGetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pSD, &cbSD);
if (dwError == ERROR_INSUFFICIENT_BUFFER) {
pSD = AllocSplMem(cbSD);
if (pSD) {
if (!RegGetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pSD, &cbSD)){
bSecurityLoaded = TRUE;
} else {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegGetKeySecurity failed %d\n", GetLastError())); } } } else {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegGetKeySecurity failed %d\n", dwError)); } RegCloseKey(hKey);
} else {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegOpenKeyEx CurrentVersion failed %d\n", dwError)); }
hToken = RevertToPrinterSelf();
//
// Open up the right keys.
//
if (RegCreateKeyEx(pUser->hKeyUser, szRegDevicesPath, 0, szNULL, 0, KEY_ALL_ACCESS, NULL, &pUser->hKeyDevices, &dwDisposition) != ERROR_SUCCESS) {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegCreateKeyEx1 failed %d\n", GetLastError()));
goto Fail; }
if (bSecurityLoaded) { RegSetKeySecurity(pUser->hKeyDevices, DACL_SECURITY_INFORMATION, pSD); }
if (RegCreateKeyEx(pUser->hKeyUser, szRegPrinterPortsPath, 0, szNULL, 0, KEY_ALL_ACCESS, NULL, &pUser->hKeyPrinterPorts, &dwDisposition) != ERROR_SUCCESS) {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegCreateKeyEx2 failed %d\n", GetLastError()));
goto Fail; }
if (bSecurityLoaded) { RegSetKeySecurity(pUser->hKeyPrinterPorts, DACL_SECURITY_INFORMATION, pSD); }
//
// First, attempt to clear out the keys by deleting them.
//
RegClearKey(pUser->hKeyDevices); RegClearKey(pUser->hKeyPrinterPorts);
if (RegOpenKeyEx(pUser->hKeyUser, szRegWindowsPath, 0, KEY_READ|KEY_WRITE, &pUser->hKeyWindows) != ERROR_SUCCESS) {
DBGMSG(DBG_WARNING, ("InitializeRegUser: RegOpenKeyEx failed %d\n", GetLastError()));
goto Fail; }
pUser->bFoundPrinter = FALSE; pUser->bDefaultSearch = FALSE; pUser->bDefaultFound = FALSE; pUser->bFirstPrinterFound = FALSE; pUser->dwNetCounter = 0;
cbData = sizeof(pUser->szDefaultPrinter);
if (RegQueryValueEx(pUser->hKeyWindows, szDevice, NULL, NULL, (PBYTE)pUser->szDefaultPrinter, &cbData) == ERROR_SUCCESS) {
pUser->bDefaultSearch = TRUE; }
//
// Remove the Device= in [windows]
//
RegDeleteValue(pUser->hKeyWindows, szDevice);
if (!pUser->bDefaultSearch) {
//
// Attempt to read from saved location.
//
if (RegOpenKeyEx(pUser->hKeyUser, szPrinters, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
cbData = sizeof(pUser->szDefaultPrinter);
//
// Try reading szDeviceOld.
//
if (RegQueryValueEx( hKey, szDeviceOld, NULL, NULL, (PBYTE)pUser->szDefaultPrinter, &cbData) == ERROR_SUCCESS) {
pUser->bDefaultSearch = TRUE; }
RegCloseKey(hKey); } }
if ( pUser->bDefaultSearch ) { pUser->szDefaultPrinter[COUNTOF(pUser->szDefaultPrinter) - 1] = '\0'; if (p = wcschr(pUser->szDefaultPrinter, L',')) { *p = 0; } }
rc = TRUE;
Fail:
if (hToken) { ImpersonatePrinterClient(hToken); }
if (pSD) { FreeSplMem(pSD); }
if (!rc) FreeRegUser(pUser);
return rc; }
VOID FreeRegUser( PINIT_REG_USER pUser)
/*++
Routine Description:
Free up the INIT_REG_USER structure intialized by InitializeRegUser.
Arguments:
Return Value:
--*/
{ if (pUser->hKeyUser) { RegCloseKey(pUser->hKeyUser); pUser->hKeyUser = NULL; }
if (pUser->hKeyDevices) { RegCloseKey(pUser->hKeyDevices); pUser->hKeyDevices = NULL; }
if (pUser->hKeyPrinterPorts) { RegCloseKey(pUser->hKeyPrinterPorts); pUser->hKeyPrinterPorts = NULL; }
if (pUser->hKeyWindows) { RegCloseKey(pUser->hKeyWindows); pUser->hKeyWindows = NULL; } }
VOID UpdatePrinterRegAll( LPWSTR pszPrinterName, LPWSTR pszPort, BOOL bDelete ) /*++
Routine Description:
Updates everyone's [devices] and [printerports] sections (for local printers only).
Arguments:
pszPrinterName - printer that has been added/deleted
pszPort - port name; if NULL, generate NetId
bDelete - if TRUE, delete entry instead of updating it.
Return Value:
--*/ { WCHAR szKey[MAX_PATH]; DWORD cchKey; DWORD i; FILETIME ftLastWriteTime; DWORD dwError;
//
// Go through all keys and fix them up.
//
for (i=0; TRUE; i++) {
cchKey = COUNTOF(szKey);
dwError = RegEnumKeyEx(HKEY_USERS, i, szKey, &cchKey, NULL, NULL, NULL, &ftLastWriteTime);
if (dwError != ERROR_SUCCESS) break;
if (!_wcsicmp(szKey, szDotDefault) || wcschr(szKey, L'_')) continue;
UpdatePrinterRegUser(NULL, szKey, pszPrinterName, pszPort, bDelete); } }
DWORD UpdatePrinterRegUser( HKEY hKeyUser, LPWSTR pszUserKey, LPWSTR pszPrinterName, LPWSTR pszPort, BOOL bDelete ) /*++
Routine Description:
Update one user's registry. The user is specified by either hKeyUser or pszUserKey.
Arguments:
hKeyUser - Clients user key (ignored if pszKey specified)
pszUserKey - Clients SID (Used if supplied instead of hKeyUser)
pszPrinterName - name of printe to add
pszPort - port name; if NULL, generate NetId
bDelete - if TRUE, delete entry instead of updating.
Return Value:
NOTE: We never cleanup [ports] since it is per-user EITHER hKeyUser or pszUserKey must be valid, but not both.
--*/ { HKEY hKeyClose = NULL; HKEY hKeyRoot; DWORD dwError; WCHAR szBuffer[MAX_PATH]; DWORD dwNetId;
INIT_REG_USER InitRegUser;
ZeroMemory(&InitRegUser, sizeof(InitRegUser));
InitRegUser.hKeyDevices = NULL; InitRegUser.hKeyPrinterPorts = NULL; InitRegUser.bDefaultSearch = FALSE; InitRegUser.bFirstPrinterFound = TRUE;
//
// Setup the registry keys.
//
if (pszUserKey) {
dwError = RegOpenKeyEx( HKEY_USERS, pszUserKey, 0, KEY_READ|KEY_WRITE, &hKeyRoot );
if (dwError != ERROR_SUCCESS) { goto Done; }
hKeyClose = hKeyRoot;
} else {
hKeyRoot = hKeyUser; }
dwError = RegOpenKeyEx(hKeyRoot, szRegDevicesPath, 0, KEY_READ|KEY_WRITE, &InitRegUser.hKeyDevices);
if (dwError != ERROR_SUCCESS) goto Done;
dwError = RegOpenKeyEx(hKeyRoot, szRegWindowsPath, 0, KEY_READ|KEY_WRITE, &InitRegUser.hKeyWindows);
if (dwError != ERROR_SUCCESS) goto Done;
//
// Setup [PrinterPorts]
//
dwError = RegOpenKeyEx(hKeyRoot, szRegPrinterPortsPath, 0, KEY_WRITE, &InitRegUser.hKeyPrinterPorts);
if (dwError != ERROR_SUCCESS) goto Done;
if (!bDelete) {
pszPort = CheckBadPortName( pszPort );
if( !pszPort ){ dwNetId = GetNetworkIdWorker(InitRegUser.hKeyDevices, pszPrinterName); }
InitRegUser.bFirstPrinterFound = FALSE;
UpdatePrinterInfo( &InitRegUser, pszPrinterName, pszPort, &dwNetId );
UpdateUsersDefaultPrinter( &InitRegUser, TRUE );
} else {
HKEY hKeyDevMode;
//
// Delete the entries.
//
RegDeleteValue(InitRegUser.hKeyDevices, pszPrinterName); RegDeleteValue(InitRegUser.hKeyPrinterPorts, pszPrinterName);
//
// Check if the printer we are deleting is currently the
// default printer.
//
if (IsUsersDefaultPrinter(&InitRegUser, pszPrinterName) == S_OK) {
//
// Remove the default printer from the registry.
//
RegDeleteValue(InitRegUser.hKeyWindows, szDevice); }
//
// Also delete DevModes2 entry from registry
//
dwError = RegOpenKeyEx( hKeyRoot, szDevModes2Path, 0, KEY_WRITE, &hKeyDevMode );
if (dwError == ERROR_SUCCESS) {
//
// Delete the devmode value entry for the particular printer
//
RegDeleteValue(hKeyDevMode, pszPrinterName); RegCloseKey(hKeyDevMode); }
//
// Remove the per-user DevMode.
//
bSetDevModePerUser( hKeyRoot, pszPrinterName, NULL ); }
Done:
if( InitRegUser.hKeyDevices ){ RegCloseKey( InitRegUser.hKeyDevices ); }
if( InitRegUser.hKeyWindows ){ RegCloseKey( InitRegUser.hKeyWindows ); }
if( InitRegUser.hKeyPrinterPorts ){ RegCloseKey( InitRegUser.hKeyPrinterPorts ); }
if( hKeyClose ){ RegCloseKey( hKeyClose ); }
return dwError; }
VOID RegClearKey( HKEY hKey ) { DWORD dwError; WCHAR szValue[MAX_PATH];
DWORD cchValue;
while (TRUE) {
cchValue = COUNTOF(szValue); dwError = RegEnumValue(hKey, 0, szValue, &cchValue, NULL, NULL, NULL, NULL);
if (dwError != ERROR_SUCCESS) {
if( dwError != ERROR_NO_MORE_ITEMS ){ DBGMSG( DBG_WARN, ( "RegClearKey: RegEnumValue failed %d\n", dwError )); } break; }
dwError = RegDeleteValue(hKey, szValue);
if( dwError != ERROR_SUCCESS) { DBGMSG( DBG_WARN, ( "RegClearKey: RegDeleteValue failed %d\n", dwError )); break; } } }
LPWSTR CheckBadPortName( LPWSTR pszPort ) /*++
Routine Description:
This routine checks whether a port name should be converted to NeXX:. Currently if the port is NULL, or "\\*," or has a space, we convert to NeXX.
Arguments:
pszPort - port to check
Return Value:
pszPort - if port is OK. NULL - if port needs to be converted
--*/
{ //
// If we have no pszPort, OR
// it begins with '\\' (as in \\server\share) OR
// it has a space in it OR
// it's length is greater than 5 ("LPT1:")
// Then
// use NeXX:
//
// Most 16 bit apps can't deal with long port names, since they
// allocate small buffers.
//
if( !pszPort || ( pszPort[0] == L'\\' && pszPort[1] == L'\\' ) || wcschr( pszPort, L' ' ) || wcslen( pszPort ) > 5 ){
return NULL; } return pszPort; }
BOOL UpdateLogonTimeStamp( void ) { long lstatus; HKEY hProvidersKey = NULL; FILETIME LogonTime;
LPWSTR szPrintProviders = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers"; LPWSTR szLogonTime = L"LogonTime";
GetSystemTimeAsFileTime (&LogonTime);
// Create (if not already present) and open Connections subkey
lstatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szPrintProviders, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hProvidersKey, NULL);
if (lstatus == ERROR_SUCCESS) {
lstatus = RegSetValueEx (hProvidersKey, szLogonTime, 0, REG_BINARY, (LPBYTE) &LogonTime, sizeof (FILETIME));
RegCloseKey(hProvidersKey); }
return lstatus == ERROR_SUCCESS; }
/*++
Routine Name
AllowRemoteCalls
Routine Description:
This chains into the server and tells it to allow remote calls on the RPC interface. Note that this is reference counted.
Arguments:
None
Return Value:
An HRESULT
--*/ HRESULT AllowRemoteCalls( VOID ) { HRESULT hr = (gpServerExports && gpServerExports->FnAllowRemoteCalls) ? S_OK : E_UNEXPECTED;
if (SUCCEEDED(hr)) { hr = gpServerExports->FnAllowRemoteCalls(); }
return hr; }
/*++
Routine Name
GetServerPolicy
Routine Description:
This chains into the server and gets a numeric policy read by the server.
Arguments:
pszPolicyName - policy name pValue - pointer to numeric value
Return Value:
An HRESULT
--*/ HRESULT GetServerPolicy( IN PCWSTR pszPolicyName, IN ULONG* pValue ) { HRESULT hr = (gpServerExports && gpServerExports->FnGetServerPolicy) ? S_OK : E_UNEXPECTED;
if (SUCCEEDED(hr)) { hr = (pValue && pszPolicyName) ? S_OK : E_POINTER;
if (SUCCEEDED(hr)) { hr = gpServerExports->FnGetServerPolicy(pszPolicyName, pValue); } }
return hr; }
|