Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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