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.

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