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.

2110 lines
61 KiB

  1. /*****************************************************************************\
  2. * MODULE: webpnp.cxx
  3. *
  4. * This module contains routines which read/write printer-configuration
  5. * data to a BIN-File. The file format is depicted below. The file begins
  6. * with a header indicating the number of (pData) items. THIS DOES NOT
  7. * include the DEVMODEW in its item-count. So, at a minimum, this code
  8. * could result in the setting of a DEVMODE, or just setting the printer
  9. * data, depending upon the header information.
  10. *
  11. *
  12. * DEVBIN_HEAD DEVBIN_INFO ...-> DEVBIN_INFO
  13. * --------------------------------------------------------------------------
  14. * | | cbSize | cbSize |
  15. * | bDevMode |------------------------------|------------------------------|
  16. * | cItems | | | | cbData | | | | cbData |
  17. * | | Type | Key | Name |----------| Type | Key | Name |----------|
  18. * | | | | | DevModeW | | | | pData 0 |
  19. * --------------------------------------------------------------------------
  20. *
  21. * The usage scenario is for webWritePrinterInfo() to query a printer and
  22. * write out the DEVMODEW and Printer-Configuration data to this file-format.
  23. * On a call to webReadPrinterInfo(), a particular printer is opened, and
  24. * the BIN-File is read. The printer is then reset to the information
  25. * contained in the BIN-File. This is accomplished by doing a GetPrinter(2)
  26. * on the opened-printer, then re-configuring the PRINT_INFO_2 information
  27. * and reseting the the printer through SetPrinter(2).
  28. *
  29. * Likewise, if there exists printer-data, the information is set to the
  30. * opened printer through SetPrinterData() calls.
  31. *
  32. *
  33. * NOTE: The DEVMODE is always the FIRST entry in this file following the
  34. * DEVBIN_HEAD.
  35. *
  36. * NOTE: The (cItems) only refers to the (Printer-Data) fields. It does
  37. * not count the DEVMODEW.
  38. *
  39. * NOTE: The processing for ICM-Profile enumeration is performed in unicode
  40. * strings and only converted to TCHAR type strings on callbacks to
  41. * the caller of the enum API. This is desirable to maintain a level
  42. * of consistency when dealing with text.
  43. *
  44. *
  45. * Copyright (C) 1996-1997 Microsoft Corporation
  46. * Copyright (C) 1996-1997 Hewlett Packard
  47. *
  48. * history:
  49. * 25-Feb-1997 <chriswil> created.
  50. *
  51. \*****************************************************************************/
  52. #include "spllibp.hxx"
  53. #include <winspool.h>
  54. #include <winsplp.h>
  55. #include <icm.h>
  56. #include <wininet.h>
  57. /***************************************\
  58. * Static Strings.
  59. \***************************************/
  60. static CONST WCHAR s_wszCopyFiles[] = L"CopyFiles";
  61. static CONST WCHAR s_wszDir[] = L"Directory";
  62. static CONST WCHAR s_wszFil[] = L"Files";
  63. static CONST WCHAR s_wszMod[] = L"Module";
  64. static CONST CHAR s_szGCFP[] = "GenerateCopyFilePaths";
  65. /*****************************************************************************\
  66. * web_GAlloc (Local Routine)
  67. *
  68. * Allocates a block of memory.
  69. *
  70. \*****************************************************************************/
  71. inline LPVOID web_GAlloc(
  72. DWORD cbSize)
  73. {
  74. return new BYTE[cbSize];
  75. }
  76. /*****************************************************************************\
  77. * web_GFree (Local Routine)
  78. *
  79. * Deletes the memory-block allocated via web_GAlloc().
  80. *
  81. \*****************************************************************************/
  82. inline BOOL web_GFree(
  83. LPVOID lpMem)
  84. {
  85. delete [] lpMem;
  86. return TRUE;
  87. }
  88. /*****************************************************************************\
  89. * web_AlignSize (Local Routine)
  90. *
  91. * Returns size (bytes) of the memory-block. This returns a 64 bit aligned
  92. * value.
  93. *
  94. \*****************************************************************************/
  95. inline DWORD web_AlignSize(
  96. DWORD cbSize)
  97. {
  98. return ((cbSize & 7) ? cbSize + (8 - (cbSize & 7)) : cbSize);
  99. }
  100. /*****************************************************************************\
  101. * web_StrSizeW (Local Routine)
  102. *
  103. * Returns size (bytes) of the string. This includes the NULL terminator.
  104. *
  105. \*****************************************************************************/
  106. inline DWORD web_StrSizeW(
  107. LPCWSTR lpszStr)
  108. {
  109. return ((lstrlenW(lpszStr) + 1) * sizeof(WCHAR));
  110. }
  111. /*****************************************************************************\
  112. * web_NextStrW (Local Routine)
  113. *
  114. * Returns pointer to the next-item in a string array.
  115. *
  116. \*****************************************************************************/
  117. inline LPWSTR web_NextStrW(
  118. LPCWSTR lpszStr)
  119. {
  120. return ((LPWSTR)lpszStr + (lstrlenW(lpszStr) + 1));
  121. }
  122. /*****************************************************************************\
  123. * web_NextItem (Local Routine)
  124. *
  125. * Returns pointer to the next-item in the BIN-File.
  126. *
  127. \*****************************************************************************/
  128. inline LPDEVBIN_INFO web_NextItem(
  129. LPDEVBIN_INFO lpInfo)
  130. {
  131. return (LPDEVBIN_INFO)(((LPBYTE)lpInfo) + lpInfo->cbSize);
  132. }
  133. /*****************************************************************************\
  134. * web_MBtoWC (Local Routine)
  135. *
  136. * Converts a MultiByte string to a Unicode string.
  137. *
  138. \*****************************************************************************/
  139. inline DWORD web_MBtoWC(
  140. LPWSTR lpszWC,
  141. LPCSTR lpszMB,
  142. DWORD cbSize)
  143. {
  144. cbSize = (DWORD)MultiByteToWideChar(CP_ACP,
  145. MB_PRECOMPOSED,
  146. lpszMB,
  147. -1,
  148. lpszWC,
  149. (int)(cbSize / sizeof(WCHAR)));
  150. return (cbSize * sizeof(WCHAR));
  151. }
  152. /*****************************************************************************\
  153. * web_WCtoTC (Local Routine)
  154. *
  155. * Converts a Unicode string to a string appropriate for the built library.
  156. * The size must account for the NULL terminator when specifying size.
  157. *
  158. \*****************************************************************************/
  159. inline LPTSTR web_WCtoTC(
  160. LPCWSTR lpwszWC,
  161. DWORD cchWC)
  162. {
  163. LPTSTR lpszTC;
  164. DWORD cbSize;
  165. cbSize = cchWC * sizeof(TCHAR);
  166. if (lpszTC = (LPTSTR)web_GAlloc(cbSize)) {
  167. #ifdef UNICODE
  168. //
  169. // Use CopyMemory, not lstrcpyn. This allows strings
  170. // with nulls in them...(e.g. MULTI_SZ regsitry values
  171. //
  172. CopyMemory(lpszTC, lpwszWC, cbSize);
  173. #else
  174. WideCharToMultiByte(CP_ACP,
  175. WC_DEFAULTCHAR,
  176. lpwszWC,
  177. cchWC,
  178. lpszTC,
  179. cchWC,
  180. NULL,
  181. NULL);
  182. #endif
  183. }
  184. return lpszTC;
  185. }
  186. /*****************************************************************************\
  187. * web_OpenDirectoryW (Local Routine)
  188. *
  189. * Open a handle to a directory.
  190. *
  191. \*****************************************************************************/
  192. inline HANDLE web_OpenDirectoryW(
  193. LPCWSTR lpwszDir)
  194. {
  195. return CreateFileW(lpwszDir,
  196. 0,
  197. FILE_SHARE_READ | FILE_SHARE_WRITE,
  198. NULL,
  199. OPEN_EXISTING,
  200. FILE_ATTRIBUTE_NORMAL,
  201. NULL);
  202. }
  203. /*****************************************************************************\
  204. * web_OpenFileRead (Local Routine)
  205. *
  206. * Open a file for reading.
  207. *
  208. \*****************************************************************************/
  209. inline HANDLE web_OpenFileRead(
  210. LPCTSTR lpszName)
  211. {
  212. return CreateFile(lpszName,
  213. GENERIC_READ,
  214. FILE_SHARE_READ,
  215. NULL,
  216. OPEN_EXISTING,
  217. FILE_ATTRIBUTE_NORMAL,
  218. NULL);
  219. }
  220. /*****************************************************************************\
  221. * web_OpenFileWrite (Local Routine)
  222. *
  223. * Open a file for writing.
  224. *
  225. \*****************************************************************************/
  226. inline HANDLE web_OpenFileWrite(
  227. LPCTSTR lpszName)
  228. {
  229. return CreateFile(lpszName,
  230. GENERIC_WRITE,
  231. 0,
  232. NULL,
  233. CREATE_ALWAYS,
  234. FILE_ATTRIBUTE_NORMAL,
  235. NULL);
  236. }
  237. /*****************************************************************************\
  238. * web_LockMap (Local Routine)
  239. *
  240. * Locks the map-view.
  241. *
  242. \*****************************************************************************/
  243. inline LPVOID web_LockMap(
  244. HANDLE hMap)
  245. {
  246. LPWEB_FILEMAP lpMap;
  247. LPVOID lpPtr = NULL;
  248. if (lpMap = (LPWEB_FILEMAP)hMap)
  249. lpPtr = MapViewOfFile(lpMap->hMap, FILE_MAP_READ, 0, 0, 0);
  250. return lpPtr;
  251. }
  252. /*****************************************************************************\
  253. * web_UnlockMap (Local Routine)
  254. *
  255. * Unlocks the map-view.
  256. *
  257. \*****************************************************************************/
  258. inline BOOL web_UnlockMap(
  259. LPVOID lpPtr)
  260. {
  261. return UnmapViewOfFile(lpPtr);
  262. }
  263. /*****************************************************************************\
  264. * web_OpenMap (Local Routine)
  265. *
  266. * Opens a file-mapping object.
  267. *
  268. \*****************************************************************************/
  269. HANDLE web_OpenMap(
  270. LPCTSTR lpszFile)
  271. {
  272. LPWEB_FILEMAP lpMap;
  273. DWORD cbSize;
  274. if (lpMap = (LPWEB_FILEMAP)web_GAlloc(sizeof(WEB_FILEMAP))) {
  275. lpMap->hFile = web_OpenFileRead(lpszFile);
  276. if (lpMap->hFile && (lpMap->hFile != INVALID_HANDLE_VALUE)) {
  277. if (cbSize = GetFileSize(lpMap->hFile, NULL)) {
  278. lpMap->hMap = CreateFileMapping(lpMap->hFile,
  279. NULL,
  280. PAGE_READONLY,
  281. 0,
  282. cbSize,
  283. NULL);
  284. if (lpMap->hMap)
  285. return (HANDLE)lpMap;
  286. }
  287. CloseHandle(lpMap->hFile);
  288. }
  289. web_GFree(lpMap);
  290. }
  291. return NULL;
  292. }
  293. /*****************************************************************************\
  294. * web_CloseMap (Local Routine)
  295. *
  296. * Closes file-mapping object.
  297. *
  298. \*****************************************************************************/
  299. BOOL web_CloseMap(
  300. HANDLE hMap)
  301. {
  302. LPWEB_FILEMAP lpMap;
  303. BOOL bRet = FALSE;
  304. if (lpMap = (LPWEB_FILEMAP)hMap) {
  305. CloseHandle(lpMap->hMap);
  306. CloseHandle(lpMap->hFile);
  307. bRet = web_GFree(lpMap);
  308. }
  309. return bRet;
  310. }
  311. /*****************************************************************************\
  312. * web_GAllocStrW (Local Routine)
  313. *
  314. * Allocates a unicode string buffer.
  315. *
  316. \*****************************************************************************/
  317. LPWSTR web_GAllocStrW(
  318. LPCWSTR lpszStr)
  319. {
  320. LPWSTR lpszMem;
  321. DWORD cbSize;
  322. if (lpszStr == NULL)
  323. return NULL;
  324. cbSize = web_StrSizeW(lpszStr);
  325. if (lpszMem = (LPWSTR)web_GAlloc(cbSize))
  326. CopyMemory(lpszMem, lpszStr, cbSize);
  327. return lpszMem;
  328. }
  329. /*****************************************************************************\
  330. * web_LoadModuleW
  331. *
  332. * Loads the module by first looking in the path. If this fails it attempts
  333. * to load from the driver-directory.
  334. *
  335. \*****************************************************************************/
  336. HMODULE web_LoadModuleW(
  337. LPCWSTR lpwszMod)
  338. {
  339. HMODULE hLib = NULL;
  340. hLib = LoadLibraryW(lpwszMod);
  341. return hLib;
  342. }
  343. /*****************************************************************************\
  344. * web_FindRCharW
  345. *
  346. * Searches for the first occurence of (cch) in a string in reverse order.
  347. *
  348. \*****************************************************************************/
  349. LPWSTR web_FindRCharW(
  350. LPWSTR lpszStr,
  351. WCHAR cch)
  352. {
  353. int nLimit;
  354. if (nLimit = lstrlenW(lpszStr)) {
  355. lpszStr += nLimit;
  356. while ((*lpszStr != cch) && nLimit--)
  357. lpszStr--;
  358. if (nLimit >= 0)
  359. return lpszStr;
  360. }
  361. return NULL;
  362. }
  363. /*****************************************************************************\
  364. * web_GetDrvDirW
  365. *
  366. * Returns: LPWSTR - the printer driver dir, minus the architecture subdir.
  367. * Example: Returns something like "%WINDIR%\SYSTEM32\SPOOL\DRIVERS"
  368. *
  369. \*****************************************************************************/
  370. LPWSTR web_GetDrvDirW(VOID)
  371. {
  372. LPWSTR lpwszDrvDir;
  373. LPWSTR lpwszFind;
  374. DWORD cbSize;
  375. //
  376. // Call once to get size of buffer needed.
  377. //
  378. cbSize = 0;
  379. GetPrinterDriverDirectoryW(NULL, NULL, 1, NULL, 0, &cbSize);
  380. //
  381. // Alloc a buffer.
  382. //
  383. if (cbSize && (lpwszDrvDir = (LPWSTR)web_GAlloc(cbSize)) ) {
  384. //
  385. // Get the driver directory.
  386. //
  387. if (GetPrinterDriverDirectoryW(NULL,
  388. NULL,
  389. 1,
  390. (LPBYTE)lpwszDrvDir,
  391. cbSize,
  392. &cbSize)) {
  393. //
  394. // Find the parent-directory of the driver-path.
  395. //
  396. if (lpwszFind = web_FindRCharW(lpwszDrvDir, L'\\')) {
  397. *lpwszFind = L'\0';
  398. return lpwszDrvDir;
  399. }
  400. }
  401. //
  402. // Free memory if we fail.
  403. //
  404. web_GFree(lpwszDrvDir);
  405. }
  406. return NULL;
  407. }
  408. /*****************************************************************************\
  409. * web_BuildNameW
  410. *
  411. * Takes path, name, extension strings and builds a fully-qualified
  412. * string representing the file. This can also be used to build other
  413. * names.
  414. *
  415. \*****************************************************************************/
  416. LPWSTR web_BuildNameW(
  417. LPCWSTR lpwszPath,
  418. LPCWSTR lpwszName,
  419. LPCWSTR lpwszExt)
  420. {
  421. DWORD cch;
  422. LPWSTR lpwszFull;
  423. //
  424. // Calculate the size necessary to hold the full-path filename.
  425. //
  426. cch = lstrlenW(L"\\");
  427. cch += (lpwszPath ? lstrlenW(lpwszPath) : 0);
  428. cch += (lpwszName ? lstrlenW(lpwszName) : 0);
  429. cch += (lpwszExt ? lstrlenW(lpwszExt) : 0);
  430. if (lpwszFull = (LPWSTR)web_GAlloc(((cch + 1) * sizeof(WCHAR)))) {
  431. if (lpwszPath) {
  432. if (lpwszExt)
  433. StringCchPrintfW(lpwszFull, cch+1, L"%s\\%s%s", lpwszPath, lpwszName, lpwszExt);
  434. else
  435. StringCchPrintfW(lpwszFull, cch+1, L"%s\\%s", lpwszPath, lpwszName);
  436. } else {
  437. if (lpwszExt)
  438. StringCchPrintfW(lpwszFull, cch+1, L"%s%s", lpwszName, lpwszExt);
  439. else
  440. StringCchPrintfW(lpwszFull, cch+1, L"%s", lpwszName);
  441. }
  442. }
  443. return lpwszFull;
  444. }
  445. /*****************************************************************************\
  446. * web_GetCurDirW
  447. *
  448. * Returns string indicating current-directory.
  449. *
  450. \*****************************************************************************/
  451. LPWSTR web_GetCurDirW(VOID)
  452. {
  453. DWORD cbSize;
  454. LPWSTR lpwszDir = NULL;
  455. cbSize = GetCurrentDirectoryW(0, NULL);
  456. if (cbSize && (lpwszDir = (LPWSTR)web_GAlloc((cbSize * sizeof(WCHAR)))))
  457. GetCurrentDirectoryW(cbSize, lpwszDir);
  458. return lpwszDir;
  459. }
  460. /*****************************************************************************\
  461. * web_MakeFullKeyW (Local Routine)
  462. *
  463. * Creates a full registry-key from the key/sub-key strings.
  464. *
  465. \*****************************************************************************/
  466. LPWSTR web_MakeFullKeyW(
  467. LPCWSTR lpszKey,
  468. LPCWSTR lpszSKey)
  469. {
  470. DWORD cbSize;
  471. LPWSTR lpszFKey = NULL;
  472. if (lpszKey && lpszSKey) {
  473. cbSize = web_StrSizeW(lpszKey) + web_StrSizeW(lpszSKey) + sizeof(WCHAR);
  474. if (lpszFKey = (LPWSTR)web_GAlloc(cbSize)) {
  475. if (*lpszKey)
  476. StringCbPrintfW(lpszFKey, cbSize, L"%ws\\%ws", lpszKey, lpszSKey);
  477. else
  478. StringCbPrintfW(lpszFKey, cbSize, L"%ws", lpszSKey);
  479. }
  480. }
  481. return lpszFKey;
  482. }
  483. /*****************************************************************************\
  484. * web_KeyExistsW (Local Routine)
  485. *
  486. * Checks to see if the printer-key exists.
  487. *
  488. \*****************************************************************************/
  489. BOOL web_KeyExistsW(
  490. HANDLE hPrinter,
  491. LPCWSTR lpszKey)
  492. {
  493. DWORD cbSize;
  494. DWORD dwRet;
  495. cbSize = 0;
  496. dwRet = EnumPrinterKeyW(hPrinter, lpszKey, NULL, 0, &cbSize);
  497. return (cbSize && (dwRet == ERROR_MORE_DATA));
  498. }
  499. /*****************************************************************************\
  500. * web_EnumPrinterSubKeysW (Local Routine)
  501. *
  502. * Returns an array of printer-keys for the specified key.
  503. *
  504. \*****************************************************************************/
  505. LPWSTR web_EnumPrinterSubKeysW(
  506. HANDLE hPrinter,
  507. LPCWSTR lpszKey)
  508. {
  509. DWORD cbSize;
  510. DWORD dwRet;
  511. LPWSTR aszSKeys;
  512. //
  513. // Determine the size necessary for enumerating all the
  514. // sub-keys for this key.
  515. //
  516. cbSize = 0;
  517. dwRet = EnumPrinterKeyW(hPrinter, lpszKey, NULL, 0, &cbSize);
  518. //
  519. // If OK, then proceed to the enumeration.
  520. //
  521. if (cbSize && (dwRet == ERROR_MORE_DATA)) {
  522. //
  523. // Allocate the space for retrieving the keys.
  524. //
  525. if (aszSKeys = (LPWSTR)web_GAlloc(cbSize)) {
  526. //
  527. // Enumerate the sub-keys for this level in (lpszKey).
  528. //
  529. dwRet = EnumPrinterKeyW(hPrinter, lpszKey, aszSKeys, cbSize, &cbSize);
  530. if (dwRet == ERROR_SUCCESS)
  531. return aszSKeys;
  532. web_GFree(aszSKeys);
  533. }
  534. }
  535. return NULL;
  536. }
  537. /*****************************************************************************\
  538. * web_EnumPrinterDataW (Local Routine)
  539. *
  540. * Returns an array of printer-data-values for the specified key.
  541. *
  542. \*****************************************************************************/
  543. LPPRINTER_ENUM_VALUES web_EnumPrinterDataW(
  544. HANDLE hPrinter,
  545. LPCWSTR lpszKey,
  546. LPDWORD lpcItems)
  547. {
  548. DWORD cbSize;
  549. DWORD dwRet;
  550. LPPRINTER_ENUM_VALUES apevData;
  551. //
  552. // Set the enumerated items to zero.
  553. //
  554. *lpcItems = 0;
  555. //
  556. // Determine the size necessary to store the enumerated data.
  557. //
  558. cbSize = 0;
  559. dwRet = EnumPrinterDataExW(hPrinter, lpszKey, NULL, 0, &cbSize, lpcItems);
  560. //
  561. // If OK, then proceed to enumerate and write the values to the
  562. // BIN-File.
  563. //
  564. if (cbSize && (dwRet == ERROR_MORE_DATA)) {
  565. if (apevData = (LPPRINTER_ENUM_VALUES)web_GAlloc(cbSize)) {
  566. //
  567. // Enumerate all values for the specified key. This
  568. // returns an array of value-structs.
  569. //
  570. dwRet = EnumPrinterDataExW(hPrinter,
  571. lpszKey,
  572. (LPBYTE)apevData,
  573. cbSize,
  574. &cbSize,
  575. lpcItems);
  576. if (dwRet == ERROR_SUCCESS)
  577. return apevData;
  578. web_GFree(apevData);
  579. }
  580. }
  581. return NULL;
  582. }
  583. /*****************************************************************************\
  584. * web_GetPrtNameW
  585. *
  586. * Returns a Wide-Char string representing the printer-name.
  587. *
  588. \*****************************************************************************/
  589. LPWSTR web_GetPrtNameW(
  590. HANDLE hPrinter)
  591. {
  592. DWORD cbSize;
  593. DWORD cbNeed;
  594. LPPRINTER_INFO_2W lppi;
  595. LPWSTR lpszPrtName = NULL;
  596. //
  597. // Get the necessary size for the printer-info-struct.
  598. //
  599. cbSize = 0;
  600. GetPrinterW(hPrinter, 2, NULL, 0, &cbSize);
  601. //
  602. // Allocate storage for holding the print-info structure.
  603. //
  604. if (cbSize && (lppi = (LPPRINTER_INFO_2W)web_GAlloc(cbSize))) {
  605. if (GetPrinterW(hPrinter, 2, (LPBYTE)lppi, cbSize, &cbNeed)) {
  606. lpszPrtName = web_GAllocStrW(lppi->pPrinterName);
  607. }
  608. web_GFree(lppi);
  609. }
  610. return lpszPrtName;
  611. }
  612. /*****************************************************************************\
  613. * web_GetPrtDataW (Local Routine)
  614. *
  615. * Returns data for the specified key.
  616. *
  617. \*****************************************************************************/
  618. LPBYTE web_GetPrtDataW(
  619. HANDLE hPrinter,
  620. LPCWSTR lpszKey,
  621. LPCWSTR lpszVal)
  622. {
  623. DWORD dwType;
  624. DWORD cbSize;
  625. DWORD dwRet;
  626. LPBYTE lpData;
  627. cbSize = 0;
  628. GetPrinterDataExW(hPrinter, lpszKey, lpszVal, &dwType, NULL, 0, &cbSize);
  629. if (cbSize && (lpData = (LPBYTE)web_GAlloc(cbSize))) {
  630. dwRet = GetPrinterDataExW(hPrinter,
  631. lpszKey,
  632. lpszVal,
  633. &dwType,
  634. lpData,
  635. cbSize,
  636. &cbSize);
  637. if (dwRet == ERROR_SUCCESS)
  638. return lpData;
  639. web_GFree(lpData);
  640. }
  641. return NULL;
  642. }
  643. /*****************************************************************************\
  644. * web_CreateDirW (Local Routine)
  645. *
  646. * Creates the specified directory, if it doesn't exist.
  647. *
  648. \*****************************************************************************/
  649. BOOL web_CreateDirW(
  650. LPCWSTR lpwszDir)
  651. {
  652. HANDLE hDir;
  653. BOOL bRet = FALSE;
  654. hDir = web_OpenDirectoryW(lpwszDir);
  655. if (hDir && (hDir != INVALID_HANDLE_VALUE)) {
  656. CloseHandle(hDir);
  657. bRet = TRUE;
  658. } else {
  659. bRet = CreateDirectoryW(lpwszDir, NULL);
  660. }
  661. return bRet;
  662. }
  663. /*****************************************************************************\
  664. * web_GetICMDirW (Local Routine)
  665. *
  666. * Loads the ICM-Module and returns the target color-directory. If the
  667. * module isn't loaded then return NULL indicating there is no color
  668. * modules to load.
  669. *
  670. \*****************************************************************************/
  671. LPWSTR web_GetICMDirW(
  672. HANDLE hPrinter,
  673. DWORD dwCliInfo,
  674. LPCWSTR lpwszDir,
  675. LPCWSTR lpwszKey)
  676. {
  677. HMODULE hLib;
  678. LPWSTR lpwszMod;
  679. WEBGENCOPYFILEPATHPROC pfn;
  680. SPLCLIENT_INFO_1 sci;
  681. LPWSTR lpwszSrc;
  682. LPWSTR lpwszDst;
  683. LPWSTR lpwszDrv;
  684. LPWSTR lpwszPrtName;
  685. DWORD cbSrc;
  686. DWORD cbDst;
  687. DWORD dwRet;
  688. LPWSTR lpwszRet = NULL;
  689. //
  690. // Load associated module. (e.g. color module)
  691. //
  692. if (lpwszMod = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszMod)) {
  693. if (hLib = web_LoadModuleW(lpwszMod)) {
  694. //
  695. // Call into module to normalize the source/target
  696. // paths.
  697. //
  698. if (pfn = (WEBGENCOPYFILEPATHPROC)GetProcAddress(hLib, s_szGCFP)) {
  699. if (lpwszPrtName = web_GetPrtNameW(hPrinter)) {
  700. if (lpwszDrv = web_GetDrvDirW()) {
  701. cbSrc = (MAX_PATH + INTERNET_MAX_HOST_NAME_LENGTH + 1) * sizeof(WCHAR);
  702. cbDst = (MAX_PATH + 1) * sizeof(WCHAR);
  703. if (lpwszSrc = (LPWSTR)web_GAlloc(cbSrc)) {
  704. if (lpwszDst = (LPWSTR)web_GAlloc(cbDst)) {
  705. sci.dwSize = sizeof(SPLCLIENT_INFO_1);
  706. sci.pMachineName = NULL;
  707. sci.pUserName = NULL;
  708. sci.dwBuildNum = 0;
  709. sci.dwMajorVersion = webGetOSMajorVer(dwCliInfo);
  710. sci.dwMinorVersion = webGetOSMinorVer(dwCliInfo);
  711. StringCbPrintfW(lpwszSrc, cbSrc, L"%s\\%s", lpwszDrv, lpwszDir);
  712. StringCbCopyW(lpwszDst, cbDst, lpwszDir);
  713. dwRet = (*pfn)(lpwszPrtName,
  714. lpwszDir,
  715. (LPBYTE)&sci,
  716. 1,
  717. lpwszSrc,
  718. &cbSrc,
  719. lpwszDst,
  720. &cbDst,
  721. COPYFILE_FLAG_SERVER_SPOOLER);
  722. if (dwRet == ERROR_SUCCESS) {
  723. lpwszRet = web_GAllocStrW(lpwszDst);
  724. }
  725. web_GFree(lpwszDst);
  726. }
  727. web_GFree(lpwszSrc);
  728. }
  729. web_GFree(lpwszDrv);
  730. }
  731. web_GFree(lpwszPrtName);
  732. }
  733. }
  734. FreeLibrary(hLib);
  735. }
  736. web_GFree(lpwszMod);
  737. }
  738. return lpwszRet;
  739. }
  740. /*****************************************************************************\
  741. * web_BuildCopyDirW (Local Routine)
  742. *
  743. * This routine builds the src or dst directory for the CopyFiles. It does the
  744. * following things:
  745. *
  746. * 1) loads optional module (if exists) and calls into it to adjust pathnames
  747. * 2) builds fully-qualified CopyFiles directory
  748. * 3) return the directory name
  749. *
  750. * Upon return this will represent the true path to the ICM profiles for the
  751. * specified key.
  752. *
  753. \*****************************************************************************/
  754. LPWSTR web_BuildCopyDirW(
  755. HANDLE hPrinter,
  756. DWORD dwCliInfo,
  757. LPCWSTR lpwszKey)
  758. {
  759. LPWSTR lpwszDir;
  760. LPWSTR lpwszDrvDir;
  761. LPWSTR lpwszICM;
  762. LPWSTR lpwszRet = NULL;
  763. //
  764. // Return the directory-value for the specified ICM key.
  765. //
  766. if (lpwszDir = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszDir)) {
  767. //
  768. // Return the printer-driver-directory-root.
  769. //
  770. if (lpwszDrvDir = web_GetDrvDirW()) {
  771. //
  772. // If called from the server, then call into the color-module
  773. // to get the target-directory. Otherwise, just return the
  774. // driver directory.
  775. //
  776. lpwszICM = web_GetICMDirW(hPrinter, dwCliInfo, lpwszDir, lpwszKey);
  777. //
  778. // If the module loaded and return a valid target-directory, then
  779. // we can return this as our path to the ICM profiles.
  780. //
  781. if (lpwszICM != NULL) {
  782. lpwszRet = web_BuildNameW( lpwszDrvDir, lpwszICM, NULL);
  783. web_GFree(lpwszICM); // Free up the memory allocated in web_GetICMDirW
  784. }
  785. web_GFree(lpwszDrvDir);
  786. }
  787. web_GFree(lpwszDir);
  788. }
  789. return lpwszRet;
  790. }
  791. /*****************************************************************************\
  792. * web_CopyFilesW (Local Routine)
  793. *
  794. * This routine copies the point & print "CopyFiles" for the given key.
  795. * It copies files from the web point & print setup-source to the directory
  796. * specified by the "Directory" value under given key.
  797. *
  798. * Use : Processed in the context of the print-client.
  799. *
  800. \*****************************************************************************/
  801. BOOL web_CopyFilesW(
  802. HANDLE hPrinter,
  803. LPCWSTR lpwszDir,
  804. LPCWSTR lpwszKey)
  805. {
  806. LPWSTR awszFiles;
  807. LPWSTR lpwszFile;
  808. LPWSTR lpwszCurDir;
  809. LPWSTR lpwszSrcFile;
  810. LPWSTR lpwszDstFile;
  811. LPWSTR lpwszPrtName;
  812. BOOL bRet = FALSE;
  813. //
  814. // Get the files under the specified ICM key.
  815. //
  816. if (awszFiles = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszFil)) {
  817. //
  818. // Get our current-directory.
  819. //
  820. if (lpwszCurDir = web_GetCurDirW()) {
  821. if (lpwszPrtName = web_GetPrtNameW(hPrinter)) {
  822. //
  823. // For each file in the list, we will need to build our source
  824. // and destination directories to copy our ICM profiles.
  825. //
  826. for (bRet = TRUE, lpwszFile = awszFiles; bRet && *lpwszFile; ) {
  827. bRet = FALSE;
  828. if (lpwszSrcFile = web_BuildNameW(lpwszCurDir, lpwszFile, NULL)) {
  829. if (lpwszDstFile = web_BuildNameW(lpwszDir, lpwszFile, NULL)) {
  830. //
  831. // Copy the ICM profile to the target directory.
  832. //
  833. bRet = CopyFileW(lpwszSrcFile, lpwszDstFile, FALSE);
  834. web_GFree(lpwszDstFile);
  835. }
  836. web_GFree(lpwszSrcFile);
  837. }
  838. lpwszFile = web_NextStrW(lpwszFile);
  839. }
  840. web_GFree(lpwszPrtName);
  841. }
  842. web_GFree(lpwszCurDir);
  843. }
  844. web_GFree(awszFiles);
  845. }
  846. return bRet;
  847. }
  848. /*****************************************************************************\
  849. * web_TraverseCopyFilesW (Local Routine)
  850. *
  851. * This routine recursively traverses the printer-registry-settings for
  852. * the CopyFiles keys.
  853. *
  854. * Use : Processed in the context of the print-client.
  855. *
  856. \*****************************************************************************/
  857. BOOL web_TraverseCopyFilesW(
  858. HANDLE hPrinter,
  859. LPCWSTR lpwszDir,
  860. LPCWSTR lpwszKey)
  861. {
  862. LPWSTR awszSKeys;
  863. LPWSTR lpwszSKey;
  864. LPWSTR lpwszFKey;
  865. LPWSTR lpwszFDir;
  866. DWORD dwType;
  867. DWORD dwCliInfo;
  868. BOOL bRet = FALSE;
  869. //
  870. // Get the array of keys under the specified key in the registry.
  871. //
  872. if (awszSKeys = web_EnumPrinterSubKeysW(hPrinter, lpwszKey)) {
  873. //
  874. // For each sub-key in the array, we need to build the path of
  875. // where we'll place the ICM files.
  876. //
  877. for (bRet = TRUE, lpwszSKey = awszSKeys; *lpwszSKey && bRet; ) {
  878. bRet = FALSE;
  879. //
  880. // The enum-routine returns a relative path, so we must build
  881. // a fully-qualified registry-path.
  882. //
  883. if (lpwszFKey = web_MakeFullKeyW(lpwszKey, lpwszSKey)) {
  884. dwCliInfo = webCreateOSInfo();
  885. if (lpwszFDir = web_BuildCopyDirW(hPrinter, dwCliInfo, lpwszFKey)) {
  886. //
  887. // Create the ICM directory if it doesn't exist. Proceed
  888. // to traverse the ICM-keys for more sub-keys.
  889. //
  890. if (web_CreateDirW(lpwszFDir))
  891. bRet = web_TraverseCopyFilesW(hPrinter, lpwszFDir, lpwszFKey);
  892. web_GFree(lpwszFDir);
  893. }
  894. web_GFree(lpwszFKey);
  895. }
  896. lpwszSKey = web_NextStrW(lpwszSKey);
  897. }
  898. //
  899. // Free up the array.
  900. //
  901. web_GFree(awszSKeys);
  902. //
  903. // Process the ICM files for the specified key. If this
  904. // is our top-level key (CopyFiles), then don't bother
  905. // with the initialization. i.e. there should be no
  906. // (module, files, directory) keys at this level.
  907. //
  908. if (bRet && lstrcmpiW(lpwszKey, s_wszCopyFiles))
  909. bRet = web_CopyFilesW(hPrinter, lpwszDir, lpwszKey);
  910. }
  911. return bRet;
  912. }
  913. /*****************************************************************************\
  914. * web_WriteHeader (Local Routine)
  915. *
  916. * Outputs the header for the BIN-file. The parameters to this routine
  917. * specify whether there is a DEVMODE contained in the file, as well as a
  918. * count of all the device-data-items.
  919. *
  920. \*****************************************************************************/
  921. BOOL web_WriteHeader(
  922. HANDLE hFile,
  923. DWORD cItems,
  924. BOOL bDevMode)
  925. {
  926. DWORD dwWr = 0;
  927. DEVBIN_HEAD dbh;
  928. BOOL bRet;
  929. //
  930. // Setup the header information.
  931. //
  932. dbh.cItems = cItems;
  933. dbh.bDevMode = bDevMode;
  934. //
  935. // Make sure our header is positioned at the beginning of the file.
  936. //
  937. SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  938. //
  939. // Write out the header. Check to make sure that all was written
  940. // succesfully.
  941. //
  942. bRet = WriteFile(hFile, &dbh, sizeof(DEVBIN_HEAD), &dwWr, NULL);
  943. return ((bRet && (dwWr != sizeof(DEVBIN_HEAD))) ? FALSE : bRet);
  944. }
  945. /*****************************************************************************\
  946. * web_ReadDevMode (Local Routine)
  947. *
  948. * Reads the devmode-structure from the BIN-File and sets the printer with
  949. * the information. Since our data from the BIN-File is in the format
  950. * of UNICODE, we must take care to only use (W) functions.
  951. *
  952. * Use : Processed in the context of the print-client.
  953. *
  954. \*****************************************************************************/
  955. BOOL web_ReadDevMode(
  956. LPDEVBIN_HEAD lpdbh,
  957. HANDLE hPrinter,
  958. LPCTSTR lpszPrtName)
  959. {
  960. LPDEVBIN_INFO lpdbi;
  961. LPPRINTER_INFO_2W lppi;
  962. LPDEVMODEW lpdm;
  963. DWORD cbSize;
  964. DWORD cbNeed;
  965. BOOL bRet = FALSE;
  966. //
  967. // Set our pointer past the header. The DEVMODE always occupies the
  968. // first entry in our item-list.
  969. //
  970. lpdbi = (LPDEVBIN_INFO)(lpdbh + 1);
  971. //
  972. // First let's see how big our buffer will need to
  973. // be in order to hold the PRINTER_INFO_2W.
  974. //
  975. cbSize = 0;
  976. GetPrinterW(hPrinter, 2, NULL, 0, &cbSize);
  977. //
  978. // Allocate storage for holding the print-info structure as well
  979. // as the new devmode data we will be copying.
  980. //
  981. if (cbSize && (lppi = (LPPRINTER_INFO_2W)web_GAlloc(cbSize + lpdbi->cbData))) {
  982. //
  983. // Retrieve our current printer-settings.
  984. //
  985. if (GetPrinterW(hPrinter, 2, (LPBYTE)lppi, cbSize, &cbNeed)) {
  986. //
  987. // If our printer has a DEVMODE, then we can continue on
  988. // with initializing it with our BIN-File DEVMODE. Otherwise,
  989. // there's no sense setting a devmode to a printer that
  990. // doesn't have one...return TRUE in this case.
  991. //
  992. if (lppi->pDevMode) {
  993. //
  994. // Set the new devmode pointer. We will be appending our
  995. // DEVMODE (from the file) to the PRINTER_INFO_2 structure
  996. // that we have just grabbed. Reset the pointers to
  997. // reflect the new-position of the DEVMODE.
  998. //
  999. lppi->pDevMode = (LPDEVMODEW)(((LPBYTE)lppi) + cbSize);
  1000. lpdm = lppi->pDevMode;
  1001. //
  1002. // Copy our new devmode to the printer-info struct.
  1003. // This is appended on to the structure.
  1004. //
  1005. // Since this data was obtained by file, the pointer
  1006. // is actually a byte offset.
  1007. //
  1008. CopyMemory(lpdm,
  1009. ((LPBYTE)lpdbi) + lpdbi->pData,
  1010. lpdbi->cbData);
  1011. //
  1012. // Copy the new printer-name to the DEVMODE. Since our
  1013. // routines deal strictly with unicode, we need to do
  1014. // the correct conversion in case this library was built
  1015. // as ansi.
  1016. //
  1017. #ifdef UNICODE
  1018. StringCchCopy(lpdm->dmDeviceName, CCHDEVICENAME, lpszPrtName);
  1019. #else
  1020. lpdm->dmDeviceName[CCHDEVICENAME - 1] = (WCHAR)0;
  1021. web_MBtoWC(lpdm->dmDeviceName,
  1022. lpszPrtName,
  1023. sizeof(lpdm->dmDeviceName) - sizeof(WCHAR));
  1024. #endif
  1025. //
  1026. // Write out our new printer-settings.
  1027. //
  1028. bRet = SetPrinterW(hPrinter, 2, (LPBYTE)lppi, 0);
  1029. } else {
  1030. bRet = TRUE;
  1031. }
  1032. }
  1033. web_GFree(lppi);
  1034. }
  1035. return bRet;
  1036. }
  1037. /*****************************************************************************\
  1038. * web_ReadDevData (Local Routine)
  1039. *
  1040. * Reads the device-configuration-data from the BIN-File and sets the
  1041. * printer with the information.
  1042. *
  1043. * Use : Processed in the context of the print-client.
  1044. *
  1045. \*****************************************************************************/
  1046. BOOL web_ReadDevData(
  1047. LPDEVBIN_HEAD lpdbh,
  1048. HANDLE hPrinter)
  1049. {
  1050. LPDEVBIN_INFO lpdbi;
  1051. LPWSTR lpszKey;
  1052. LPWSTR lpszVal;
  1053. LPBYTE lpbData;
  1054. DWORD idx;
  1055. DWORD dwRet;
  1056. BOOL bRet;
  1057. PWSTR lpszNewKey = NULL;
  1058. PWSTR lpszNewVal = NULL;
  1059. PBYTE lpbNewData = NULL;
  1060. //
  1061. // Set our pointer past the header. The DEVMODE always occupies the
  1062. // first entry (If a DEVMODE exists).
  1063. //
  1064. lpdbi = (LPDEVBIN_INFO)(lpdbh + 1);
  1065. //
  1066. // If there's a DEVMODE, skip over it and point to the Printer-Data
  1067. // entries.
  1068. //
  1069. if (lpdbh->bDevMode)
  1070. lpdbi = web_NextItem(lpdbi);
  1071. //
  1072. // Loop through our items and set the data to the registry.
  1073. //
  1074. for (idx = 0, bRet = TRUE; (idx < lpdbh->cItems) && bRet; idx++) {
  1075. //
  1076. // Remarshall the byte-offsets into pointers.
  1077. //
  1078. lpszKey = (LPWSTR)(((LPBYTE)lpdbi) + lpdbi->pKey);
  1079. lpszVal = (LPWSTR)(((LPBYTE)lpdbi) + lpdbi->pValue);
  1080. lpbData = (LPBYTE)(((LPBYTE)lpdbi) + lpdbi->pData);
  1081. //
  1082. // We have to copy the data into a new buffer to avoid 64 bit mis-alignment.
  1083. //
  1084. lpszNewKey = new WCHAR[(lpdbi->pValue - lpdbi->pKey) / sizeof (WCHAR)];
  1085. lpszNewVal = new WCHAR[(lpdbi->pData - lpdbi->pValue) / sizeof (WCHAR)];
  1086. lpbNewData = new BYTE[lpdbi->cbData];
  1087. if (!lpszNewKey || !lpszVal || !lpbData)
  1088. {
  1089. bRet = FALSE;
  1090. }
  1091. else
  1092. {
  1093. CopyMemory (lpszNewKey, lpszKey, lpdbi->pValue - lpdbi->pKey);
  1094. CopyMemory (lpszNewVal, lpszVal, lpdbi->pData - lpdbi->pValue);
  1095. CopyMemory (lpbNewData, lpbData, lpdbi->cbData);
  1096. }
  1097. if (bRet)
  1098. {
  1099. //
  1100. // Set the printer-data. Since our file-format
  1101. // deals with UNICODE-strings, we will use the
  1102. // Wide-API.
  1103. //
  1104. dwRet = SetPrinterDataExW(hPrinter,
  1105. lpszNewKey,
  1106. lpszNewVal,
  1107. lpdbi->dwType,
  1108. lpbNewData,
  1109. lpdbi->cbData);
  1110. //
  1111. // If the data is set-correctly, then continue on
  1112. // to the next-item. Otherwise, set us up to return
  1113. // false.
  1114. //
  1115. if (dwRet == ERROR_SUCCESS) {
  1116. lpdbi = web_NextItem(lpdbi);
  1117. } else {
  1118. bRet = FALSE;
  1119. }
  1120. }
  1121. if (lpszNewKey)
  1122. {
  1123. delete [] lpszNewKey;
  1124. lpszNewKey = NULL;
  1125. }
  1126. if (lpszNewVal)
  1127. {
  1128. delete [] lpszNewVal;
  1129. lpszNewVal = NULL;
  1130. }
  1131. if (lpbNewData)
  1132. {
  1133. delete [] lpbNewData;
  1134. lpbNewData = NULL;
  1135. }
  1136. }
  1137. //
  1138. // Once the registry is initialized with the printer-data, we need
  1139. // to parse the printer-data-registry for the ICM (CopyFiles), to
  1140. // initialize ICM profiles.
  1141. //
  1142. if (bRet && web_KeyExistsW(hPrinter, s_wszCopyFiles))
  1143. bRet = web_TraverseCopyFilesW(hPrinter, NULL, s_wszCopyFiles);
  1144. return bRet;
  1145. }
  1146. /*****************************************************************************\
  1147. * web_WriteDevMode (Local Routine)
  1148. *
  1149. * Output the DEVMODEW struct to the BIN-File. Since we are storing this
  1150. * to a file, we make sure that our format is consistent across various
  1151. * processes. Our choice is to use UNICODE API as a means to query and store
  1152. * the DEVMODE information.
  1153. *
  1154. \*****************************************************************************/
  1155. BOOL web_WriteDevMode(
  1156. HANDLE hFile,
  1157. HANDLE hPrinter,
  1158. LPBOOL lpbDevMode)
  1159. {
  1160. DWORD cbSize;
  1161. DWORD cbNeed;
  1162. DWORD cbDevMode;
  1163. DWORD dwWr;
  1164. LPDEVBIN_INFO lpdbi;
  1165. LPPRINTER_INFO_2W lppi;
  1166. BOOL bRet = FALSE;
  1167. //
  1168. // Set the default return for a devmode.
  1169. //
  1170. *lpbDevMode = FALSE;
  1171. //
  1172. // Retrieve the size to store the printer-info-2 struct.
  1173. //
  1174. cbSize = 0;
  1175. GetPrinterW(hPrinter, 2, NULL, 0, &cbSize);
  1176. //
  1177. // Allocate the printer-info-2 struct and proceed
  1178. // to pull out the devmode information.
  1179. //
  1180. if (cbSize && (lppi = (LPPRINTER_INFO_2W)web_GAlloc(cbSize))) {
  1181. //
  1182. // Retreive the printer-info-2 and write out the
  1183. // DEVMODEW part of this structure.
  1184. //
  1185. if (GetPrinterW(hPrinter, 2, (LPBYTE)lppi, cbSize, &cbNeed)) {
  1186. //
  1187. // Allocate space for the devmode and our header information.
  1188. // Align this on DWORD boundries.
  1189. //
  1190. if (lppi->pDevMode) {
  1191. //
  1192. // The DEVMODE will need to include driver-specific
  1193. // information if such is stored in this DEVMODE.
  1194. //
  1195. cbDevMode = lppi->pDevMode->dmSize +
  1196. lppi->pDevMode->dmDriverExtra;
  1197. //
  1198. // Calculate the DWORD aligned size that we will need
  1199. // to store our DEVMODE information to file.
  1200. //
  1201. cbSize = web_AlignSize(sizeof(DEVBIN_INFO) + cbDevMode);
  1202. //
  1203. // Get the DEVMODE from the PRINTER_INFO_2 struct. and
  1204. // write to file. We want to take care to
  1205. //
  1206. if (lpdbi = (LPDEVBIN_INFO)web_GAlloc(cbSize)) {
  1207. //
  1208. // Setup our memory-block. The DEVMODEW will
  1209. // occupy the first item in the array. Since
  1210. // it's not associated with printer-data-information,
  1211. // we will not store any (NAME and TYPE).
  1212. //
  1213. // Since this structure will inevitably be written
  1214. // to file, we must marshall the pointers and store
  1215. // only byte-offsets.
  1216. //
  1217. lpdbi->cbSize = cbSize;
  1218. lpdbi->dwType = 0;
  1219. lpdbi->pKey = 0;
  1220. lpdbi->pValue = 0;
  1221. lpdbi->pData = sizeof(DEVBIN_INFO);
  1222. lpdbi->cbData = cbDevMode;
  1223. CopyMemory(((LPBYTE)lpdbi) + lpdbi->pData,
  1224. lppi->pDevMode,
  1225. cbDevMode);
  1226. //
  1227. // Write the information to file. Check the return
  1228. // to verify bytes were written correctly.
  1229. //
  1230. bRet = WriteFile(hFile, lpdbi, cbSize, &dwWr, NULL);
  1231. if (bRet && (dwWr != cbSize))
  1232. bRet = FALSE;
  1233. //
  1234. // Indicate that a devmode was written.
  1235. //
  1236. *lpbDevMode = TRUE;
  1237. web_GFree(lpdbi);
  1238. }
  1239. } else {
  1240. bRet = TRUE;
  1241. *lpbDevMode = FALSE;
  1242. }
  1243. }
  1244. web_GFree(lppi);
  1245. }
  1246. return bRet;
  1247. }
  1248. /*****************************************************************************\
  1249. * web_WriteKeyItem (Local Routine)
  1250. *
  1251. * Writes one item to the file.
  1252. *
  1253. \*****************************************************************************/
  1254. BOOL web_WriteKeyItem(
  1255. HANDLE hFile,
  1256. LPCWSTR lpszKey,
  1257. LPPRINTER_ENUM_VALUES lpPEV)
  1258. {
  1259. DWORD cbKeySize;
  1260. DWORD cbKey;
  1261. DWORD cbName;
  1262. DWORD cbSize;
  1263. DWORD dwWr;
  1264. LPDEVBIN_INFO lpdbi;
  1265. BOOL bWrite = FALSE;
  1266. //
  1267. // Calculate aligned sizes for the key-name and key-value strings.
  1268. //
  1269. cbKeySize = web_StrSizeW(lpszKey);
  1270. cbKey = web_AlignSize(cbKeySize);
  1271. cbName = web_AlignSize(lpPEV->cbValueName);
  1272. //
  1273. // Calculate size necessary to hold our DEVBIN_INFO information
  1274. // which is written to file.
  1275. //
  1276. cbSize = sizeof(DEVBIN_INFO) + cbKey + cbName + web_AlignSize (lpPEV->cbData);
  1277. //
  1278. // Allocate space for the structure.
  1279. //
  1280. if (lpdbi = (LPDEVBIN_INFO)web_GAlloc(cbSize)) {
  1281. //
  1282. // Initialize the structure elements. Since this information
  1283. // is written to file, we must take care to convert the
  1284. // pointers to byte-offsets.
  1285. //
  1286. lpdbi->cbSize = cbSize;
  1287. lpdbi->dwType = lpPEV->dwType;
  1288. lpdbi->pKey = sizeof(DEVBIN_INFO);
  1289. lpdbi->pValue = lpdbi->pKey + cbKey;
  1290. lpdbi->pData = lpdbi->pValue + cbName;
  1291. lpdbi->cbData = lpPEV->cbData;
  1292. CopyMemory(((LPBYTE)lpdbi) + lpdbi->pKey , lpszKey , cbKeySize);
  1293. CopyMemory(((LPBYTE)lpdbi) + lpdbi->pValue, lpPEV->pValueName, lpPEV->cbValueName);
  1294. CopyMemory(((LPBYTE)lpdbi) + lpdbi->pData , lpPEV->pData , lpPEV->cbData);
  1295. bWrite = WriteFile(hFile, lpdbi, lpdbi->cbSize, &dwWr, NULL);
  1296. if (bWrite && (dwWr != lpdbi->cbSize))
  1297. bWrite = FALSE;
  1298. web_GFree(lpdbi);
  1299. }
  1300. return bWrite;
  1301. }
  1302. /*****************************************************************************\
  1303. * web_WriteKeyData (Local Routine)
  1304. *
  1305. * Outputs the Printer-Configuration-Data to the BIN-File. This writes
  1306. * all info for the specified key.
  1307. *
  1308. * returns: number of items written to file.
  1309. * (-1) if an error occurs.
  1310. *
  1311. \*****************************************************************************/
  1312. int web_WriteKeyData(
  1313. HANDLE hFile,
  1314. HANDLE hPrinter,
  1315. LPCWSTR lpszKey)
  1316. {
  1317. LPPRINTER_ENUM_VALUES apevData;
  1318. BOOL bWr;
  1319. int idx;
  1320. int nItems = -1;
  1321. //
  1322. // Only write data if we are given a valid-key.
  1323. //
  1324. if ((lpszKey == NULL) || (*lpszKey == (WCHAR)0))
  1325. return 0;
  1326. //
  1327. // Enumerate all data for the specified key and write to the file.
  1328. //
  1329. if (apevData = web_EnumPrinterDataW(hPrinter, lpszKey, (LPDWORD)&nItems)) {
  1330. //
  1331. // Write all the values for this key.
  1332. //
  1333. for (idx = 0, bWr = TRUE; (idx < nItems) && bWr; idx++)
  1334. bWr = web_WriteKeyItem(hFile, lpszKey, apevData + idx);
  1335. if (bWr == FALSE)
  1336. nItems = -1;
  1337. web_GFree(apevData);
  1338. }
  1339. return nItems;
  1340. }
  1341. /*****************************************************************************\
  1342. * web_WriteDevData (Local Routine)
  1343. *
  1344. * Recursively traverses the printer registry and writes out the settings
  1345. * to file.
  1346. *
  1347. \*****************************************************************************/
  1348. BOOL web_WriteDevData(
  1349. HANDLE hFile,
  1350. HANDLE hPrinter,
  1351. LPCWSTR lpszKey,
  1352. LPDWORD lpcItems)
  1353. {
  1354. LPWSTR aszSKeys;
  1355. LPWSTR lpszSKey;
  1356. LPWSTR lpszFKey;
  1357. DWORD dwRet;
  1358. INT cItems;
  1359. BOOL bRet = FALSE;
  1360. if (aszSKeys = web_EnumPrinterSubKeysW(hPrinter, lpszKey)) {
  1361. for (bRet = TRUE, lpszSKey = aszSKeys; *lpszSKey && bRet; ) {
  1362. if (lpszFKey = web_MakeFullKeyW(lpszKey, lpszSKey)) {
  1363. bRet = web_WriteDevData(hFile, hPrinter, lpszFKey, lpcItems);
  1364. web_GFree(lpszFKey);
  1365. }
  1366. lpszSKey = web_NextStrW(lpszSKey);
  1367. }
  1368. //
  1369. // Free up the array.
  1370. //
  1371. web_GFree(aszSKeys);
  1372. //
  1373. // Write the keys/values to the file.
  1374. //
  1375. if (bRet) {
  1376. cItems = web_WriteKeyData(hFile, hPrinter, lpszKey);
  1377. if (cItems >= 0)
  1378. *lpcItems += cItems;
  1379. else
  1380. bRet = FALSE;
  1381. }
  1382. }
  1383. return bRet;
  1384. }
  1385. /*****************************************************************************\
  1386. * web_ICMEnumCallBack (Local Routine)
  1387. *
  1388. * This routine takes the UNICODE (lpwszDir, lpwszFile) and converts it to
  1389. * the appropriate string prior to making the callback to the caller.
  1390. *
  1391. * Use : Processed in the context of the print-server.
  1392. *
  1393. \*****************************************************************************/
  1394. BOOL web_ICMEnumCallBack(
  1395. LPCWSTR lpwszDir,
  1396. LPCWSTR lpwszFile,
  1397. FARPROC fpEnum,
  1398. LPVOID lpParm)
  1399. {
  1400. LPTSTR lpszDir;
  1401. LPTSTR lpszFile;
  1402. BOOL bRet = FALSE;
  1403. if (lpszDir = web_WCtoTC(lpwszDir, lstrlenW(lpwszDir) + 1)) {
  1404. if (lpszFile = web_WCtoTC(lpwszFile, lstrlenW(lpwszFile) + 1)) {
  1405. bRet = (*(WEBENUMICMPROC)fpEnum)(lpszDir, lpszFile, lpParm);
  1406. web_GFree(lpszFile);
  1407. }
  1408. web_GFree(lpszDir);
  1409. }
  1410. return bRet;
  1411. }
  1412. /*****************************************************************************\
  1413. * web_EnumFilesW (Local Routine)
  1414. *
  1415. * This routine enums the point & print "files" under the "copyfiles" path
  1416. * for the printer. This is called once we're at the end of a sub-key list
  1417. * in the registry.
  1418. *
  1419. * Use : Processed in the context of the print-server.
  1420. *
  1421. \*****************************************************************************/
  1422. BOOL web_EnumFilesW(
  1423. HANDLE hPrinter,
  1424. DWORD dwCliInfo,
  1425. LPCWSTR lpwszKey,
  1426. FARPROC fpEnum,
  1427. LPVOID lpParm)
  1428. {
  1429. LPWSTR awszFiles;
  1430. LPWSTR lpwszFile;
  1431. LPWSTR lpwszDir;
  1432. BOOL bRet = FALSE;
  1433. //
  1434. // For this ICM key, we will grab the list of ICM profiles that are
  1435. // necessary.
  1436. //
  1437. if (awszFiles = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszFil)) {
  1438. //
  1439. // Get the src-directory for the ICM profiles under the given key.
  1440. //
  1441. if (lpwszDir = web_BuildCopyDirW(hPrinter, dwCliInfo, lpwszKey)) {
  1442. for (bRet = TRUE, lpwszFile = awszFiles; *lpwszFile && bRet; ) {
  1443. //
  1444. // Make the callback to the caller. In order to do this,
  1445. // we must make sure our strings are in the appropriate
  1446. // format according to what the caller expects (ie. unicode
  1447. // or ansi).
  1448. //
  1449. bRet = web_ICMEnumCallBack(lpwszDir, lpwszFile, fpEnum, lpParm);
  1450. lpwszFile = web_NextStrW(lpwszFile);
  1451. }
  1452. web_GFree(lpwszDir);
  1453. }
  1454. web_GFree(awszFiles);
  1455. }
  1456. return bRet;
  1457. }
  1458. /*****************************************************************************\
  1459. * web_EnumCopyFilesW (similar to TraverseCopyFiles) (Local Routine)
  1460. *
  1461. * This routine recursively traverses the printer-registry-settings for
  1462. * the CopyFiles keys. Since the API's used in this routine are only
  1463. * available in UNICODE, this should be a (W) type routine.
  1464. *
  1465. * Use : Processed in the context of the print-server.
  1466. *
  1467. \*****************************************************************************/
  1468. BOOL web_EnumCopyFilesW(
  1469. HANDLE hPrinter,
  1470. DWORD dwCliInfo,
  1471. LPCWSTR lpwszKey,
  1472. FARPROC fpEnum,
  1473. LPVOID lpParm)
  1474. {
  1475. LPWSTR awszSKeys;
  1476. LPWSTR lpwszSKey;
  1477. LPWSTR lpwszFKey;
  1478. DWORD dwType;
  1479. BOOL bRet = FALSE;
  1480. //
  1481. // Returns an array of keys stored under the printer registry.
  1482. //
  1483. if (awszSKeys = web_EnumPrinterSubKeysW(hPrinter, lpwszKey)) {
  1484. //
  1485. // For each key, look to see if it contains other sub-keys. We
  1486. // recursively traverse the registry until we hit a key with
  1487. // no sub-keys.
  1488. //
  1489. for (bRet = TRUE, lpwszSKey = awszSKeys; *lpwszSKey && bRet; ) {
  1490. bRet = FALSE;
  1491. //
  1492. // Since the enum-routine only returns relative key-values,
  1493. // we need to build the fully-qualified key-path.
  1494. //
  1495. if (lpwszFKey = web_MakeFullKeyW(lpwszKey, lpwszSKey)) {
  1496. bRet = web_EnumCopyFilesW(hPrinter,
  1497. dwCliInfo,
  1498. lpwszFKey,
  1499. fpEnum,
  1500. lpParm);
  1501. web_GFree(lpwszFKey);
  1502. }
  1503. //
  1504. // Next key in list.
  1505. //
  1506. lpwszSKey = web_NextStrW(lpwszSKey);
  1507. }
  1508. //
  1509. // Free up the array.
  1510. //
  1511. web_GFree(awszSKeys);
  1512. //
  1513. // Process the files for the specified key. If this
  1514. // is our top-level key (CopyFiles), then don't bother
  1515. // with the initialization. i.e. there should be no
  1516. // (module, files, directory) keys at this level.
  1517. //
  1518. if (bRet && lstrcmpiW(lpwszKey, s_wszCopyFiles))
  1519. bRet = web_EnumFilesW(hPrinter, dwCliInfo, lpwszKey, fpEnum, lpParm);
  1520. }
  1521. return bRet;
  1522. }
  1523. /*****************************************************************************\
  1524. * webEnumPrinterInfo
  1525. *
  1526. * This routine enumerates the information stored in the registery. Depending
  1527. * upon the (dwType) passed in, it can enumerate different types of information.
  1528. *
  1529. * Use : Called from the Printer-Server to enumerate the copyfiles sections
  1530. * of the registry. This also provides a callback to allow the caller
  1531. * to trap the profiles so they may be added to the CAB list.
  1532. *
  1533. * Use : Called from the printer-server to enumerate ICM information.
  1534. *
  1535. \*****************************************************************************/
  1536. BOOL webEnumPrinterInfo(
  1537. HANDLE hPrinter,
  1538. DWORD dwCliInfo,
  1539. DWORD dwType,
  1540. FARPROC fpEnum,
  1541. LPVOID lpParm)
  1542. {
  1543. BOOL bEnum = TRUE;
  1544. //
  1545. // Call enumeration functions for various enumeration types.
  1546. //
  1547. switch (dwType) {
  1548. case WEB_ENUM_ICM:
  1549. if (web_KeyExistsW(hPrinter, s_wszCopyFiles))
  1550. bEnum = web_EnumCopyFilesW(hPrinter, dwCliInfo, s_wszCopyFiles, fpEnum, lpParm);
  1551. break;
  1552. default:
  1553. case WEB_ENUM_KEY: // NOT IMPLEMENTED
  1554. bEnum = FALSE;
  1555. }
  1556. return bEnum;
  1557. }
  1558. /*****************************************************************************\
  1559. * webWritePrinterInfo
  1560. *
  1561. * This routine reads the DEVMODE and Configuration-Data from the specified
  1562. * printer, and writes this to a .BIN file.
  1563. *
  1564. * Use : Called from the printer-server to write the registry settings to file.
  1565. *
  1566. \*****************************************************************************/
  1567. BOOL webWritePrinterInfo(
  1568. HANDLE hPrinter,
  1569. LPCTSTR lpszBinFile)
  1570. {
  1571. HANDLE hFile;
  1572. BOOL bDevMode;
  1573. DWORD cItems;
  1574. BOOL bRet = FALSE;
  1575. //
  1576. // Open the BIN file for writing.
  1577. //
  1578. hFile = web_OpenFileWrite(lpszBinFile);
  1579. if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
  1580. //
  1581. // Output the header. This basically reserves
  1582. // space at the beginning of the file to store
  1583. // the item-count.
  1584. //
  1585. if (web_WriteHeader(hFile, 0, FALSE)) {
  1586. //
  1587. // Write out the devmode-info.
  1588. //
  1589. if (web_WriteDevMode(hFile, hPrinter, &bDevMode)) {
  1590. //
  1591. // Write out devdata-info. The (cItems) indicates how
  1592. // many driver-specific entries were written.
  1593. //
  1594. cItems = 0;
  1595. if (web_WriteDevData(hFile, hPrinter, L"", &cItems))
  1596. bRet = web_WriteHeader(hFile, cItems, bDevMode);
  1597. }
  1598. }
  1599. CloseHandle(hFile);
  1600. }
  1601. return bRet;
  1602. }
  1603. /*****************************************************************************\
  1604. * webReadPrinterInfo
  1605. *
  1606. * This routine reads the DEVMODE and Configuration-Data from the specified
  1607. * BIN-File, and sets the printer-handle with the attributes.
  1608. *
  1609. * Use : Called from the printer-client to initialize the registry.
  1610. *
  1611. \*****************************************************************************/
  1612. BOOL webReadPrinterInfo(
  1613. HANDLE hPrinter,
  1614. LPCTSTR lpszPrtName,
  1615. LPCTSTR lpszBinFile)
  1616. {
  1617. HANDLE hMap;
  1618. LPDEVBIN_HEAD lpdbh;
  1619. BOOL bRet = FALSE;
  1620. //
  1621. // Open the BIN file for writing.
  1622. //
  1623. if (hMap = web_OpenMap(lpszBinFile)) {
  1624. if (lpdbh = (LPDEVBIN_HEAD)web_LockMap(hMap)) {
  1625. //
  1626. // Only if we have a DevMode should we write out the information.
  1627. //
  1628. if (!lpdbh->bDevMode || web_ReadDevMode(lpdbh, hPrinter, lpszPrtName)) {
  1629. //
  1630. // Only if we have printer-data items should we proceed
  1631. // to write out the information.
  1632. //
  1633. if (!lpdbh->cItems || web_ReadDevData(lpdbh, hPrinter)) {
  1634. bRet = TRUE;
  1635. }
  1636. }
  1637. web_UnlockMap((LPVOID)lpdbh);
  1638. }
  1639. web_CloseMap(hMap);
  1640. }
  1641. return bRet;
  1642. }
  1643. /*****************************************************************************\
  1644. * WebPnpEntry
  1645. *
  1646. * This routine is called by PrintWizard prior to installing the printer.
  1647. * Currently, we can find no value to this, but it is a nice balance to the
  1648. * WebPnpPostEntry() routine.
  1649. *
  1650. * Use : Called from the print-client prior to printer installation.
  1651. *
  1652. \*****************************************************************************/
  1653. BOOL WebPnpEntry(
  1654. LPCTSTR lpszCmdLine)
  1655. {
  1656. return TRUE;
  1657. }
  1658. BOOL
  1659. PrinterExists(
  1660. HANDLE hPrinter)
  1661. {
  1662. DWORD cbNeeded;
  1663. DWORD Error;
  1664. BOOL rc = FALSE;
  1665. LPPRINTER_INFO_2 pPrinter;
  1666. DWORD cbPrinter;
  1667. cbPrinter = 0x400;
  1668. pPrinter = (PPRINTER_INFO_2) web_GAlloc ( cbPrinter );
  1669. if( !pPrinter )
  1670. return FALSE;
  1671. if( !GetPrinter( hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbNeeded ) )
  1672. {
  1673. Error = GetLastError( );
  1674. if( Error == ERROR_INSUFFICIENT_BUFFER )
  1675. {
  1676. web_GFree (pPrinter);
  1677. pPrinter = (PPRINTER_INFO_2)web_GAlloc ( cbNeeded );
  1678. if( pPrinter )
  1679. {
  1680. cbPrinter = cbNeeded;
  1681. if( GetPrinter( hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbNeeded ) )
  1682. {
  1683. rc = TRUE;
  1684. }
  1685. }
  1686. }
  1687. else if( Error == ERROR_INVALID_HANDLE )
  1688. {
  1689. SetLastError( ERROR_INVALID_PRINTER_NAME );
  1690. }
  1691. }
  1692. else
  1693. {
  1694. rc = TRUE;
  1695. }
  1696. if( pPrinter )
  1697. {
  1698. web_GFree ( pPrinter );
  1699. }
  1700. return rc;
  1701. }
  1702. /*****************************************************************************\
  1703. * WebPnpPostEntry
  1704. *
  1705. * This routine is called via PrintWizard after a printer has been added. This
  1706. * provides the oportunity for the web-pnp-installer to initialize the
  1707. * registry settings and files according to the information provided in the
  1708. * BIN-File. The (fConnection) flag indicates whether the printer was
  1709. * installed via RPC or HTTP. If it was RPC, then it's not necessary to do
  1710. * any printer-settings.
  1711. *
  1712. * Use : Called from the print-client after printer installation.
  1713. *
  1714. \*****************************************************************************/
  1715. BOOL WebPnpPostEntry(
  1716. BOOL fConnection,
  1717. LPCTSTR lpszBinFile,
  1718. LPCTSTR lpszPortName,
  1719. LPCTSTR lpszPrtName)
  1720. {
  1721. HANDLE hPrinter;
  1722. PRINTER_DEFAULTS pd;
  1723. BOOL bRet = TRUE;
  1724. if (fConnection == FALSE) {
  1725. //
  1726. // Setup the printer-defaults to
  1727. // allow printer-changes.
  1728. //
  1729. pd.pDatatype = NULL;
  1730. pd.pDevMode = NULL;
  1731. pd.DesiredAccess = PRINTER_ALL_ACCESS;
  1732. //
  1733. // Open the printer specified.
  1734. //
  1735. if (OpenPrinter((LPTSTR)lpszPrtName, &hPrinter, &pd)) {
  1736. if (!PrinterExists(hPrinter) && GetLastError () == ERROR_ACCESS_DENIED) {
  1737. ConfigurePort( NULL, GetDesktopWindow (), (LPTSTR) lpszPortName);
  1738. }
  1739. bRet = webReadPrinterInfo(hPrinter, lpszPrtName, lpszBinFile);
  1740. ClosePrinter(hPrinter);
  1741. }
  1742. }
  1743. return bRet;
  1744. }