/*++ Copyright (c) 1996 - 1998 Microsoft Corporation Module Name: config.c Abstract: Routines to do multiple hardware profile support for printing Author: Muhunthan Sivapragasam (MuhuntS) 07-Nov-96 (Rewrite from Win95) Revision History: --*/ #include #include "config.h" #include "clusspl.h" #include #define CM_REGSITRY_CONFIG 0x00000200 WCHAR cszPnPKey[] = L"PnPData"; WCHAR cszPrinter[] = L"Printer"; WCHAR cszPrinterOnLine[] = L"PrinterOnLine"; WCHAR cszDeviceInstanceId[] = L"DeviceInstanceId"; WCHAR cszRegistryConfig[] = L"System\\CurrentControlSet\\Hardware Profiles\\"; BOOL LoadSetupApiDll( PSETUPAPI_INFO pSetupInfo ) { UINT uOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); pSetupInfo->hSetupApi = LoadLibrary(L"setupapi"); SetErrorMode(uOldErrMode); if ( !pSetupInfo->hSetupApi ) return FALSE; (FARPROC) pSetupInfo->pfnDestroyDeviceInfoList = GetProcAddress(pSetupInfo->hSetupApi, "SetupDiDestroyDeviceInfoList"); (FARPROC) pSetupInfo->pfnGetClassDevs = GetProcAddress(pSetupInfo->hSetupApi, "SetupDiGetClassDevsA"); (FARPROC) pSetupInfo->pfnRemoveDevice = GetProcAddress(pSetupInfo->hSetupApi, "SetupDiRemoveDevice"); (FARPROC) pSetupInfo->pfnOpenDeviceInfo = GetProcAddress(pSetupInfo->hSetupApi, "SetupDiOpenDeviceInfoW"); if ( !pSetupInfo->pfnDestroyDeviceInfoList || !pSetupInfo->pfnGetClassDevs || !pSetupInfo->pfnRemoveDevice || !pSetupInfo->pfnOpenDeviceInfo ) { FreeLibrary(pSetupInfo->hSetupApi); pSetupInfo->hSetupApi = NULL; return FALSE; } return TRUE; } BOOL DeletePrinterDevNode( LPWSTR pszDeviceInstanceId ) { BOOL bRet = FALSE; HDEVINFO hDevInfo = INVALID_HANDLE_VALUE; SP_DEVINFO_DATA DevData; SETUPAPI_INFO SetupInfo; HANDLE UserToken; if ( !LoadSetupApiDll(&SetupInfo) ) return FALSE; UserToken = RevertToPrinterSelf(); hDevInfo = SetupInfo.pfnGetClassDevs((LPGUID)&GUID_DEVCLASS_PRINTER, NULL, INVALID_HANDLE_VALUE, 0); if ( hDevInfo == INVALID_HANDLE_VALUE ) goto Cleanup; DevData.cbSize = sizeof(DevData); if ( SetupInfo.pfnOpenDeviceInfo(hDevInfo, pszDeviceInstanceId, INVALID_HANDLE_VALUE, 0, &DevData) ) { bRet = SetupInfo.pfnRemoveDevice(hDevInfo, &DevData); } Cleanup: if ( hDevInfo != INVALID_HANDLE_VALUE ) SetupInfo.pfnDestroyDeviceInfoList(hDevInfo); if (!ImpersonatePrinterClient(UserToken)) { DBGMSG(DBG_ERROR, ("DeletePrinterDevNode: ImpersonatePrinterClient Failed. Error %d\n", GetLastError())); } FreeLibrary(SetupInfo.hSetupApi); return bRet; } LPWSTR GetPrinterDeviceInstanceId( PINIPRINTER pIniPrinter ) { WCHAR buf[MAX_PATH]; DWORD dwType, cbNeeded, dwReturn; HKEY hKey = NULL; LPWSTR pszDeviceInstanceId = NULL; SplInSem(); cbNeeded = sizeof(buf); if ( ERROR_SUCCESS == OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, cszPnPKey, TRUE) && ERROR_SUCCESS == SplRegQueryValue(hKey, cszDeviceInstanceId, &dwType, (LPBYTE)buf, &cbNeeded, pIniPrinter->pIniSpooler) && dwType == REG_SZ ) { pszDeviceInstanceId = AllocSplStr(buf); } if ( hKey ) SplRegCloseKey(hKey, pIniPrinter->pIniSpooler); return pszDeviceInstanceId; } BOOL DeleteIniPrinterDevNode( PINIPRINTER pIniPrinter ) { BOOL bRet = FALSE; LPWSTR pszStr = GetPrinterDeviceInstanceId(pIniPrinter); if ( pszStr ) { bRet = DeletePrinterDevNode(pszStr); FreeSplStr(pszStr); } return bRet; } VOID SplConfigChange( ) { PINIPRINTER pIniPrinter = NULL; BOOL bCheckScheduler = FALSE; HKEY hConfig = NULL; HKEY hKey; DWORD dwOnline, dwType, cbNeeded; EnterSplSem(); // // If we have no printers which are offline then we would not have // created the key at all // if ( RegCreateKeyEx(HKEY_CURRENT_CONFIG, ipszRegistryPrinters, 0, NULL, 0, KEY_READ, NULL, &hConfig, NULL) ) goto Cleanup; for ( pIniPrinter = pLocalIniSpooler->pIniPrinter ; pIniPrinter ; pIniPrinter = pIniPrinter->pNext ) { // // Don't consider printers that have invalid ports, these must always // stay offline until this is resolved. If the user explicitely turns // the port online, that is up to them. // UINT i = 0; // // If pIniPrinter->ppIniPorts is NULL, cPorts would be zero. // for(i = 0; i < pIniPrinter->cPorts; i++) { if (pIniPrinter->ppIniPorts[i]->Status & PP_PLACEHOLDER) { break; } } // // If we reached the end of the list, none of the ports were // placeholders. If we didn't go onto the next one. // if (i < pIniPrinter->cPorts) { continue; } if ( RegOpenKeyEx(hConfig, pIniPrinter->pName, 0, KEY_READ, &hKey) ) continue; // to next printer cbNeeded = sizeof(dwOnline); if ( ERROR_SUCCESS == SplRegQueryValue(hKey, cszPrinterOnLine, &dwType, (LPBYTE)&dwOnline, &cbNeeded, NULL) ) { if ( dwOnline ) { // // If any printers which are offline in current config // become online in the new config then we need to trigger // the scheduler // if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE ) { pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_WORK_OFFLINE; bCheckScheduler = TRUE; } } else { pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_WORK_OFFLINE; } } RegCloseKey(hKey); } if ( bCheckScheduler ) CHECK_SCHEDULER(); Cleanup: LeaveSplSem(); if ( hConfig ) RegCloseKey(hConfig); } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ DeletePrinterInAllConfigs Routine Description: Deletes a pIniPrinter from all the hardware profiles. Arguments: pIniPrinter - Printer to delete. Return Value: BOOL, TRUE = success, FALSE = FAILUER Last Error: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ BOOL DeletePrinterInAllConfigs( PINIPRINTER pIniPrinter ) { HKEY hConfig; WCHAR szSubKey[2 * MAX_PATH]; DWORD Config; DWORD Size; DWORD Status; SplInSem(); Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszRegistryConfig, 0, KEY_READ | KEY_WRITE | DELETE, &hConfig); if (Status != ERROR_SUCCESS) { DBGMSG(DBG_WARN, ("DeletePrinterInAllConfigs: RegOpenKey failed %d\n", Status)); } else { DWORD RegPrintersLen = wcslen(ipszRegistryPrinters); for (Config = 0; Size = (DWORD)(COUNTOF(szSubKey) - ( RegPrintersLen + wcslen(pIniPrinter->pName) +2)) , (Status = RegEnumKeyEx(hConfig, Config, szSubKey, &Size, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS; ++Config) { StrNCatBuff(szSubKey, COUNTOF(szSubKey), L"\\", ipszRegistryPrinters, L"\\", pIniPrinter->pName, NULL); Status = RegDeleteKey(hConfig, szSubKey); if (Status != ERROR_SUCCESS && Status != ERROR_FILE_NOT_FOUND) { DBGMSG( DBG_WARN, ("DeletePrinterInAllConfigs: RegDeleteKey failed %d\n", Status)); } } if (Status != ERROR_NO_MORE_ITEMS) { DBGMSG(DBG_WARN, ("DeletePrinterInAllConfigs: RegEnumKey failed %d\n", Status)); } RegCloseKey(hConfig); } return TRUE; } BOOL WritePrinterOnlineStatusInCurrentConfig( PINIPRINTER pIniPrinter ) { HKEY hKey = NULL; DWORD dwOnline, dwReturn; WCHAR szKey[2 * MAX_PATH]; HANDLE hToken; SplInSem(); hToken = RevertToPrinterSelf(); StrNCatBuff(szKey, COUNTOF(szKey), ipszRegistryPrinters, L"\\", pIniPrinter->pName, NULL); dwOnline = (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) ? 0 : 1; dwReturn = RegCreateKeyEx(HKEY_CURRENT_CONFIG, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL); if ( dwReturn == ERROR_SUCCESS ) dwReturn = RegSetValueEx(hKey, cszPrinterOnLine, 0, REG_DWORD, (LPBYTE)&dwOnline, sizeof(DWORD)); if ( hKey ) RegCloseKey(hKey); ImpersonatePrinterClient(hToken); return dwReturn == ERROR_SUCCESS; }