Leaked source code of windows server 2003
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.

1928 lines
48 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. SplInit.c
  6. Abstract:
  7. Initialize the spooler.
  8. Author:
  9. Environment:
  10. User Mode -Win32
  11. Revision History:
  12. 4-Jan-1999 Khaleds
  13. Added Code for optimiziting the load time of the spooler by decoupling
  14. the startup dependency between spoolsv and spoolss
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include "local.h"
  19. LPWSTR szDevice = L"Device";
  20. LPWSTR szPrinters = L"Printers";
  21. LPWSTR szDeviceOld = L"DeviceOld";
  22. LPWSTR szNULL = L"";
  23. LPWSTR szPorts=L"Ports";
  24. LPWSTR szWinspool = L"winspool";
  25. LPWSTR szNetwork = L"Ne";
  26. LPWSTR szTimeouts = L",15,45";
  27. LPWSTR szDotDefault = L".Default";
  28. LPWSTR szRegDevicesPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
  29. LPWSTR szRegWindowsPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
  30. LPWSTR szRegPrinterPortsPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\PrinterPorts";
  31. LPWSTR szCurrentVersionPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion";
  32. LPWSTR szDevModes2Path = L"Printers\\DevModes2";
  33. PrintSpoolerServerExports *gpServerExports = NULL;
  34. typedef struct INIT_REG_USER {
  35. HKEY hKeyUser;
  36. HKEY hKeyWindows;
  37. HKEY hKeyDevices;
  38. HKEY hKeyPrinterPorts;
  39. BOOL bFoundPrinter;
  40. BOOL bDefaultSearch;
  41. BOOL bDefaultFound;
  42. BOOL bFirstPrinterFound;
  43. DWORD dwNetCounter;
  44. WCHAR szFirstPrinter[MAX_PATH * 2];
  45. WCHAR szDefaultPrinter[MAX_PATH * 2];
  46. } INIT_REG_USER, *PINIT_REG_USER;
  47. //
  48. // Prototypes
  49. //
  50. BOOL
  51. SplRegCopy(
  52. PINIT_REG_USER pUser,
  53. HKEY hMcConnectionKey
  54. );
  55. BOOL
  56. InitializeRegUser(
  57. LPWSTR szSubKey,
  58. PINIT_REG_USER pUser
  59. );
  60. VOID
  61. FreeRegUser(
  62. PINIT_REG_USER pUser
  63. );
  64. BOOL
  65. SetupRegForUsers(
  66. PINIT_REG_USER pUsers,
  67. DWORD cUsers
  68. );
  69. VOID
  70. UpdateUsersDefaultPrinter(
  71. IN PINIT_REG_USER pUser,
  72. IN BOOL bFindDefault
  73. );
  74. HRESULT
  75. IsUsersDefaultPrinter(
  76. IN PINIT_REG_USER pUser,
  77. IN PCWSTR pszPrinterName
  78. );
  79. DWORD
  80. ReadPrinters(
  81. PINIT_REG_USER pUser,
  82. DWORD Flags,
  83. PDWORD pcbPrinters,
  84. LPBYTE* ppPrinters
  85. );
  86. BOOL
  87. UpdatePrinterInfo(
  88. const PINIT_REG_USER pCurUser,
  89. LPCWSTR pPrinterName,
  90. LPCWSTR pPorts,
  91. PDWORD pdwNetId
  92. );
  93. BOOL
  94. EnumerateConnectedPrinters(
  95. LPBYTE pPrinter,
  96. DWORD cbBuf,
  97. LPDWORD pcbNeeded,
  98. LPDWORD pcReturned,
  99. HKEY hKeyUser
  100. );
  101. VOID
  102. RegClearKey(
  103. HKEY hKey
  104. );
  105. LPWSTR
  106. CheckBadPortName(
  107. LPWSTR pszPort
  108. );
  109. BOOL
  110. UpdateLogonTimeStamp(
  111. void
  112. );
  113. BOOL
  114. SpoolerInitAll(
  115. VOID
  116. )
  117. {
  118. DWORD dwError;
  119. WCHAR szClass[MAX_PATH];
  120. WCHAR szSubKey[MAX_PATH];
  121. DWORD cUsers;
  122. DWORD cSubKeys;
  123. DWORD cchMaxSubkey;
  124. DWORD cchMaxClass;
  125. DWORD cValues;
  126. DWORD cbMaxValueData;
  127. DWORD cbSecurityDescriptor;
  128. DWORD cchClass;
  129. DWORD cchMaxValueName;
  130. FILETIME ftLastWriteTime;
  131. BOOL bSuccess;
  132. DWORD cchSubKey;
  133. PINIT_REG_USER pUsers;
  134. PINIT_REG_USER pCurUser;
  135. DWORD i;
  136. cchClass = COUNTOF(szClass);
  137. dwError = RegQueryInfoKey(HKEY_USERS,
  138. szClass,
  139. &cchClass,
  140. NULL,
  141. &cSubKeys,
  142. &cchMaxSubkey,
  143. &cchMaxClass,
  144. &cValues,
  145. &cchMaxValueName,
  146. &cbMaxValueData,
  147. &cbSecurityDescriptor,
  148. &ftLastWriteTime);
  149. if (dwError) {
  150. SetLastError( dwError );
  151. DBGMSG(DBG_WARNING, ("SpoolerIniAll failed RegQueryInfoKey HKEY_USERS error %d\n", dwError));
  152. return FALSE;
  153. }
  154. if (cSubKeys < 1)
  155. return TRUE;
  156. pUsers = AllocSplMem(cSubKeys * sizeof(pUsers[0]));
  157. if (!pUsers) {
  158. DBGMSG(DBG_WARNING, ("SpoolerIniAll failed to allocate pUsers error %d\n", dwError));
  159. return FALSE;
  160. }
  161. for (i=0, pCurUser=pUsers, cUsers=0;
  162. i< cSubKeys;
  163. i++) {
  164. cchSubKey = COUNTOF(szSubKey);
  165. dwError = RegEnumKeyEx(HKEY_USERS,
  166. i,
  167. szSubKey,
  168. &cchSubKey,
  169. NULL,
  170. NULL,
  171. NULL,
  172. &ftLastWriteTime);
  173. if ( dwError ) {
  174. //
  175. // We possibly should return an error here if we fail to initiatise a
  176. // user.
  177. //
  178. DBGMSG( DBG_WARNING, ("SpoolerInitAll failed RegEnumKeyEx HKEY_USERS %ws %d %d\n", szSubKey, i, dwError));
  179. SetLastError( dwError );
  180. } else {
  181. if (!_wcsicmp(szSubKey, szDotDefault) || wcschr(szSubKey, L'_')) {
  182. continue;
  183. }
  184. if (InitializeRegUser(szSubKey, pCurUser)) {
  185. pCurUser++;
  186. cUsers++;
  187. }
  188. }
  189. }
  190. bSuccess = SetupRegForUsers(pUsers,
  191. cUsers);
  192. for (i=0; i< cUsers; i++)
  193. FreeRegUser(&pUsers[i]);
  194. //
  195. // In case we are starting after the user has logged in, inform
  196. // all applications that there may be printers now.
  197. //
  198. BroadcastMessage(BROADCAST_TYPE_CHANGEDEFAULT,
  199. 0,
  200. 0,
  201. 0);
  202. FreeSplMem(pUsers);
  203. if ( !bSuccess ) {
  204. DBGMSG( DBG_WARNING, ("SpoolerInitAll failed error %d\n", GetLastError() ));
  205. } else {
  206. DBGMSG( DBG_TRACE, ("SpoolerInitAll Success\n" ));
  207. }
  208. return bSuccess;
  209. }
  210. BOOL
  211. DeleteOldPerMcConnections(
  212. HKEY hConnectionKey,
  213. HKEY hMcConnectionKey
  214. )
  215. /*++
  216. Function Description - Deletes the existing permachine connections from hConnectionKey
  217. Parameters - hConnectionKey - handle to hUserKey\Printers\Connections
  218. Return Values - TRUE if success
  219. FALSE otherwise.
  220. --*/
  221. {
  222. BOOL bReturn = TRUE;
  223. struct Node {
  224. struct Node *pNext;
  225. LPTSTR szPrinterName;
  226. } *phead = NULL,*ptemp = NULL;
  227. LONG lstatus;
  228. DWORD dwRegIndex,dwNameSize,cbdata,dwquerylocal,dwType;
  229. WCHAR szPrinterName[MAX_UNC_PRINTER_NAME];
  230. HKEY hPrinterKey;
  231. // Before deleting the old permachine connections, we need to record all them into
  232. // a list. This is required because, the subkeys should not be deleted while they
  233. // are being enumerated.
  234. // Identifying permachine connections and saving the printernames in a list.
  235. for (dwRegIndex = 0;
  236. dwNameSize = COUNTOF(szPrinterName),
  237. ((lstatus = RegEnumKeyEx(hConnectionKey, dwRegIndex, szPrinterName,
  238. &dwNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS);
  239. ++dwRegIndex) {
  240. if (RegOpenKeyEx(hConnectionKey, szPrinterName, 0, KEY_READ, &hPrinterKey)
  241. != ERROR_SUCCESS) {
  242. bReturn = FALSE;
  243. goto CleanUp;
  244. }
  245. dwquerylocal = 0;
  246. cbdata = sizeof(dwquerylocal);
  247. RegQueryValueEx(hPrinterKey, L"LocalConnection", NULL, &dwType,
  248. (LPBYTE)&dwquerylocal, &cbdata);
  249. RegCloseKey(hPrinterKey);
  250. //
  251. // See if it's a LocalConnection, and if it exists on the current
  252. // machine. We don't want to delete it if it is a per-machine
  253. // connection, since we want to keep the associated per-user
  254. // DevMode.
  255. //
  256. if( ERROR_SUCCESS == RegOpenKeyEx( hMcConnectionKey,
  257. szPrinterName,
  258. 0,
  259. KEY_READ,
  260. &hPrinterKey )) {
  261. //
  262. // The per-machine key exists. Close it and don't bother
  263. // deleting this connection.
  264. //
  265. RegCloseKey( hPrinterKey );
  266. } else {
  267. //
  268. // It's not a per-machine connection. Prepare to delete it.
  269. //
  270. if (dwquerylocal == 1) {
  271. if (!(ptemp = (struct Node *) AllocSplMem(sizeof(struct Node)))) {
  272. bReturn = FALSE;
  273. goto CleanUp;
  274. }
  275. ptemp->pNext = phead;
  276. phead = ptemp;
  277. if (!(ptemp->szPrinterName = AllocSplStr(szPrinterName))) {
  278. bReturn = FALSE;
  279. goto CleanUp;
  280. }
  281. }
  282. }
  283. }
  284. if (lstatus != ERROR_NO_MORE_ITEMS) {
  285. bReturn = FALSE;
  286. goto CleanUp;
  287. }
  288. // Deleting old permachine connections. The printer names are stored in the
  289. // list pointed to by phead.
  290. for (ptemp = phead; ptemp != NULL; ptemp = ptemp->pNext) {
  291. if (RegDeleteKey(hConnectionKey,ptemp->szPrinterName) != ERROR_SUCCESS) {
  292. bReturn = FALSE;
  293. goto CleanUp;
  294. }
  295. }
  296. CleanUp:
  297. while (ptemp = phead) {
  298. phead = phead->pNext;
  299. if (ptemp->szPrinterName) FreeSplStr(ptemp->szPrinterName);
  300. FreeSplMem(ptemp);
  301. }
  302. return bReturn;
  303. }
  304. BOOL
  305. AddNewPerMcConnections(
  306. HKEY hConnectionKey,
  307. HKEY hMcConnectionKey
  308. )
  309. /*++
  310. Function Description - Adds per-machine connections to the user hive if the connection
  311. does not already exist.
  312. Parameters - hConnectionKey - handle to hUserKey\Printers\Connections
  313. hMcConnectionKey - handle to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
  314. Control\Print\Connections
  315. Return Values - TRUE if success
  316. FALSE otherwise.
  317. --*/
  318. { DWORD dwRegIndex,dwNameSize,cbdata,dwType,dwlocalconnection = 1;
  319. WCHAR szPrinterName[MAX_UNC_PRINTER_NAME];
  320. WCHAR szConnData[MAX_UNC_PRINTER_NAME];
  321. LONG lstatus;
  322. BOOL bReturn = TRUE;
  323. HKEY hNewConnKey = NULL, hPrinterKey = NULL;
  324. for (dwRegIndex = 0;
  325. dwNameSize = COUNTOF(szPrinterName),
  326. ((lstatus = RegEnumKeyEx(hMcConnectionKey, dwRegIndex, szPrinterName,
  327. &dwNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS);
  328. ++dwRegIndex) {
  329. RegOpenKeyEx(hConnectionKey,szPrinterName,0,KEY_READ,&hNewConnKey);
  330. if (hNewConnKey == NULL) {
  331. // Connection does not exist. Add one.
  332. if (RegCreateKeyEx(hConnectionKey,
  333. szPrinterName,
  334. 0,
  335. NULL,
  336. REG_OPTION_NON_VOLATILE,
  337. KEY_WRITE,
  338. NULL,
  339. &hNewConnKey,
  340. NULL) ||
  341. RegOpenKeyEx(hMcConnectionKey,
  342. szPrinterName,
  343. 0,
  344. KEY_READ,
  345. &hPrinterKey)) {
  346. bReturn = FALSE;
  347. goto CleanUp;
  348. }
  349. cbdata = sizeof(szConnData);
  350. if (RegQueryValueEx(hPrinterKey,L"Server",NULL,&dwType,(LPBYTE)szConnData,&cbdata)
  351. || RegSetValueEx(hNewConnKey,L"Server",0,dwType,(LPBYTE)szConnData,cbdata)) {
  352. bReturn = FALSE;
  353. goto CleanUp;
  354. }
  355. cbdata = sizeof(szConnData);
  356. if (RegQueryValueEx(hPrinterKey,L"Provider",NULL,&dwType,(LPBYTE)szConnData,&cbdata)
  357. || RegSetValueEx(hNewConnKey,L"Provider",0,dwType,(LPBYTE)szConnData,cbdata)
  358. || RegSetValueEx(hNewConnKey,L"LocalConnection",0,REG_DWORD,
  359. (LPBYTE)&dwlocalconnection,sizeof(dwlocalconnection))) {
  360. bReturn = FALSE;
  361. goto CleanUp;
  362. }
  363. RegCloseKey(hPrinterKey);
  364. hPrinterKey = NULL;
  365. }
  366. RegCloseKey(hNewConnKey);
  367. hNewConnKey = NULL;
  368. }
  369. if (lstatus != ERROR_NO_MORE_ITEMS) {
  370. bReturn = FALSE;
  371. }
  372. CleanUp:
  373. if (hNewConnKey) {
  374. RegCloseKey(hNewConnKey);
  375. }
  376. if (hPrinterKey) {
  377. RegCloseKey(hPrinterKey);
  378. }
  379. return bReturn;
  380. }
  381. BOOL
  382. SplRegCopy(
  383. PINIT_REG_USER pUser,
  384. HKEY hMcConnectionKey)
  385. /*++
  386. Function Description - Removes old permachine connections for pUser and adds the new
  387. permachine connections from hMcConnectionKey
  388. Parameters - pUser - pointer to INIT_REG_USER which contains hUserKey.
  389. hMcConnectionKey - handle to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
  390. Control\Print\Connections
  391. Return Values - TRUE if success
  392. FALSE otherwise.
  393. --*/
  394. {
  395. LONG lstatus;
  396. BOOL bReturn = TRUE;
  397. WCHAR szRegistryConnections[] = L"Printers\\Connections";
  398. HKEY hConnectionKey = NULL;
  399. // Create (if not already present) and open Connections subkey
  400. lstatus = RegCreateKeyEx(pUser->hKeyUser,
  401. szRegistryConnections,
  402. 0,
  403. NULL,
  404. REG_OPTION_NON_VOLATILE,
  405. KEY_ALL_ACCESS,
  406. NULL,
  407. &hConnectionKey,
  408. NULL);
  409. if (lstatus != ERROR_SUCCESS) {
  410. bReturn = FALSE;
  411. goto CleanUp;
  412. }
  413. if (!DeleteOldPerMcConnections(hConnectionKey,hMcConnectionKey)
  414. || !AddNewPerMcConnections(hConnectionKey,hMcConnectionKey)) {
  415. bReturn = FALSE;
  416. }
  417. CleanUp:
  418. if (hConnectionKey) {
  419. RegCloseKey(hConnectionKey);
  420. }
  421. return bReturn;
  422. }
  423. BOOL
  424. SetupRegForUsers(
  425. PINIT_REG_USER pUsers,
  426. DWORD cUsers)
  427. {
  428. DWORD cbPrinters;
  429. DWORD cPrinters;
  430. PBYTE pPrinters;
  431. HKEY hMcConnectionKey = NULL;
  432. WCHAR szMachineConnections[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Connections";
  433. #define pPrinters2 ((PPRINTER_INFO_2)pPrinters)
  434. #define pPrinters4 ((PPRINTER_INFO_4)pPrinters)
  435. DWORD i, j;
  436. LPWSTR pszPort;
  437. //
  438. // Read in local printers.
  439. //
  440. cbPrinters = 1000;
  441. pPrinters = AllocSplMem(cbPrinters);
  442. if (!pPrinters)
  443. return FALSE;
  444. if (cPrinters = ReadPrinters(NULL,
  445. PRINTER_ENUM_LOCAL,
  446. &cbPrinters,
  447. &pPrinters)) {
  448. for (i=0; i< cUsers; i++) {
  449. for(j=0; j< cPrinters; j++) {
  450. if( pPrinters2[j].Attributes & PRINTER_ATTRIBUTE_NETWORK ){
  451. //
  452. // Use NeXX:
  453. //
  454. pszPort = NULL;
  455. } else {
  456. pszPort = CheckBadPortName( pPrinters2[j].pPortName );
  457. }
  458. UpdatePrinterInfo( &pUsers[i],
  459. pPrinters2[j].pPrinterName,
  460. pszPort,
  461. &(pUsers[i].dwNetCounter));
  462. }
  463. }
  464. }
  465. // Open the Key containing the current list of per-machine connections.
  466. RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMachineConnections, 0,
  467. KEY_READ , &hMcConnectionKey);
  468. for (i=0; i< cUsers; i++) {
  469. // Copy Per Machine Connections into the user hive
  470. SplRegCopy(&pUsers[i], hMcConnectionKey);
  471. if (cPrinters = ReadPrinters(&pUsers[i],
  472. PRINTER_ENUM_CONNECTIONS,
  473. &cbPrinters,
  474. &pPrinters)) {
  475. for(j=0; j< cPrinters; j++) {
  476. UpdatePrinterInfo(&pUsers[i],
  477. pPrinters4[j].pPrinterName,
  478. NULL,
  479. &(pUsers[i].dwNetCounter));
  480. }
  481. }
  482. }
  483. // Close the handle to Per Machine Connections.
  484. if (hMcConnectionKey) RegCloseKey(hMcConnectionKey);
  485. FreeSplMem(pPrinters);
  486. for (i=0; i< cUsers; i++) {
  487. UpdateUsersDefaultPrinter(&pUsers[i], FALSE);
  488. }
  489. return TRUE;
  490. #undef pPrinters2
  491. #undef pPrinters4
  492. }
  493. VOID
  494. UpdateUsersDefaultPrinter(
  495. IN PINIT_REG_USER pUser,
  496. IN BOOL bFindDefault
  497. )
  498. /*++
  499. Routine Description:
  500. Updates the default printer using the information in the
  501. current users reg structure. If the bFindDefault flag is
  502. specified then a default printer is located. The method for this
  503. is first see if there is currently a default printer, then user this.
  504. If a default printer is not found then located the first printer in
  505. devices section, again if on exists.
  506. Arguments:
  507. pUser - Information about the current user, reg keys etc.
  508. This routine assumes that hKeyWindows and hKeyDevices
  509. are valid opened registry keys, with read access.
  510. bFindDefault - TRUE located a default printer, FALSE the default
  511. printer is already specified in the users reg
  512. structure.
  513. Return Value:
  514. Nothing.
  515. --*/
  516. {
  517. LPWSTR pszNewDefault = NULL;
  518. //
  519. // If a request to find the default printer.
  520. //
  521. if (bFindDefault) {
  522. DWORD dwError = ERROR_SUCCESS;
  523. DWORD cbData = sizeof(pUser->szDefaultPrinter);
  524. //
  525. // Check if there is a default printer.
  526. //
  527. dwError = RegQueryValueEx(pUser->hKeyWindows,
  528. szDevice,
  529. NULL,
  530. NULL,
  531. (PBYTE)pUser->szDefaultPrinter,
  532. &cbData);
  533. //
  534. // If the device key was read and there is a non null string
  535. // as the default printer name.
  536. //
  537. if (dwError == ERROR_SUCCESS && pUser->szDefaultPrinter[0] != L'\0') {
  538. pUser->bDefaultFound = TRUE;
  539. } else {
  540. //
  541. // Default was not found.
  542. //
  543. pUser->bDefaultFound = FALSE;
  544. //
  545. // If a first printer was not found.
  546. //
  547. if (!pUser->bFirstPrinterFound)
  548. {
  549. DWORD cchPrinterLen = 0;
  550. WCHAR szBuffer [MAX_PATH*2];
  551. DWORD cbDataBuffer = sizeof(szBuffer);
  552. DBGMSG(DBG_TRACE, ("UpdateUsersDefaultPrinter default printer not found.\n"));
  553. cchPrinterLen = cbData = COUNTOF(pUser->szFirstPrinter);
  554. //
  555. // Default printer was not found, find any printer
  556. // in the devices section of the registry.
  557. //
  558. dwError = RegEnumValue(pUser->hKeyDevices,
  559. 0,
  560. pUser->szFirstPrinter,
  561. &cbData,
  562. NULL,
  563. NULL,
  564. (PBYTE)szBuffer,
  565. &cbDataBuffer);
  566. if (dwError == ERROR_SUCCESS) {
  567. StringCchCat(pUser->szFirstPrinter, cchPrinterLen, L",");
  568. StringCchCat(pUser->szFirstPrinter, cchPrinterLen, szBuffer);
  569. pUser->bFirstPrinterFound = TRUE;
  570. } else {
  571. DBGMSG(DBG_WARNING, ("UpdateUsersDefaultPrinter no printer found in devices section.\n"));
  572. pUser->bFirstPrinterFound = FALSE;
  573. }
  574. }
  575. }
  576. }
  577. //
  578. // If default wasn't present, and we did get a first printer,
  579. // make this the default.
  580. //
  581. if (!pUser->bDefaultFound) {
  582. if (pUser->bFirstPrinterFound) {
  583. pszNewDefault = pUser->szFirstPrinter;
  584. }
  585. } else {
  586. //
  587. // Write out default.
  588. //
  589. pszNewDefault = pUser->szDefaultPrinter;
  590. }
  591. if (pszNewDefault) {
  592. RegSetValueEx(pUser->hKeyWindows,
  593. szDevice,
  594. 0,
  595. REG_SZ,
  596. (PBYTE)pszNewDefault,
  597. (wcslen(pszNewDefault) + 1) * sizeof(pszNewDefault[0]));
  598. }
  599. }
  600. HRESULT
  601. IsUsersDefaultPrinter(
  602. IN PINIT_REG_USER pUser,
  603. IN PCWSTR pszPrinterName
  604. )
  605. /*++
  606. Routine Description:
  607. Asks if the users default printer matched the specified
  608. printer name.
  609. Arguments:
  610. pCurUser - Information about the current user, reg keys etc.
  611. This routine assumes that hKeyWindows is a valid
  612. opened registry keys, with at least read access.
  613. pszPrinterName - Printer name to check if it is the default printer.
  614. Return Value:
  615. S_OK the printer name is the default, S_FALSE the printer is not the
  616. default, An HRESULT error code if an error occurrs attempting to
  617. determine the default printer.
  618. --*/
  619. {
  620. HRESULT hr = E_INVALIDARG;
  621. if (pszPrinterName) {
  622. WCHAR szBuffer[MAX_PATH*2];
  623. DWORD dwError = ERROR_SUCCESS;
  624. DWORD cbData = sizeof(szBuffer);
  625. //
  626. // Read the default printer, if one exists.
  627. //
  628. dwError = RegQueryValueEx(pUser->hKeyWindows,
  629. szDevice,
  630. NULL,
  631. NULL,
  632. (PBYTE)szBuffer,
  633. &cbData);
  634. if (dwError == ERROR_SUCCESS) {
  635. PWSTR p = wcschr(szBuffer, L',');
  636. if (p) {
  637. *p = 0;
  638. }
  639. hr = !_wcsicmp(pszPrinterName, szBuffer) ? S_OK : S_FALSE;
  640. } else {
  641. hr = HRESULT_FROM_WIN32(dwError);
  642. }
  643. }
  644. return hr;
  645. }
  646. DWORD
  647. ReadPrinters(
  648. PINIT_REG_USER pUser,
  649. DWORD Flags,
  650. PDWORD pcbPrinters,
  651. LPBYTE* ppPrinters)
  652. {
  653. BOOL bSuccess = FALSE;
  654. DWORD cbNeeded = 0;
  655. DWORD cPrinters = 0;
  656. LPBYTE pPrinters = NULL;
  657. if (Flags == PRINTER_ENUM_CONNECTIONS) {
  658. bSuccess = EnumerateConnectedPrinters(*ppPrinters,
  659. *pcbPrinters,
  660. &cbNeeded,
  661. &cPrinters,
  662. pUser->hKeyUser);
  663. } else {
  664. bSuccess = EnumPrinters(Flags,
  665. NULL,
  666. 2,
  667. (PBYTE)*ppPrinters,
  668. *pcbPrinters,
  669. &cbNeeded,
  670. &cPrinters);
  671. }
  672. if (!bSuccess && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  673. //
  674. // If not enough space, realloc.
  675. //
  676. if (pPrinters = ReallocSplMem(*ppPrinters,
  677. 0,
  678. cbNeeded)) {
  679. *ppPrinters = pPrinters;
  680. pPrinters = NULL;
  681. *pcbPrinters = cbNeeded;
  682. bSuccess = TRUE;
  683. }
  684. else {
  685. bSuccess = FALSE;
  686. }
  687. if (bSuccess) {
  688. if (Flags == PRINTER_ENUM_CONNECTIONS) {
  689. bSuccess = EnumerateConnectedPrinters(*ppPrinters,
  690. *pcbPrinters,
  691. &cbNeeded,
  692. &cPrinters,
  693. pUser->hKeyUser);
  694. } else {
  695. bSuccess = EnumPrinters(Flags,
  696. NULL,
  697. 2,
  698. (PBYTE)*ppPrinters,
  699. *pcbPrinters,
  700. &cbNeeded,
  701. &cPrinters);
  702. }
  703. }
  704. }
  705. if (!bSuccess) {
  706. cPrinters = 0;
  707. }
  708. return cPrinters;
  709. }
  710. BOOL
  711. UpdatePrinterInfo(
  712. const PINIT_REG_USER pCurUser,
  713. LPCWSTR pszPrinterName,
  714. LPCWSTR pszPort,
  715. PDWORD pdwNetId
  716. )
  717. /*++
  718. Routine Description:
  719. Updates the printer information in the registry win.ini.
  720. Arguments:
  721. pCurUser - Information about the user. The following fields are
  722. used by this routine:
  723. hKeyDevices
  724. hKeyPrinterPorts
  725. bDefaultSearch (if true, read/writes to:)
  726. bDefaultFound
  727. szDefaultPrinter
  728. bFirstPrinterFound (if false, writes to:)
  729. szFirstPrinter
  730. pszPort - Port name. If NULL, generates NetId.
  731. pdwNetId - Pointer to NetId counter. This value will be incremented
  732. if the NetId is used.
  733. Return Value:
  734. --*/
  735. {
  736. WCHAR szBuffer[MAX_PATH * 2];
  737. LPWSTR p;
  738. DWORD dwCount = 0;
  739. DWORD cbLen;
  740. if (!pszPrinterName)
  741. return FALSE;
  742. //
  743. // Now we know the spooler is up, since the EnumPrinters succeeded.
  744. // Update all sections.
  745. //
  746. StringCchPrintf(szBuffer,
  747. MAX_PATH*2,
  748. L"%s,",
  749. szWinspool);
  750. dwCount = wcslen(szBuffer);
  751. if( !pszPort ){
  752. HANDLE hToken;
  753. StringCchPrintf(&szBuffer[dwCount],
  754. MAX_PATH*2 - dwCount,
  755. L"%s%.2d:",
  756. szNetwork,
  757. *pdwNetId);
  758. (*pdwNetId)++;
  759. //
  760. // !! HACK !!
  761. //
  762. // Works 3.0b expects the printer port entry in the
  763. // [ports] section.
  764. //
  765. // This is in the per-machine part of the registry, but we
  766. // are updating it for each user. Fix later.
  767. //
  768. // We never remove the NeXX: entries from [ports] but since
  769. // the same entries will be used by all users, this is ok.
  770. //
  771. hToken = RevertToPrinterSelf();
  772. WriteProfileString( szPorts, &szBuffer[dwCount], L"" );
  773. if( hToken ){
  774. ImpersonatePrinterClient( hToken );
  775. }
  776. //
  777. // End Works 3.0b HACK
  778. //
  779. } else {
  780. StringCchCopy(&szBuffer[dwCount],
  781. MAX_PATH*2 - dwCount,
  782. pszPort);
  783. //
  784. // Get the first port only.
  785. //
  786. if ( p = wcschr(&szBuffer[dwCount], L',') )
  787. *p = 0;
  788. }
  789. cbLen = (wcslen(szBuffer)+1) * sizeof(szBuffer[0]);
  790. RegSetValueEx(pCurUser->hKeyDevices,
  791. pszPrinterName,
  792. 0,
  793. REG_SZ,
  794. (PBYTE)szBuffer,
  795. cbLen);
  796. //
  797. // If the user has a default printer specified, then verify
  798. // that it exists.
  799. //
  800. if (pCurUser->bDefaultSearch) {
  801. pCurUser->bDefaultFound = !_wcsicmp(pszPrinterName,
  802. pCurUser->szDefaultPrinter);
  803. if (pCurUser->bDefaultFound) {
  804. StringCchPrintf(pCurUser->szDefaultPrinter,
  805. COUNTOF(pCurUser->szDefaultPrinter),
  806. L"%s,%s",
  807. pszPrinterName,
  808. szBuffer);
  809. pCurUser->bDefaultSearch = FALSE;
  810. }
  811. }
  812. if (!pCurUser->bFirstPrinterFound) {
  813. StringCchPrintf(pCurUser->szFirstPrinter,
  814. COUNTOF(pCurUser->szFirstPrinter),
  815. L"%s,%s",
  816. pszPrinterName,
  817. szBuffer);
  818. pCurUser->bFirstPrinterFound = TRUE;
  819. }
  820. StringCchCat(szBuffer, COUNTOF(szBuffer), szTimeouts);
  821. RegSetValueEx(pCurUser->hKeyPrinterPorts,
  822. pszPrinterName,
  823. 0,
  824. REG_SZ,
  825. (PBYTE)szBuffer,
  826. (wcslen(szBuffer)+1) * sizeof(szBuffer[0]));
  827. return TRUE;
  828. }
  829. VOID
  830. SpoolerInitAsync(
  831. PINIT_REG_USER pUser
  832. )
  833. /*++
  834. Routine Description: Asynchronously sets up the user's registry information
  835. Arguments: pUser - pointer to INIT_REG_USER containing user keys
  836. Return Values: NONE
  837. --*/
  838. {
  839. if (InitializeRegUser(NULL, pUser))
  840. {
  841. SetupRegForUsers(pUser, 1);
  842. }
  843. BroadcastMessage(BROADCAST_TYPE_CHANGEDEFAULT,0,0,0);
  844. FreeRegUser(pUser);
  845. FreeSplMem(pUser);
  846. }
  847. BOOL
  848. SpoolerInit(
  849. VOID
  850. )
  851. /*++
  852. Routine Description: Initializes just the current user.
  853. Arguments: NONE
  854. Return Value: TRUE if initialized or async init thread created successfully
  855. FALSE otherwise
  856. --*/
  857. {
  858. BOOL bSuccess = FALSE;
  859. DWORD dwThreadId;
  860. HANDLE hThread;
  861. PINIT_REG_USER pUser;
  862. UpdateLogonTimeStamp ();
  863. if (!(pUser = AllocSplMem(sizeof(INIT_REG_USER)))) {
  864. return FALSE;
  865. }
  866. //
  867. // Enum just the current user.
  868. //
  869. pUser->hKeyUser = GetClientUserHandle(KEY_READ|KEY_WRITE);
  870. if (pUser->hKeyUser)
  871. {
  872. if (!Initialized)
  873. {
  874. //
  875. // Process the user initialization asynchronously if the spooler
  876. // hasn't completed it's initialization.
  877. //
  878. hThread = CreateThread(NULL,
  879. 0,
  880. (LPTHREAD_START_ROUTINE) SpoolerInitAsync,
  881. (LPVOID) pUser, 0, &dwThreadId);
  882. if (hThread)
  883. {
  884. //
  885. // We assume that the async thread will succeed.
  886. //
  887. CloseHandle(hThread);
  888. bSuccess = TRUE;
  889. }
  890. else
  891. {
  892. FreeRegUser(pUser);
  893. FreeSplMem(pUser);
  894. }
  895. }
  896. else
  897. {
  898. if (InitializeRegUser(NULL, pUser))
  899. {
  900. bSuccess = SetupRegForUsers(pUser, 1);
  901. }
  902. FreeRegUser(pUser);
  903. FreeSplMem(pUser);
  904. }
  905. }
  906. return bSuccess;
  907. }
  908. BOOL
  909. InitializeRegUser(
  910. LPWSTR pszSubKey,
  911. PINIT_REG_USER pUser
  912. )
  913. /*++
  914. Routine Description:
  915. Initialize a single users structure based on a HKEY_USERS subkey.
  916. Arguments:
  917. pszSubKey - if non-NULL initialize hKeyUser to this key
  918. pUser - structure to initialize
  919. Return Value:
  920. --*/
  921. {
  922. HKEY hKey;
  923. LPWSTR p;
  924. BOOL bSecurityLoaded = FALSE, rc = FALSE;
  925. DWORD cbData, cbSD = 0, dwError, dwDisposition;
  926. PSECURITY_DESCRIPTOR pSD = NULL;
  927. HANDLE hToken = NULL;
  928. if (pszSubKey) {
  929. if (RegOpenKeyEx(HKEY_USERS,
  930. pszSubKey,
  931. 0,
  932. KEY_READ|KEY_WRITE,
  933. &pUser->hKeyUser) != ERROR_SUCCESS) {
  934. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegOpenKeyEx failed\n"));
  935. goto Fail;
  936. }
  937. }
  938. //
  939. // Now attempt to set the security on these two keys to
  940. // their parent key.
  941. //
  942. dwError = RegOpenKeyEx(pUser->hKeyUser,
  943. szCurrentVersionPath,
  944. 0,
  945. KEY_READ,
  946. &hKey);
  947. if (!dwError) {
  948. dwError = RegGetKeySecurity(hKey,
  949. DACL_SECURITY_INFORMATION,
  950. pSD,
  951. &cbSD);
  952. if (dwError == ERROR_INSUFFICIENT_BUFFER) {
  953. pSD = AllocSplMem(cbSD);
  954. if (pSD) {
  955. if (!RegGetKeySecurity(hKey,
  956. DACL_SECURITY_INFORMATION,
  957. pSD,
  958. &cbSD)){
  959. bSecurityLoaded = TRUE;
  960. } else {
  961. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegGetKeySecurity failed %d\n",
  962. GetLastError()));
  963. }
  964. }
  965. } else {
  966. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegGetKeySecurity failed %d\n",
  967. dwError));
  968. }
  969. RegCloseKey(hKey);
  970. } else {
  971. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegOpenKeyEx CurrentVersion failed %d\n",
  972. dwError));
  973. }
  974. hToken = RevertToPrinterSelf();
  975. //
  976. // Open up the right keys.
  977. //
  978. if (RegCreateKeyEx(pUser->hKeyUser,
  979. szRegDevicesPath,
  980. 0,
  981. szNULL,
  982. 0,
  983. KEY_ALL_ACCESS,
  984. NULL,
  985. &pUser->hKeyDevices,
  986. &dwDisposition) != ERROR_SUCCESS) {
  987. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegCreateKeyEx1 failed %d\n",
  988. GetLastError()));
  989. goto Fail;
  990. }
  991. if (bSecurityLoaded) {
  992. RegSetKeySecurity(pUser->hKeyDevices,
  993. DACL_SECURITY_INFORMATION,
  994. pSD);
  995. }
  996. if (RegCreateKeyEx(pUser->hKeyUser,
  997. szRegPrinterPortsPath,
  998. 0,
  999. szNULL,
  1000. 0,
  1001. KEY_ALL_ACCESS,
  1002. NULL,
  1003. &pUser->hKeyPrinterPorts,
  1004. &dwDisposition) != ERROR_SUCCESS) {
  1005. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegCreateKeyEx2 failed %d\n",
  1006. GetLastError()));
  1007. goto Fail;
  1008. }
  1009. if (bSecurityLoaded) {
  1010. RegSetKeySecurity(pUser->hKeyPrinterPorts,
  1011. DACL_SECURITY_INFORMATION,
  1012. pSD);
  1013. }
  1014. //
  1015. // First, attempt to clear out the keys by deleting them.
  1016. //
  1017. RegClearKey(pUser->hKeyDevices);
  1018. RegClearKey(pUser->hKeyPrinterPorts);
  1019. if (RegOpenKeyEx(pUser->hKeyUser,
  1020. szRegWindowsPath,
  1021. 0,
  1022. KEY_READ|KEY_WRITE,
  1023. &pUser->hKeyWindows) != ERROR_SUCCESS) {
  1024. DBGMSG(DBG_WARNING, ("InitializeRegUser: RegOpenKeyEx failed %d\n",
  1025. GetLastError()));
  1026. goto Fail;
  1027. }
  1028. pUser->bFoundPrinter = FALSE;
  1029. pUser->bDefaultSearch = FALSE;
  1030. pUser->bDefaultFound = FALSE;
  1031. pUser->bFirstPrinterFound = FALSE;
  1032. pUser->dwNetCounter = 0;
  1033. cbData = sizeof(pUser->szDefaultPrinter);
  1034. if (RegQueryValueEx(pUser->hKeyWindows,
  1035. szDevice,
  1036. NULL,
  1037. NULL,
  1038. (PBYTE)pUser->szDefaultPrinter,
  1039. &cbData) == ERROR_SUCCESS) {
  1040. pUser->bDefaultSearch = TRUE;
  1041. }
  1042. //
  1043. // Remove the Device= in [windows]
  1044. //
  1045. RegDeleteValue(pUser->hKeyWindows,
  1046. szDevice);
  1047. if (!pUser->bDefaultSearch) {
  1048. //
  1049. // Attempt to read from saved location.
  1050. //
  1051. if (RegOpenKeyEx(pUser->hKeyUser,
  1052. szPrinters,
  1053. 0,
  1054. KEY_READ,
  1055. &hKey) == ERROR_SUCCESS) {
  1056. cbData = sizeof(pUser->szDefaultPrinter);
  1057. //
  1058. // Try reading szDeviceOld.
  1059. //
  1060. if (RegQueryValueEx(
  1061. hKey,
  1062. szDeviceOld,
  1063. NULL,
  1064. NULL,
  1065. (PBYTE)pUser->szDefaultPrinter,
  1066. &cbData) == ERROR_SUCCESS) {
  1067. pUser->bDefaultSearch = TRUE;
  1068. }
  1069. RegCloseKey(hKey);
  1070. }
  1071. }
  1072. if ( pUser->bDefaultSearch )
  1073. {
  1074. pUser->szDefaultPrinter[COUNTOF(pUser->szDefaultPrinter) - 1] = '\0';
  1075. if (p = wcschr(pUser->szDefaultPrinter, L','))
  1076. {
  1077. *p = 0;
  1078. }
  1079. }
  1080. rc = TRUE;
  1081. Fail:
  1082. if (hToken) {
  1083. ImpersonatePrinterClient(hToken);
  1084. }
  1085. if (pSD) {
  1086. FreeSplMem(pSD);
  1087. }
  1088. if (!rc)
  1089. FreeRegUser(pUser);
  1090. return rc;
  1091. }
  1092. VOID
  1093. FreeRegUser(
  1094. PINIT_REG_USER pUser)
  1095. /*++
  1096. Routine Description:
  1097. Free up the INIT_REG_USER structure intialized by InitializeRegUser.
  1098. Arguments:
  1099. Return Value:
  1100. --*/
  1101. {
  1102. if (pUser->hKeyUser) {
  1103. RegCloseKey(pUser->hKeyUser);
  1104. pUser->hKeyUser = NULL;
  1105. }
  1106. if (pUser->hKeyDevices) {
  1107. RegCloseKey(pUser->hKeyDevices);
  1108. pUser->hKeyDevices = NULL;
  1109. }
  1110. if (pUser->hKeyPrinterPorts) {
  1111. RegCloseKey(pUser->hKeyPrinterPorts);
  1112. pUser->hKeyPrinterPorts = NULL;
  1113. }
  1114. if (pUser->hKeyWindows) {
  1115. RegCloseKey(pUser->hKeyWindows);
  1116. pUser->hKeyWindows = NULL;
  1117. }
  1118. }
  1119. VOID
  1120. UpdatePrinterRegAll(
  1121. LPWSTR pszPrinterName,
  1122. LPWSTR pszPort,
  1123. BOOL bDelete
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. Updates everyone's [devices] and [printerports] sections (for
  1128. local printers only).
  1129. Arguments:
  1130. pszPrinterName - printer that has been added/deleted
  1131. pszPort - port name; if NULL, generate NetId
  1132. bDelete - if TRUE, delete entry instead of updating it.
  1133. Return Value:
  1134. --*/
  1135. {
  1136. WCHAR szKey[MAX_PATH];
  1137. DWORD cchKey;
  1138. DWORD i;
  1139. FILETIME ftLastWriteTime;
  1140. DWORD dwError;
  1141. //
  1142. // Go through all keys and fix them up.
  1143. //
  1144. for (i=0; TRUE; i++) {
  1145. cchKey = COUNTOF(szKey);
  1146. dwError = RegEnumKeyEx(HKEY_USERS,
  1147. i,
  1148. szKey,
  1149. &cchKey,
  1150. NULL,
  1151. NULL,
  1152. NULL,
  1153. &ftLastWriteTime);
  1154. if (dwError != ERROR_SUCCESS)
  1155. break;
  1156. if (!_wcsicmp(szKey, szDotDefault) || wcschr(szKey, L'_'))
  1157. continue;
  1158. UpdatePrinterRegUser(NULL,
  1159. szKey,
  1160. pszPrinterName,
  1161. pszPort,
  1162. bDelete);
  1163. }
  1164. }
  1165. DWORD
  1166. UpdatePrinterRegUser(
  1167. HKEY hKeyUser,
  1168. LPWSTR pszUserKey,
  1169. LPWSTR pszPrinterName,
  1170. LPWSTR pszPort,
  1171. BOOL bDelete
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Update one user's registry. The user is specified by either
  1176. hKeyUser or pszUserKey.
  1177. Arguments:
  1178. hKeyUser - Clients user key (ignored if pszKey specified)
  1179. pszUserKey - Clients SID (Used if supplied instead of hKeyUser)
  1180. pszPrinterName - name of printe to add
  1181. pszPort - port name; if NULL, generate NetId
  1182. bDelete - if TRUE, delete entry instead of updating.
  1183. Return Value:
  1184. NOTE: We never cleanup [ports] since it is per-user
  1185. EITHER hKeyUser or pszUserKey must be valid, but not both.
  1186. --*/
  1187. {
  1188. HKEY hKeyClose = NULL;
  1189. HKEY hKeyRoot;
  1190. DWORD dwError;
  1191. WCHAR szBuffer[MAX_PATH];
  1192. DWORD dwNetId;
  1193. INIT_REG_USER InitRegUser;
  1194. ZeroMemory(&InitRegUser, sizeof(InitRegUser));
  1195. InitRegUser.hKeyDevices = NULL;
  1196. InitRegUser.hKeyPrinterPorts = NULL;
  1197. InitRegUser.bDefaultSearch = FALSE;
  1198. InitRegUser.bFirstPrinterFound = TRUE;
  1199. //
  1200. // Setup the registry keys.
  1201. //
  1202. if (pszUserKey) {
  1203. dwError = RegOpenKeyEx( HKEY_USERS,
  1204. pszUserKey,
  1205. 0,
  1206. KEY_READ|KEY_WRITE,
  1207. &hKeyRoot );
  1208. if (dwError != ERROR_SUCCESS) {
  1209. goto Done;
  1210. }
  1211. hKeyClose = hKeyRoot;
  1212. } else {
  1213. hKeyRoot = hKeyUser;
  1214. }
  1215. dwError = RegOpenKeyEx(hKeyRoot,
  1216. szRegDevicesPath,
  1217. 0,
  1218. KEY_READ|KEY_WRITE,
  1219. &InitRegUser.hKeyDevices);
  1220. if (dwError != ERROR_SUCCESS)
  1221. goto Done;
  1222. dwError = RegOpenKeyEx(hKeyRoot,
  1223. szRegWindowsPath,
  1224. 0,
  1225. KEY_READ|KEY_WRITE,
  1226. &InitRegUser.hKeyWindows);
  1227. if (dwError != ERROR_SUCCESS)
  1228. goto Done;
  1229. //
  1230. // Setup [PrinterPorts]
  1231. //
  1232. dwError = RegOpenKeyEx(hKeyRoot,
  1233. szRegPrinterPortsPath,
  1234. 0,
  1235. KEY_WRITE,
  1236. &InitRegUser.hKeyPrinterPorts);
  1237. if (dwError != ERROR_SUCCESS)
  1238. goto Done;
  1239. if (!bDelete) {
  1240. pszPort = CheckBadPortName( pszPort );
  1241. if( !pszPort ){
  1242. dwNetId = GetNetworkIdWorker(InitRegUser.hKeyDevices,
  1243. pszPrinterName);
  1244. }
  1245. InitRegUser.bFirstPrinterFound = FALSE;
  1246. UpdatePrinterInfo( &InitRegUser,
  1247. pszPrinterName,
  1248. pszPort,
  1249. &dwNetId );
  1250. UpdateUsersDefaultPrinter( &InitRegUser,
  1251. TRUE );
  1252. } else {
  1253. HKEY hKeyDevMode;
  1254. //
  1255. // Delete the entries.
  1256. //
  1257. RegDeleteValue(InitRegUser.hKeyDevices, pszPrinterName);
  1258. RegDeleteValue(InitRegUser.hKeyPrinterPorts, pszPrinterName);
  1259. //
  1260. // Check if the printer we are deleting is currently the
  1261. // default printer.
  1262. //
  1263. if (IsUsersDefaultPrinter(&InitRegUser, pszPrinterName) == S_OK) {
  1264. //
  1265. // Remove the default printer from the registry.
  1266. //
  1267. RegDeleteValue(InitRegUser.hKeyWindows, szDevice);
  1268. }
  1269. //
  1270. // Also delete DevModes2 entry from registry
  1271. //
  1272. dwError = RegOpenKeyEx( hKeyRoot,
  1273. szDevModes2Path,
  1274. 0,
  1275. KEY_WRITE,
  1276. &hKeyDevMode );
  1277. if (dwError == ERROR_SUCCESS) {
  1278. //
  1279. // Delete the devmode value entry for the particular printer
  1280. //
  1281. RegDeleteValue(hKeyDevMode, pszPrinterName);
  1282. RegCloseKey(hKeyDevMode);
  1283. }
  1284. //
  1285. // Remove the per-user DevMode.
  1286. //
  1287. bSetDevModePerUser( hKeyRoot,
  1288. pszPrinterName,
  1289. NULL );
  1290. }
  1291. Done:
  1292. if( InitRegUser.hKeyDevices ){
  1293. RegCloseKey( InitRegUser.hKeyDevices );
  1294. }
  1295. if( InitRegUser.hKeyWindows ){
  1296. RegCloseKey( InitRegUser.hKeyWindows );
  1297. }
  1298. if( InitRegUser.hKeyPrinterPorts ){
  1299. RegCloseKey( InitRegUser.hKeyPrinterPorts );
  1300. }
  1301. if( hKeyClose ){
  1302. RegCloseKey( hKeyClose );
  1303. }
  1304. return dwError;
  1305. }
  1306. VOID
  1307. RegClearKey(
  1308. HKEY hKey
  1309. )
  1310. {
  1311. DWORD dwError;
  1312. WCHAR szValue[MAX_PATH];
  1313. DWORD cchValue;
  1314. while (TRUE) {
  1315. cchValue = COUNTOF(szValue);
  1316. dwError = RegEnumValue(hKey,
  1317. 0,
  1318. szValue,
  1319. &cchValue,
  1320. NULL,
  1321. NULL,
  1322. NULL,
  1323. NULL);
  1324. if (dwError != ERROR_SUCCESS) {
  1325. if( dwError != ERROR_NO_MORE_ITEMS ){
  1326. DBGMSG( DBG_WARN, ( "RegClearKey: RegEnumValue failed %d\n", dwError ));
  1327. }
  1328. break;
  1329. }
  1330. dwError = RegDeleteValue(hKey, szValue);
  1331. if( dwError != ERROR_SUCCESS) {
  1332. DBGMSG( DBG_WARN, ( "RegClearKey: RegDeleteValue failed %d\n", dwError ));
  1333. break;
  1334. }
  1335. }
  1336. }
  1337. LPWSTR
  1338. CheckBadPortName(
  1339. LPWSTR pszPort
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. This routine checks whether a port name should be converted to
  1344. NeXX:. Currently if the port is NULL, or "\\*," or has a space,
  1345. we convert to NeXX.
  1346. Arguments:
  1347. pszPort - port to check
  1348. Return Value:
  1349. pszPort - if port is OK.
  1350. NULL - if port needs to be converted
  1351. --*/
  1352. {
  1353. //
  1354. // If we have no pszPort, OR
  1355. // it begins with '\\' (as in \\server\share) OR
  1356. // it has a space in it OR
  1357. // it's length is greater than 5 ("LPT1:")
  1358. // Then
  1359. // use NeXX:
  1360. //
  1361. // Most 16 bit apps can't deal with long port names, since they
  1362. // allocate small buffers.
  1363. //
  1364. if( !pszPort ||
  1365. ( pszPort[0] == L'\\' && pszPort[1] == L'\\' ) ||
  1366. wcschr( pszPort, L' ' ) ||
  1367. wcslen( pszPort ) > 5 ){
  1368. return NULL;
  1369. }
  1370. return pszPort;
  1371. }
  1372. BOOL
  1373. UpdateLogonTimeStamp(
  1374. void
  1375. )
  1376. {
  1377. long lstatus;
  1378. HKEY hProvidersKey = NULL;
  1379. FILETIME LogonTime;
  1380. LPWSTR szPrintProviders = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers";
  1381. LPWSTR szLogonTime = L"LogonTime";
  1382. GetSystemTimeAsFileTime (&LogonTime);
  1383. // Create (if not already present) and open Connections subkey
  1384. lstatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1385. szPrintProviders,
  1386. 0,
  1387. NULL,
  1388. REG_OPTION_NON_VOLATILE,
  1389. KEY_SET_VALUE,
  1390. NULL,
  1391. &hProvidersKey,
  1392. NULL);
  1393. if (lstatus == ERROR_SUCCESS) {
  1394. lstatus = RegSetValueEx (hProvidersKey,
  1395. szLogonTime,
  1396. 0,
  1397. REG_BINARY,
  1398. (LPBYTE) &LogonTime,
  1399. sizeof (FILETIME));
  1400. RegCloseKey(hProvidersKey);
  1401. }
  1402. return lstatus == ERROR_SUCCESS;
  1403. }
  1404. /*++
  1405. Routine Name
  1406. AllowRemoteCalls
  1407. Routine Description:
  1408. This chains into the server and tells it to allow remote calls on the RPC
  1409. interface. Note that this is reference counted.
  1410. Arguments:
  1411. None
  1412. Return Value:
  1413. An HRESULT
  1414. --*/
  1415. HRESULT
  1416. AllowRemoteCalls(
  1417. VOID
  1418. )
  1419. {
  1420. HRESULT hr = (gpServerExports && gpServerExports->FnAllowRemoteCalls) ?
  1421. S_OK :
  1422. E_UNEXPECTED;
  1423. if (SUCCEEDED(hr))
  1424. {
  1425. hr = gpServerExports->FnAllowRemoteCalls();
  1426. }
  1427. return hr;
  1428. }
  1429. /*++
  1430. Routine Name
  1431. GetServerPolicy
  1432. Routine Description:
  1433. This chains into the server and gets a numeric policy read
  1434. by the server.
  1435. Arguments:
  1436. pszPolicyName - policy name
  1437. pValue - pointer to numeric value
  1438. Return Value:
  1439. An HRESULT
  1440. --*/
  1441. HRESULT
  1442. GetServerPolicy(
  1443. IN PCWSTR pszPolicyName,
  1444. IN ULONG* pValue
  1445. )
  1446. {
  1447. HRESULT hr = (gpServerExports && gpServerExports->FnGetServerPolicy) ?
  1448. S_OK :
  1449. E_UNEXPECTED;
  1450. if (SUCCEEDED(hr))
  1451. {
  1452. hr = (pValue && pszPolicyName) ? S_OK : E_POINTER;
  1453. if (SUCCEEDED(hr))
  1454. {
  1455. hr = gpServerExports->FnGetServerPolicy(pszPolicyName, pValue);
  1456. }
  1457. }
  1458. return hr;
  1459. }