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.

6271 lines
169 KiB

  1. /****************************Module*Header******************************\
  2. * Module Name: PROFMAN.C
  3. *
  4. * Module Descripton: Profile management functions.
  5. *
  6. * Warnings:
  7. *
  8. * Issues:
  9. *
  10. * Public Routines:
  11. *
  12. * Created: 5 Nov 1996
  13. *
  14. * Author: Srinivasan Chandrasekar [srinivac]
  15. *
  16. * Copyright (c) 1996, 1997 Microsoft Corporation
  17. \***********************************************************************/
  18. #include "mscms.h"
  19. #include "objbase.h"
  20. #include "initguid.h"
  21. #include "devguid.h"
  22. #include "sti.h"
  23. #define TAG_DEVICESETTINGS 'devs'
  24. #define TAG_MS01 'MS01'
  25. #define TAG_MS02 'MS02'
  26. #define TAG_MS03 'MS03'
  27. #define ID_MSFT_REVERSED 'tfsm'
  28. #define ID_MEDIATYPE_REVERSED 'aidm'
  29. #define ID_DITHER_REVERSED 'ntfh'
  30. #define ID_RESLN_REVERSED 'nlsr'
  31. #define DEVICE_PROFILE_DATA 1
  32. #define DEVICE_PROFILE_ENUMMODE 2
  33. //
  34. // Local types
  35. //
  36. typedef enum {
  37. NOMATCH = 0,
  38. MATCH = 1,
  39. EXACT_MATCH = 2,
  40. } MATCHTYPE;
  41. typedef struct tagREGDATA {
  42. DWORD dwRefCount;
  43. DWORD dwManuID;
  44. DWORD dwModelID;
  45. } REGDATA, *PREGDATA;
  46. typedef struct tagSCANNERDATA {
  47. PWSTR pDeviceName;
  48. HINSTANCE hModule;
  49. PSTI pSti;
  50. } SCANNERDATA, *PSCANNERDATA;
  51. typedef BOOL (WINAPI *PFNOPENDEVICE)(PTSTR, LPHANDLE, PTSTR);
  52. typedef BOOL (WINAPI *PFNCLOSEDEVICE)(HANDLE);
  53. typedef DWORD (WINAPI *PFNGETDEVICEDATA)(HANDLE, PTSTR, PTSTR, PDWORD, PBYTE, DWORD, PDWORD);
  54. typedef DWORD (WINAPI *PFNSETDEVICEDATA)(HANDLE, PTSTR, PTSTR, DWORD, PBYTE, DWORD);
  55. typedef HRESULT (__stdcall *PFNSTICREATEINSTANCE)(HINSTANCE, DWORD, PSTI*, LPDWORD);
  56. //
  57. // Local functions
  58. //
  59. BOOL InternalGetColorDirectory(LPCTSTR, PTSTR, DWORD*);
  60. BOOL InternalInstallColorProfile(LPCTSTR, LPCTSTR);
  61. BOOL InternalUninstallColorProfile(LPCTSTR, LPCTSTR, BOOL);
  62. BOOL InternalAssociateColorProfileWithDevice(LPCTSTR, LPCTSTR, LPCTSTR);
  63. BOOL InternalDisassociateColorProfileFromDevice(LPCTSTR, LPCTSTR, LPCTSTR);
  64. BOOL InternalEnumColorProfiles(LPCTSTR, PENUMTYPE, PBYTE, PDWORD, PDWORD);
  65. BOOL InternalSetSCSProfile(LPCTSTR, DWORD, LPCTSTR);
  66. BOOL InternalGetSCSProfile(LPCTSTR, DWORD, PTSTR, PDWORD);
  67. VOID ConvertDwordToString(DWORD, PTSTR);
  68. PTSTR ConvertClassIdToClassString(DWORD);
  69. BOOL GetProfileClassString(LPCTSTR, PTSTR, PPROFILEHEADER);
  70. BOOL GetDeviceData(LPCTSTR, DWORD, DWORD, PVOID*, PDWORD, BOOL);
  71. BOOL SetDeviceData(LPCTSTR, DWORD, DWORD, PVOID, DWORD);
  72. BOOL IGetDeviceData(LPCTSTR, DWORD, DWORD, PVOID*, PDWORD, BOOL);
  73. BOOL ISetDeviceData(LPCTSTR, DWORD, DWORD, PVOID, DWORD);
  74. BOOL IsStringInMultiSz(PTSTR, PTSTR);
  75. DWORD RemoveStringFromMultiSz(PTSTR, PTSTR, DWORD);
  76. VOID InsertInBuffer(PBYTE, PBYTE, PTSTR);
  77. MATCHTYPE DoesProfileMatchEnumRecord(PTSTR, PENUMTYPE);
  78. MATCHTYPE CheckResMedHftnMatch(HPROFILE, PENUMTYPE);
  79. BOOL DwordMatches(PSETTINGS, DWORD);
  80. BOOL QwordMatches(PSETTINGS, PDWORD);
  81. BOOL WINAPI OpenPrtr(PTSTR, LPHANDLE, PTSTR);
  82. BOOL WINAPI ClosePrtr(HANDLE);
  83. DWORD WINAPI GetPrtrData(HANDLE, PTSTR, PTSTR, PDWORD, PBYTE, DWORD, PDWORD);
  84. DWORD WINAPI SetPrtrData(HANDLE, PTSTR, PTSTR, DWORD, PBYTE, DWORD);
  85. BOOL WINAPI OpenMonitor(PTSTR, LPHANDLE, PTSTR);
  86. BOOL WINAPI CloseMonitor(HANDLE);
  87. DWORD WINAPI GetMonitorData(HANDLE, PTSTR, PTSTR, PDWORD, PBYTE, DWORD, PDWORD);
  88. DWORD WINAPI SetMonitorData(HANDLE, PTSTR, PTSTR, DWORD, PBYTE, DWORD);
  89. BOOL WINAPI OpenScanner(PTSTR, LPHANDLE, PTSTR);
  90. BOOL WINAPI CloseScanner(HANDLE);
  91. DWORD WINAPI GetScannerData(HANDLE, PTSTR, PTSTR, PDWORD, PBYTE, DWORD, PDWORD);
  92. DWORD WINAPI SetScannerData(HANDLE, PTSTR, PTSTR, DWORD, PBYTE, DWORD);
  93. #ifdef _WIN95_
  94. BOOL LoadSetupAPIDll(VOID);
  95. #else
  96. VOID ChangeICMSetting(LPCTSTR, LPCTSTR, DWORD);
  97. #endif // _WIN95_
  98. //
  99. // SetupAPI function pointers
  100. //
  101. typedef WINSETUPAPI HKEY
  102. (WINAPI *FP_SetupDiOpenDevRegKey)(
  103. IN HDEVINFO DeviceInfoSet,
  104. IN PSP_DEVINFO_DATA DeviceInfoData,
  105. IN DWORD Scope,
  106. IN DWORD HwProfile,
  107. IN DWORD KeyType,
  108. IN REGSAM samDesired
  109. );
  110. typedef WINSETUPAPI BOOL
  111. (WINAPI *FP_SetupDiDestroyDeviceInfoList)(
  112. IN HDEVINFO DeviceInfoSet
  113. );
  114. typedef WINSETUPAPI BOOL
  115. (WINAPI *FP_SetupDiEnumDeviceInfo)(
  116. IN HDEVINFO DeviceInfoSet,
  117. IN DWORD MemberIndex,
  118. OUT PSP_DEVINFO_DATA DeviceInfoData
  119. );
  120. #if !defined(_WIN95_)
  121. typedef WINSETUPAPI BOOL
  122. (WINAPI *FP_SetupDiGetDeviceInstanceId)(
  123. IN HDEVINFO DeviceInfoSet,
  124. IN PSP_DEVINFO_DATA DeviceInfoData,
  125. OUT PWSTR DeviceInstanceId,
  126. IN DWORD DeviceInstanceIdSize,
  127. OUT PDWORD RequiredSize OPTIONAL
  128. );
  129. typedef WINSETUPAPI HDEVINFO
  130. (WINAPI *FP_SetupDiGetClassDevs)(
  131. IN LPGUID ClassGuid, OPTIONAL
  132. IN PCWSTR Enumerator, OPTIONAL
  133. IN HWND hwndParent, OPTIONAL
  134. IN DWORD Flags
  135. );
  136. #else
  137. typedef WINSETUPAPI BOOL
  138. (WINAPI *FP_SetupDiGetDeviceInstanceId)(
  139. IN HDEVINFO DeviceInfoSet,
  140. IN PSP_DEVINFO_DATA DeviceInfoData,
  141. OUT PSTR DeviceInstanceId,
  142. IN DWORD DeviceInstanceIdSize,
  143. OUT PDWORD RequiredSize OPTIONAL
  144. );
  145. typedef WINSETUPAPI HDEVINFO
  146. (WINAPI *FP_SetupDiGetClassDevs)(
  147. IN LPGUID ClassGuid, OPTIONAL
  148. IN PCSTR Enumerator, OPTIONAL
  149. IN HWND hwndParent, OPTIONAL
  150. IN DWORD Flags
  151. );
  152. #endif
  153. HMODULE ghModSetupAPIDll = NULL;
  154. FP_SetupDiOpenDevRegKey fpSetupDiOpenDevRegKey = NULL;
  155. FP_SetupDiDestroyDeviceInfoList fpSetupDiDestroyDeviceInfoList = NULL;
  156. FP_SetupDiEnumDeviceInfo fpSetupDiEnumDeviceInfo = NULL;
  157. FP_SetupDiGetDeviceInstanceId fpSetupDiGetDeviceInstanceId = NULL;
  158. FP_SetupDiGetClassDevs fpSetupDiGetClassDevs = NULL;
  159. //
  160. // Predefined profiles in order - INF file has 1-based index into this list
  161. //
  162. TCHAR *gszDispProfiles[] = {
  163. __TEXT("mnB22G15.icm"), // 1
  164. __TEXT("mnB22G18.icm"), // 2
  165. __TEXT("mnB22G21.icm"), // 3
  166. __TEXT("mnEBUG15.icm"), // 4
  167. __TEXT("mnEBUG18.icm"), // 5
  168. __TEXT("mnEBUG21.icm"), // 6
  169. __TEXT("mnP22G15.icm"), // 7
  170. __TEXT("mnP22G18.icm"), // 8
  171. __TEXT("mnP22G21.icm"), // 9
  172. __TEXT("Diamond Compatible 9300K G2.2.icm"), // 10
  173. __TEXT("Hitachi Compatible 9300K G2.2.icm"), // 11
  174. __TEXT("NEC Compatible 9300K G2.2.icm"), // 12
  175. __TEXT("Trinitron Compatible 9300K G2.2.icm"), // 13
  176. };
  177. TCHAR *gpszClasses[] = { // different profile classes
  178. __TEXT("mntr"), // 0
  179. __TEXT("prtr"), // 1
  180. __TEXT("scnr"), // 2
  181. __TEXT("link"), // 3
  182. __TEXT("abst"), // 4
  183. __TEXT("spac"), // 5
  184. __TEXT("nmcl") // 6
  185. };
  186. #define INDEX_CLASS_MONITOR 0
  187. #define INDEX_CLASS_PRINTER 1
  188. #define INDEX_CLASS_SCANNER 2
  189. #define INDEX_CLASS_LINK 3
  190. #define INDEX_CLASS_ABSTRACT 4
  191. #define INDEX_CLASS_COLORSPACE 5
  192. #define INDEX_CLASS_NAMED 6
  193. /******************************************************************************
  194. *
  195. * GetColorDirectory
  196. *
  197. * Function:
  198. * These are the ANSI & Unicode wrappers for InternalGetColorDirectory.
  199. * Please see InternalGetColorDirectory for more details on this
  200. * function.
  201. *
  202. * Arguments:
  203. * pMachineName - name identifying machine on which the path
  204. * to the color directory is requested
  205. * pBuffer - pointer to buffer to receive pathname
  206. * pdwSize - pointer to size of buffer. On return it has size of
  207. * buffer needed if failure, and used on success
  208. *
  209. * Returns:
  210. * TRUE if successful, NULL otherwise
  211. *
  212. ******************************************************************************/
  213. #ifdef UNICODE // Windows NT versions
  214. BOOL WINAPI
  215. GetColorDirectoryA(
  216. PCSTR pMachineName,
  217. PSTR pBuffer,
  218. PDWORD pdwSize
  219. )
  220. {
  221. PWSTR pwszMachineName = NULL; // Unicode machine name
  222. PWSTR pwBuffer = NULL; // Unicode color directory path
  223. DWORD dwSize; // size of Unicode buffer
  224. DWORD dwErr = 0; // error code
  225. BOOL rc = TRUE; // return code
  226. TRACEAPI((__TEXT("GetColorDirectoryA\n")));
  227. //
  228. // Validate parameters before we touch them
  229. //
  230. if (!pdwSize ||
  231. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  232. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)))
  233. {
  234. WARNING((__TEXT("Invalid parameter to GetColorDirectory\n")));
  235. SetLastError(ERROR_INVALID_PARAMETER);
  236. return FALSE;
  237. }
  238. //
  239. // Convert machine name to Unicode
  240. //
  241. if (pMachineName)
  242. {
  243. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  244. }
  245. else
  246. pwszMachineName = NULL;
  247. dwSize = *pdwSize * sizeof(WCHAR);
  248. //
  249. // Create a buffer to get Unicode directory from system
  250. //
  251. if (pBuffer && dwSize)
  252. {
  253. pwBuffer = (PWSTR)MemAlloc(dwSize);
  254. if (! pwBuffer)
  255. {
  256. WARNING((__TEXT("Error allocating memory for Unicode string\n")));
  257. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  258. rc = FALSE;
  259. goto EndGetColorDirectoryA;
  260. }
  261. }
  262. rc = rc && InternalGetColorDirectory(pwszMachineName, pwBuffer, &dwSize);
  263. *pdwSize = dwSize / sizeof(WCHAR);
  264. //
  265. // Convert Unicode path to Ansi
  266. //
  267. if (pwBuffer)
  268. {
  269. rc = rc && ConvertToAnsi(pwBuffer, &pBuffer, FALSE);
  270. }
  271. EndGetColorDirectoryA:
  272. if (pwszMachineName)
  273. {
  274. MemFree(pwszMachineName);
  275. }
  276. if (pwBuffer)
  277. {
  278. MemFree(pwBuffer);
  279. }
  280. return rc;
  281. }
  282. BOOL WINAPI
  283. GetColorDirectoryW(
  284. PCWSTR pMachineName,
  285. PWSTR pBuffer,
  286. PDWORD pdwSize
  287. )
  288. {
  289. TRACEAPI((__TEXT("GetColorDirectoryW\n")));
  290. //
  291. // Internal function is ANSI in Windows 95, call it directly.
  292. //
  293. return InternalGetColorDirectory(pMachineName, pBuffer, pdwSize);
  294. }
  295. #else // Windows 95 versions
  296. BOOL WINAPI
  297. GetColorDirectoryA(
  298. PCSTR pMachineName,
  299. PSTR pBuffer,
  300. PDWORD pdwSize
  301. )
  302. {
  303. TRACEAPI((__TEXT("GetColorDirectoryA\n")));
  304. //
  305. // Internal function is ANSI in Windows 95, call it directly.
  306. //
  307. return InternalGetColorDirectory(pMachineName, pBuffer, pdwSize);
  308. }
  309. BOOL WINAPI
  310. GetColorDirectoryW(
  311. PCWSTR pMachineName,
  312. PWSTR pBuffer,
  313. PDWORD pdwSize
  314. )
  315. {
  316. PSTR pszMachineName = NULL; // Ansi machine name
  317. PSTR pszBuffer = NULL; // Ansi color directory path
  318. DWORD dwSize; // size of Ansi buffer
  319. BOOL rc = TRUE; // return code
  320. TRACEAPI((__TEXT("GetColorDirectoryW\n")));
  321. //
  322. // Validate parameters before we touch them
  323. //
  324. if (!pdwSize ||
  325. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  326. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)))
  327. {
  328. WARNING((__TEXT("Invalid parameter to GetColorDirectory\n")));
  329. SetLastError(ERROR_INVALID_PARAMETER);
  330. return FALSE;
  331. }
  332. //
  333. // Convert machine name to Ansi
  334. //
  335. if (pMachineName)
  336. {
  337. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  338. }
  339. else
  340. pszMachineName = NULL;
  341. //
  342. // Create a buffer to get Ansi directory from system
  343. //
  344. dwSize = *pdwSize / sizeof(WCHAR);
  345. if (pBuffer && dwSize)
  346. {
  347. pszBuffer = (PSTR)MemAlloc(dwSize);
  348. if (! pszBuffer)
  349. {
  350. WARNING((__TEXT("Error allocating memory for Ansi string\n")));
  351. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  352. rc = FALSE;
  353. goto EndGetColorDirectoryW;
  354. }
  355. }
  356. rc = rc && InternalGetColorDirectory(pszMachineName, pszBuffer, &dwSize);
  357. *pdwSize = dwSize * sizeof(WCHAR);
  358. //
  359. // Convert Ansi path to Unicode
  360. //
  361. if (pszBuffer)
  362. {
  363. rc = rc && ConvertToUnicode(pszBuffer, &pBuffer, FALSE);
  364. }
  365. EndGetColorDirectoryW:
  366. if (pszMachineName)
  367. {
  368. MemFree(pszMachineName);
  369. }
  370. if (pszBuffer)
  371. {
  372. MemFree(pszBuffer);
  373. }
  374. return rc;
  375. }
  376. #endif // ! UNICODE
  377. /******************************************************************************
  378. *
  379. * InstallColorProfile
  380. *
  381. * Function:
  382. * These are the ANSI & Unicode wrappers for InternalInstallColorProfile.
  383. * Please see InternalInstallColorProfile for more details on this
  384. * function.
  385. *
  386. * Arguments:
  387. * pMachineName - name identifying machine on which the profile
  388. * should be installed. NULL implies local
  389. * pProfileName - pointer to filename of profile to install
  390. *
  391. * Returns:
  392. * TRUE if successful, NULL otherwise
  393. *
  394. ******************************************************************************/
  395. #ifdef UNICODE // Windows NT versions
  396. BOOL WINAPI
  397. InstallColorProfileA(
  398. PCSTR pMachineName,
  399. PCSTR pProfileName
  400. )
  401. {
  402. PWSTR pwszMachineName = NULL; // Unicode machine name
  403. PWSTR pwszProfileName = NULL; // Unicode profile name
  404. BOOL rc = TRUE; // return code
  405. TRACEAPI((__TEXT("InstallColorProfileA\n")));
  406. //
  407. // Validate parameters before we touch them
  408. //
  409. if (!pProfileName)
  410. {
  411. WARNING((__TEXT("Invalid parameter to InstallColorProfile\n")));
  412. SetLastError(ERROR_INVALID_PARAMETER);
  413. return FALSE;
  414. }
  415. //
  416. // Convert machine name to Unicode
  417. //
  418. if (pMachineName)
  419. {
  420. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  421. }
  422. else
  423. pwszMachineName = NULL;
  424. //
  425. // Convert profile name to Unicode
  426. //
  427. rc = rc && ConvertToUnicode(pProfileName, &pwszProfileName, TRUE);
  428. //
  429. // Call the internal Unicode function
  430. //
  431. rc = rc && InternalInstallColorProfile(pwszMachineName, pwszProfileName);
  432. //
  433. // Free memory before leaving
  434. //
  435. if (pwszProfileName)
  436. {
  437. MemFree(pwszProfileName);
  438. }
  439. if (pwszMachineName)
  440. {
  441. MemFree(pwszMachineName);
  442. }
  443. return rc;
  444. }
  445. BOOL WINAPI
  446. InstallColorProfileW(
  447. PCWSTR pMachineName,
  448. PCWSTR pProfileName
  449. )
  450. {
  451. TRACEAPI((__TEXT("InstallColorProfileW\n")));
  452. //
  453. // Internal function is Unicode in Windows NT, call it directly.
  454. //
  455. return InternalInstallColorProfile(pMachineName, pProfileName);
  456. }
  457. #else // Windows 95 versions
  458. BOOL WINAPI
  459. InstallColorProfileA(
  460. PCSTR pMachineName,
  461. PCSTR pProfileName
  462. )
  463. {
  464. TRACEAPI((__TEXT("InstallColorProfileA\n")));
  465. //
  466. // Internal function is ANSI in Windows 95, call it directly.
  467. //
  468. return InternalInstallColorProfile(pMachineName, pProfileName);
  469. }
  470. BOOL WINAPI
  471. InstallColorProfileW(
  472. PCWSTR pMachineName,
  473. PCWSTR pProfileName
  474. )
  475. {
  476. PSTR pszMachineName = NULL; // Ansi machine name
  477. PSTR pszProfileName = NULL; // Ansi profile name
  478. BOOL rc = TRUE; // return code
  479. TRACEAPI((__TEXT("InstallColorProfileW\n")));
  480. //
  481. // Validate parameters before we touch them
  482. //
  483. if (!pProfileName)
  484. {
  485. WARNING((__TEXT("Invalid parameter to InstallColorProfile\n")));
  486. SetLastError(ERROR_INVALID_PARAMETER);
  487. return FALSE;
  488. }
  489. //
  490. // Convert machine name to Ansi
  491. //
  492. if (pMachineName)
  493. {
  494. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  495. }
  496. else
  497. pszMachineName = NULL;
  498. //
  499. // Convert profile name to Ansi
  500. //
  501. rc = rc && ConvertToAnsi(pProfileName, &pszProfileName, TRUE);
  502. //
  503. // Call the internal Ansi function
  504. //
  505. rc = rc && InternalInstallColorProfile(pszMachineName, pszProfileName);
  506. //
  507. // Free memory before leaving
  508. //
  509. if (pszProfileName)
  510. {
  511. MemFree(pszProfileName);
  512. }
  513. if (pszMachineName)
  514. {
  515. MemFree(pszMachineName);
  516. }
  517. return rc;
  518. }
  519. #endif // ! UNICODE
  520. /******************************************************************************
  521. *
  522. * UninstallColorProfile
  523. *
  524. * Function:
  525. * These are the ANSI & Unicode wrappers for InternalUninstallColorProfile.
  526. * Please see InternalUninstallColorProfile for more details on this
  527. * function.
  528. *
  529. * Arguments:
  530. * pMachineName - name identifying machine on which the profile
  531. * should be uninstalled. NULL implies local
  532. * pProfileName - pointer to filename of profile to uninstall
  533. * bDelete - TRUE if profile should be deleted in disk
  534. *
  535. * Returns:
  536. * TRUE if successful, NULL otherwise
  537. *
  538. ******************************************************************************/
  539. #ifdef UNICODE // Windows NT versions
  540. BOOL WINAPI
  541. UninstallColorProfileA(
  542. PCSTR pMachineName,
  543. PCSTR pProfileName,
  544. BOOL bDelete
  545. )
  546. {
  547. PWSTR pwszMachineName = NULL; // Unicode machine name
  548. PWSTR pwszProfileName = NULL; // Unicode profile name
  549. BOOL rc = TRUE; // return code
  550. TRACEAPI((__TEXT("UninstallColorProfileA\n")));
  551. //
  552. // Validate parameters before we touch them
  553. //
  554. if (!pProfileName)
  555. {
  556. WARNING((__TEXT("Invalid parameter to UninstallColorProfile\n")));
  557. SetLastError(ERROR_INVALID_PARAMETER);
  558. return FALSE;
  559. }
  560. //
  561. // Convert machine name to Unicode
  562. //
  563. if (pMachineName)
  564. {
  565. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  566. }
  567. else
  568. pwszMachineName = NULL;
  569. //
  570. // Convert profile name to Unicode
  571. //
  572. rc = rc && ConvertToUnicode(pProfileName, &pwszProfileName, TRUE);
  573. //
  574. // Call the internal Unicode function
  575. //
  576. rc = rc && InternalUninstallColorProfile(pwszMachineName, pwszProfileName,
  577. bDelete);
  578. //
  579. // Free memory before leaving
  580. //
  581. if (pwszProfileName)
  582. {
  583. MemFree(pwszProfileName);
  584. }
  585. if (pwszMachineName)
  586. {
  587. MemFree(pwszMachineName);
  588. }
  589. return rc;
  590. }
  591. BOOL WINAPI
  592. UninstallColorProfileW(
  593. PCWSTR pMachineName,
  594. PCWSTR pProfileName,
  595. BOOL bDelete
  596. )
  597. {
  598. TRACEAPI((__TEXT("UninstallColorProfileW\n")));
  599. //
  600. // Internal function is Unicode in Windows NT, call it directly.
  601. //
  602. return InternalUninstallColorProfile(pMachineName, pProfileName, bDelete);
  603. }
  604. #else // Windows 95 versions
  605. BOOL WINAPI
  606. UninstallColorProfileA(
  607. PCSTR pMachineName,
  608. PCSTR pProfileName,
  609. BOOL bDelete
  610. )
  611. {
  612. TRACEAPI((__TEXT("UninstallColorProfileA\n")));
  613. //
  614. // Internal function is ANSI in Windows 95, call it directly.
  615. //
  616. return InternalUninstallColorProfile(pMachineName, pProfileName, bDelete);
  617. }
  618. BOOL WINAPI
  619. UninstallColorProfileW(
  620. PCWSTR pMachineName,
  621. PCWSTR pProfileName,
  622. BOOL bDelete
  623. )
  624. {
  625. PSTR pszMachineName = NULL; // Ansi machine name
  626. PSTR pszProfileName = NULL; // Ansi profile name
  627. BOOL rc = TRUE; // return code
  628. TRACEAPI((__TEXT("UninstallColorProfileW\n")));
  629. //
  630. // Validate parameters before we touch them
  631. //
  632. if (!pProfileName)
  633. {
  634. WARNING((__TEXT("Invalid parameter to UninstallColorProfile\n")));
  635. SetLastError(ERROR_INVALID_PARAMETER);
  636. return FALSE;
  637. }
  638. //
  639. // Convert machine name to Ansi
  640. //
  641. if (pMachineName)
  642. {
  643. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  644. }
  645. else
  646. pszMachineName = NULL;
  647. //
  648. // Convert profile name to Ansi
  649. //
  650. rc = rc && ConvertToAnsi(pProfileName, &pszProfileName, TRUE);
  651. //
  652. // Call the internal Ansi function
  653. //
  654. rc = rc && InternalUninstallColorProfile(pszMachineName, pszProfileName,
  655. bDelete);
  656. //
  657. // Free memory before leaving
  658. //
  659. if (pszProfileName)
  660. {
  661. MemFree(pszProfileName);
  662. }
  663. if (pszMachineName)
  664. {
  665. MemFree(pszMachineName);
  666. }
  667. return rc;
  668. }
  669. #endif // ! UNICODE
  670. /******************************************************************************
  671. *
  672. * AssociateColorProfileWithDevice
  673. *
  674. * Function:
  675. * These are the ANSI & Unicode wrappers for
  676. * InternalAssociateColorProfileWithDevice. Please see
  677. * InternalAssociateColorProfileWithDevice for more details
  678. * on this function.
  679. *
  680. * Arguments:
  681. * pMachineName - name identifying machine. NULL implies local
  682. * pProfileName - pointer to profile to associate
  683. * pDeviceName - pointer to device name
  684. *
  685. * Returns:
  686. * TRUE if successful, NULL otherwise
  687. *
  688. ******************************************************************************/
  689. #ifdef UNICODE // Windows NT versions
  690. BOOL WINAPI
  691. AssociateColorProfileWithDeviceA(
  692. PCSTR pMachineName,
  693. PCSTR pProfileName,
  694. PCSTR pDeviceName
  695. )
  696. {
  697. PWSTR pwszMachineName = NULL; // Unicode machine name
  698. PWSTR pwszProfileName = NULL; // Unicode profile name
  699. PWSTR pwszDeviceName = NULL; // Unicode device name
  700. BOOL rc = TRUE; // return code
  701. TRACEAPI((__TEXT("AssociateColorProfileWithDeviceA\n")));
  702. //
  703. // Validate parameters before we touch them
  704. //
  705. if (! pProfileName ||
  706. ! pDeviceName)
  707. {
  708. WARNING((__TEXT("Invalid parameter to AssociateColorProfileWithDevice\n")));
  709. SetLastError(ERROR_INVALID_PARAMETER);
  710. return FALSE;
  711. }
  712. //
  713. // Convert machine name to Unicode
  714. //
  715. if (pMachineName)
  716. {
  717. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  718. }
  719. else
  720. pwszMachineName = NULL;
  721. //
  722. // Convert profile name to Unicode
  723. //
  724. rc = rc && ConvertToUnicode(pProfileName, &pwszProfileName, TRUE);
  725. //
  726. // Convert device name to Unicode
  727. //
  728. rc = rc && ConvertToUnicode(pDeviceName, &pwszDeviceName, TRUE);
  729. //
  730. // Call the internal Unicode function
  731. //
  732. rc = rc && InternalAssociateColorProfileWithDevice(pwszMachineName,
  733. pwszProfileName, pwszDeviceName);
  734. //
  735. // Free memory before leaving
  736. //
  737. if (pwszProfileName)
  738. {
  739. MemFree(pwszProfileName);
  740. }
  741. if (pwszMachineName)
  742. {
  743. MemFree(pwszMachineName);
  744. }
  745. if (pwszDeviceName)
  746. {
  747. MemFree(pwszDeviceName);
  748. }
  749. return rc;
  750. }
  751. BOOL WINAPI
  752. AssociateColorProfileWithDeviceW(
  753. PCWSTR pMachineName,
  754. PCWSTR pProfileName,
  755. PCWSTR pDeviceName
  756. )
  757. {
  758. TRACEAPI((__TEXT("AssociateColorProfileWithDeviceW\n")));
  759. //
  760. // Internal function is Unicode in Windows NT, call it directly.
  761. //
  762. return InternalAssociateColorProfileWithDevice(pMachineName,
  763. pProfileName, pDeviceName);
  764. }
  765. #else // Windows 95 versions
  766. BOOL WINAPI
  767. AssociateColorProfileWithDeviceA(
  768. PCSTR pMachineName,
  769. PCSTR pProfileName,
  770. PCSTR pDeviceName
  771. )
  772. {
  773. TRACEAPI((__TEXT("AssociateColorProfileWithDeviceA\n")));
  774. //
  775. // Internal function is ANSI in Windows 95, call it directly.
  776. //
  777. return InternalAssociateColorProfileWithDevice(pMachineName,
  778. pProfileName, pDeviceName);
  779. }
  780. BOOL WINAPI
  781. AssociateColorProfileWithDeviceW(
  782. PCWSTR pMachineName,
  783. PCWSTR pProfileName,
  784. PCWSTR pDeviceName
  785. )
  786. {
  787. PSTR pszMachineName = NULL; // Ansi machine name
  788. PSTR pszProfileName = NULL; // Ansi profile name
  789. PSTR pszDeviceName = NULL; // Ansi device name
  790. BOOL rc = TRUE; // return code
  791. TRACEAPI((__TEXT("AssociateColorProfileWithDeviceW\n")));
  792. //
  793. // Validate parameters before we touch them
  794. //
  795. if (! pProfileName ||
  796. ! pDeviceName)
  797. {
  798. WARNING((__TEXT("Invalid parameter to AssociateColorProfileWithDevice\n")));
  799. SetLastError(ERROR_INVALID_PARAMETER);
  800. return FALSE;
  801. }
  802. //
  803. // Convert machine name to Ansi
  804. //
  805. if (pMachineName)
  806. {
  807. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  808. }
  809. else
  810. pszMachineName = NULL;
  811. //
  812. // Convert profile name to Ansi
  813. //
  814. rc = rc && ConvertToAnsi(pProfileName, &pszProfileName, TRUE);
  815. //
  816. // Convert device name to Ansi
  817. //
  818. rc = rc && ConvertToAnsi(pDeviceName, &pszDeviceName, TRUE);
  819. //
  820. // Call the internal Ansi function
  821. //
  822. rc = rc && InternalAssociateColorProfileWithDevice(pszMachineName,
  823. pszProfileName, pszDeviceName);
  824. //
  825. // Free memory before leaving
  826. //
  827. if (pszProfileName)
  828. {
  829. MemFree(pszProfileName);
  830. }
  831. if (pszMachineName)
  832. {
  833. MemFree(pszMachineName);
  834. }
  835. if (pszDeviceName)
  836. {
  837. MemFree(pszDeviceName);
  838. }
  839. return rc;
  840. }
  841. #endif // ! UNICODE
  842. /******************************************************************************
  843. *
  844. * DisassociateColorProfileFromDevice
  845. *
  846. * Function:
  847. * These are the ANSI & Unicode wrappers for
  848. * InternalDisassociateColorProfileFromDevice. Please see
  849. * InternalDisassociateColorProfileFromDevice for more details
  850. * on this function.
  851. *
  852. * Arguments:
  853. * pMachineName - name identifying machine. NULL implies local
  854. * pProfileName - pointer to profile to disassiciate
  855. * pDeviceName - pointer to device name
  856. *
  857. * Returns:
  858. * TRUE if successful, NULL otherwise
  859. *
  860. ******************************************************************************/
  861. #ifdef UNICODE // Windows NT versions
  862. BOOL WINAPI
  863. DisassociateColorProfileFromDeviceA(
  864. PCSTR pMachineName,
  865. PCSTR pProfileName,
  866. PCSTR pDeviceName
  867. )
  868. {
  869. PWSTR pwszMachineName = NULL; // Unicode machine name
  870. PWSTR pwszProfileName = NULL; // Unicode profile name
  871. PWSTR pwszDeviceName = NULL; // Unicode device name
  872. BOOL rc = TRUE; // return code
  873. TRACEAPI((__TEXT("DisassociateColorProfileWithDeviceA\n")));
  874. //
  875. // Validate parameters before we touch them
  876. //
  877. if (! pProfileName ||
  878. ! pDeviceName)
  879. {
  880. WARNING((__TEXT("Invalid parameter to DisassociateColorProfileFromDevice\n")));
  881. SetLastError(ERROR_INVALID_PARAMETER);
  882. return FALSE;
  883. }
  884. //
  885. // Convert machine name to Unicode
  886. //
  887. if (pMachineName)
  888. {
  889. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  890. }
  891. else
  892. pwszMachineName = NULL;
  893. //
  894. // Convert profile name to Unicode
  895. //
  896. rc = rc && ConvertToUnicode(pProfileName, &pwszProfileName, TRUE);
  897. //
  898. // Convert device name to Unicode
  899. //
  900. rc = rc && ConvertToUnicode(pDeviceName, &pwszDeviceName, TRUE);
  901. //
  902. // Call the internal Unicode function
  903. //
  904. rc = rc && InternalDisassociateColorProfileFromDevice(pwszMachineName,
  905. pwszProfileName, pwszDeviceName);
  906. //
  907. // Free memory before leaving
  908. //
  909. if (pwszProfileName)
  910. {
  911. MemFree(pwszProfileName);
  912. }
  913. if (pwszMachineName)
  914. {
  915. MemFree(pwszMachineName);
  916. }
  917. if (pwszDeviceName)
  918. {
  919. MemFree(pwszDeviceName);
  920. }
  921. return rc;
  922. }
  923. BOOL WINAPI
  924. DisassociateColorProfileFromDeviceW(
  925. PCWSTR pMachineName,
  926. PCWSTR pProfileName,
  927. PCWSTR pDeviceName
  928. )
  929. {
  930. TRACEAPI((__TEXT("DisassociateColorProfileWithDeviceW\n")));
  931. //
  932. // Internal function is Unicode in Windows NT, call it directly.
  933. //
  934. return InternalDisassociateColorProfileFromDevice(pMachineName,
  935. pProfileName, pDeviceName);
  936. }
  937. #else // Windows 95 versions
  938. BOOL WINAPI
  939. DisassociateColorProfileFromDeviceA(
  940. PCSTR pMachineName,
  941. PCSTR pProfileName,
  942. PCSTR pDeviceName
  943. )
  944. {
  945. TRACEAPI((__TEXT("DisassociateColorProfileWithDeviceA\n")));
  946. //
  947. // Internal function is ANSI in Windows 95, call it directly.
  948. //
  949. return InternalDisassociateColorProfileFromDevice(pMachineName,
  950. pProfileName, pDeviceName);
  951. }
  952. BOOL WINAPI
  953. DisassociateColorProfileFromDeviceW(
  954. PCWSTR pMachineName,
  955. PCWSTR pProfileName,
  956. PCWSTR pDeviceName
  957. )
  958. {
  959. PSTR pszMachineName = NULL; // Ansi machine name
  960. PSTR pszProfileName = NULL; // Ansi profile name
  961. PSTR pszDeviceName = NULL; // Ansi device name
  962. BOOL rc = TRUE; // return code
  963. TRACEAPI((__TEXT("DisassociateColorProfileWithDeviceW\n")));
  964. //
  965. // Validate parameters before we touch them
  966. //
  967. if (! pProfileName ||
  968. ! pDeviceName)
  969. {
  970. WARNING((__TEXT("Invalid parameter to AssociateColorProfileWithDevice\n")));
  971. SetLastError(ERROR_INVALID_PARAMETER);
  972. return FALSE;
  973. }
  974. //
  975. // Convert machine name to Ansi
  976. //
  977. if (pMachineName)
  978. {
  979. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  980. }
  981. else
  982. pszMachineName = NULL;
  983. //
  984. // Convert profile name to Ansi
  985. //
  986. rc = rc && ConvertToAnsi(pProfileName, &pszProfileName, TRUE);
  987. //
  988. // Convert device name to Ansi
  989. //
  990. rc = rc && ConvertToAnsi(pDeviceName, &pszDeviceName, TRUE);
  991. //
  992. // Call the internal Ansi function
  993. //
  994. rc = rc && InternalDisassociateColorProfileFromDevice(pszMachineName,
  995. pszProfileName, pszDeviceName);
  996. //
  997. // Free memory before leaving
  998. //
  999. if (pszProfileName)
  1000. {
  1001. MemFree(pszProfileName);
  1002. }
  1003. if (pszMachineName)
  1004. {
  1005. MemFree(pszMachineName);
  1006. }
  1007. if (pszDeviceName)
  1008. {
  1009. MemFree(pszDeviceName);
  1010. }
  1011. return rc;
  1012. }
  1013. #endif // ! UNICODE
  1014. /******************************************************************************
  1015. *
  1016. * EnumColorProfiles
  1017. *
  1018. * Function:
  1019. * These are the ANSI & Unicode wrappers for InternalEnumColorProfile.
  1020. * Please see InternalEnumColorProfile for more details on this
  1021. * function.
  1022. *
  1023. * Arguments:
  1024. * pMachineName - name identifying machine on which the enumeration
  1025. * needs to be done
  1026. * pEnumRecord - pointer to enumeration criteria
  1027. * pBuffer - pointer to buffer to receive result, can be NULL
  1028. * pdwSize - pointer to buffer size. On return it is actual number
  1029. * of bytes copied/needed.
  1030. * pnProfiles - pointer to DWORD. On return, it is number of profiles
  1031. * copied to pBuffer.
  1032. *
  1033. * Returns:
  1034. * TRUE if successful, NULL otherwise
  1035. *
  1036. ******************************************************************************/
  1037. #ifdef UNICODE // Windows NT versions
  1038. BOOL WINAPI
  1039. EnumColorProfilesA(
  1040. PCSTR pMachineName,
  1041. PENUMTYPEA pEnumRecord,
  1042. PBYTE pBuffer,
  1043. PDWORD pdwSize,
  1044. PDWORD pnProfiles
  1045. )
  1046. {
  1047. PWSTR pwszMachineName = NULL; // Unicode machine name
  1048. PWSTR pwszDeviceName = NULL; // Unicode device name
  1049. PSTR pAnsiDeviceName = NULL; // incoming Ansi device name
  1050. PWSTR pwBuffer = NULL; // buffer to receive data
  1051. PWSTR pwTempBuffer = NULL; // temporary pointer to buffer
  1052. DWORD dwSize; // size of buffer
  1053. DWORD dwSizeOfStruct; // size of ENUMTYPE structure
  1054. DWORD dwVersion; // ENUMTYPE structure version
  1055. BOOL rc = TRUE; // return code
  1056. TRACEAPI((__TEXT("EnumColorProfilesA\n")));
  1057. //
  1058. // Validate parameters before we touch them
  1059. //
  1060. if (! pdwSize ||
  1061. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  1062. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)) ||
  1063. ! pEnumRecord ||
  1064. IsBadReadPtr(pEnumRecord, sizeof(DWORD)*3)) // probe until ENUMTYPE.dwFields
  1065. {
  1066. ParameterError_EnumColorProfilesA:
  1067. WARNING((__TEXT("Invalid parameter to EnumColorProfiles\n")));
  1068. SetLastError(ERROR_INVALID_PARAMETER);
  1069. return FALSE;
  1070. }
  1071. //
  1072. // Check structure size based on its version.
  1073. //
  1074. dwSizeOfStruct = pEnumRecord->dwSize;
  1075. dwVersion = pEnumRecord->dwVersion;
  1076. if (dwVersion >= ENUM_TYPE_VERSION)
  1077. {
  1078. if (dwSizeOfStruct < sizeof(ENUMTYPE))
  1079. goto ParameterError_EnumColorProfilesA;
  1080. }
  1081. else if (dwVersion == 0x0200)
  1082. {
  1083. if (dwSizeOfStruct < sizeof(ENUMTYPE)-sizeof(DWORD))
  1084. goto ParameterError_EnumColorProfilesA;
  1085. //
  1086. // Version 2 should not have ET_DEVICECLASS bit
  1087. //
  1088. if (pEnumRecord->dwFields & ET_DEVICECLASS)
  1089. goto ParameterError_EnumColorProfilesA;
  1090. WARNING((__TEXT("Old version ENUMTYPE to EnumColorProfiles\n")));
  1091. }
  1092. else
  1093. {
  1094. goto ParameterError_EnumColorProfilesA;
  1095. }
  1096. if (IsBadReadPtr(pEnumRecord, dwSizeOfStruct))
  1097. {
  1098. goto ParameterError_EnumColorProfilesA;
  1099. }
  1100. //
  1101. // Convert machine name to Unicode
  1102. //
  1103. if (pMachineName)
  1104. {
  1105. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  1106. }
  1107. else
  1108. pwszMachineName = NULL;
  1109. //
  1110. // If device name is specified, convert it to Unicode
  1111. //
  1112. if (pEnumRecord->dwFields & ET_DEVICENAME)
  1113. {
  1114. if (! pEnumRecord->pDeviceName)
  1115. {
  1116. WARNING((__TEXT("Invalid parameter to EnumColorProfiles\n")));
  1117. SetLastError(ERROR_INVALID_PARAMETER);
  1118. rc = FALSE;
  1119. goto EndEnumColorProfilesA;
  1120. }
  1121. //
  1122. // Convert device name to Unicode
  1123. //
  1124. pAnsiDeviceName = (PSTR)pEnumRecord->pDeviceName;
  1125. rc = rc && ConvertToUnicode(pAnsiDeviceName, &pwszDeviceName, TRUE);
  1126. pEnumRecord->pDeviceName = (PSTR) pwszDeviceName;
  1127. }
  1128. dwSize = *pdwSize * sizeof(WCHAR);
  1129. //
  1130. // Allocate buffer of suitable size
  1131. //
  1132. if (pBuffer && dwSize)
  1133. {
  1134. pwBuffer = MemAlloc(dwSize);
  1135. if (! pwBuffer)
  1136. {
  1137. WARNING((__TEXT("Error allocating memory for Unicode buffer\n")));
  1138. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1139. rc = FALSE;
  1140. goto EndEnumColorProfilesA;
  1141. }
  1142. }
  1143. //
  1144. // Call the internal Unicode function
  1145. //
  1146. rc = rc && InternalEnumColorProfiles(pwszMachineName,
  1147. (PENUMTYPEW)pEnumRecord, (PBYTE)pwBuffer, &dwSize, pnProfiles);
  1148. if (pwBuffer && rc)
  1149. {
  1150. pwTempBuffer = pwBuffer;
  1151. while (*pwTempBuffer)
  1152. {
  1153. rc = rc && ConvertToAnsi(pwTempBuffer, (PSTR *)&pBuffer, FALSE);
  1154. if (!rc)
  1155. {
  1156. pBuffer = NULL;
  1157. break;
  1158. }
  1159. pwTempBuffer += lstrlenW(pwTempBuffer) + 1;
  1160. pBuffer += (lstrlenA((PSTR)pBuffer) + 1) * sizeof(char);
  1161. }
  1162. if (pBuffer)
  1163. {
  1164. *((PSTR)pBuffer) = '\0';
  1165. }
  1166. }
  1167. *pdwSize = dwSize / sizeof(WCHAR);
  1168. EndEnumColorProfilesA:
  1169. if (pwszMachineName)
  1170. {
  1171. MemFree(pwszMachineName);
  1172. }
  1173. if (pAnsiDeviceName)
  1174. {
  1175. ASSERT(pEnumRecord->pDeviceName != NULL);
  1176. MemFree((PBYTE)pEnumRecord->pDeviceName);
  1177. pEnumRecord->pDeviceName = (PCSTR)pAnsiDeviceName;
  1178. }
  1179. if (pwBuffer)
  1180. {
  1181. MemFree(pwBuffer);
  1182. }
  1183. return rc;
  1184. }
  1185. BOOL WINAPI
  1186. EnumColorProfilesW(
  1187. PCWSTR pMachineName,
  1188. PENUMTYPEW pEnumRecord,
  1189. PBYTE pBuffer,
  1190. PDWORD pdwSize,
  1191. PDWORD pnProfiles
  1192. )
  1193. {
  1194. TRACEAPI((__TEXT("EnumColorProfilesW\n")));
  1195. //
  1196. // Internal function is Unicode in Windows NT, call it directly.
  1197. //
  1198. return InternalEnumColorProfiles(pMachineName, pEnumRecord,
  1199. pBuffer, pdwSize, pnProfiles);
  1200. }
  1201. #else // Windows 95 versions
  1202. BOOL WINAPI
  1203. EnumColorProfilesA(
  1204. PCSTR pMachineName,
  1205. PENUMTYPEA pEnumRecord,
  1206. PBYTE pBuffer,
  1207. PDWORD pdwSize,
  1208. PDWORD pnProfiles
  1209. )
  1210. {
  1211. TRACEAPI((__TEXT("EnumColorProfilesA\n")));
  1212. //
  1213. // Internal function is ANSI in Windows 95, call it directly.
  1214. //
  1215. return InternalEnumColorProfiles(pMachineName, pEnumRecord,
  1216. pBuffer, pdwSize, pnProfiles);
  1217. }
  1218. BOOL WINAPI
  1219. EnumColorProfilesW(
  1220. PCWSTR pMachineName,
  1221. PENUMTYPEW pEnumRecord,
  1222. PBYTE pBuffer,
  1223. PDWORD pdwSize,
  1224. PDWORD pnProfiles
  1225. )
  1226. {
  1227. PSTR pszMachineName = NULL; // Ansi machine name
  1228. PSTR pszDeviceName = NULL; // Ansi device name
  1229. PWSTR pUnicodeDeviceName = NULL;// incoming Unicode device name
  1230. PSTR pszBuffer = NULL; // buffer to receive data
  1231. PSTR pszTempBuffer = NULL; // temporary pointer to buffer
  1232. DWORD dwSize; // size of buffer
  1233. DWORD dwSizeOfStruct; // size of ENUMTYPE structure
  1234. DWORD dwVersion; // ENUMTYPE structure version
  1235. BOOL rc = TRUE; // return code
  1236. TRACEAPI((__TEXT("EnumColorProfilesW\n")));
  1237. //
  1238. // Validate parameters before we touch them
  1239. //
  1240. if (! pdwSize ||
  1241. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  1242. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)) ||
  1243. ! pEnumRecord ||
  1244. IsBadReadPtr(pEnumRecord, sizeof(DWORD)*3)) // probe until ENUMTYPE.dwFields
  1245. {
  1246. ParameterError_EnumColorProfilesW:
  1247. WARNING((__TEXT("Invalid parameter to EnumColorProfiles\n")));
  1248. SetLastError(ERROR_INVALID_PARAMETER);
  1249. return FALSE;
  1250. }
  1251. //
  1252. // Check structure size based on its version.
  1253. //
  1254. dwSizeOfStruct = pEnumRecord->dwSize;
  1255. dwVersion = pEnumRecord->dwVersion;
  1256. if (dwVersion >= ENUM_TYPE_VERSION)
  1257. {
  1258. if (dwSizeOfStruct < sizeof(ENUMTYPE))
  1259. goto ParameterError_EnumColorProfilesW;
  1260. }
  1261. else if (dwVersion == 0x0200)
  1262. {
  1263. if (dwSizeOfStruct < sizeof(ENUMTYPE)-sizeof(DWORD))
  1264. goto ParameterError_EnumColorProfilesW;
  1265. //
  1266. // Version 2 should not have ET_DEVICECLASS bit
  1267. //
  1268. if (pEnumRecord->dwFields & ET_DEVICECLASS)
  1269. goto ParameterError_EnumColorProfilesW;
  1270. WARNING((__TEXT("Old version ENUMTYPE to EnumColorProfiles\n")));
  1271. }
  1272. else
  1273. {
  1274. goto ParameterError_EnumColorProfilesW;
  1275. }
  1276. if (IsBadReadPtr(pEnumRecord, dwSizeOfStruct))
  1277. {
  1278. goto ParameterError_EnumColorProfilesW;
  1279. }
  1280. //
  1281. // Convert machine name to Ansi
  1282. //
  1283. if (pMachineName)
  1284. {
  1285. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  1286. }
  1287. //
  1288. // If device name is specified, convert it to Unicode
  1289. //
  1290. if (pEnumRecord->dwFields & ET_DEVICENAME)
  1291. {
  1292. if (! pEnumRecord->pDeviceName)
  1293. {
  1294. WARNING((__TEXT("Invalid parameter to EnumColorProfiles\n")));
  1295. SetLastError(ERROR_INVALID_PARAMETER);
  1296. goto EndEnumColorProfilesW;
  1297. }
  1298. //
  1299. // Convert device name to Ansi
  1300. //
  1301. pUnicodeDeviceName = (PWSTR)pEnumRecord->pDeviceName;
  1302. rc = rc && ConvertToAnsi(pUnicodeDeviceName, &pszDeviceName, TRUE);
  1303. pEnumRecord->pDeviceName = (PCWSTR) pszDeviceName;
  1304. }
  1305. dwSize = *pdwSize / sizeof(WCHAR);
  1306. //
  1307. // Allocate buffer of suitable size
  1308. //
  1309. if (pBuffer && dwSize)
  1310. {
  1311. pszBuffer = MemAlloc(dwSize);
  1312. if (! pszBuffer)
  1313. {
  1314. WARNING((__TEXT("Error allocating memory for Ansi buffer\n")));
  1315. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1316. rc = FALSE;
  1317. goto EndEnumColorProfilesW;
  1318. }
  1319. }
  1320. //
  1321. // Call the internal Ansi function
  1322. //
  1323. rc = rc && InternalEnumColorProfiles(pszMachineName,
  1324. (PENUMTYPEA)pEnumRecord, (PBYTE)pszBuffer, &dwSize, pnProfiles);
  1325. if (pszBuffer && rc)
  1326. {
  1327. pszTempBuffer = pszBuffer;
  1328. while (*pszTempBuffer)
  1329. {
  1330. rc = rc && ConvertToUnicode(pszTempBuffer, (PWSTR *)&pBuffer, FALSE);
  1331. pszTempBuffer += lstrlenA(pszTempBuffer) + 1;
  1332. pBuffer += (lstrlenW((PWSTR)pBuffer) + 1) * sizeof(WCHAR);
  1333. }
  1334. *((PWSTR)pBuffer) = '\0';
  1335. }
  1336. *pdwSize = dwSize * sizeof(WCHAR);
  1337. EndEnumColorProfilesW:
  1338. if (pszMachineName)
  1339. {
  1340. MemFree(pszMachineName);
  1341. }
  1342. if (pUnicodeDeviceName)
  1343. {
  1344. ASSERT(pEnumRecord->pDeviceName != NULL);
  1345. MemFree((PSTR)pEnumRecord->pDeviceName);
  1346. pEnumRecord->pDeviceName = (PCWSTR)pUnicodeDeviceName;
  1347. }
  1348. if (pszBuffer)
  1349. {
  1350. MemFree(pszBuffer);
  1351. }
  1352. return rc;
  1353. }
  1354. #endif // ! UNICODE
  1355. /******************************************************************************
  1356. *
  1357. * SetStandardColorSpaceProfile
  1358. *
  1359. * Function:
  1360. * These are the ANSI & Unicode wrappers for InternalSetSCSProfile.
  1361. * Please see InternalSetSCSProfile for more details on this
  1362. * function.
  1363. *
  1364. * Arguments:
  1365. * pMachineName - name identifying machine on which the standard color
  1366. * space profile should be registered
  1367. * dwSCS - ID for the standard color space
  1368. * pProfileName - pointer to profile filename
  1369. *
  1370. * Returns:
  1371. * TRUE if successful, NULL otherwise
  1372. *
  1373. ******************************************************************************/
  1374. #ifdef UNICODE // Windows NT versions
  1375. BOOL WINAPI
  1376. SetStandardColorSpaceProfileA(
  1377. PCSTR pMachineName,
  1378. DWORD dwSCS,
  1379. PCSTR pProfileName
  1380. )
  1381. {
  1382. PWSTR pwszMachineName = NULL; // Unicode machine name
  1383. PWSTR pwszProfileName = NULL; // Unicode profile name
  1384. BOOL rc = TRUE; // return code
  1385. TRACEAPI((__TEXT("SetStandardColorSpaceProfileA\n")));
  1386. //
  1387. // Validate parameters before we touch them
  1388. //
  1389. if (! pProfileName)
  1390. {
  1391. WARNING((__TEXT("Invalid parameter to SetStandardColorSpaceProfile\n")));
  1392. SetLastError(ERROR_INVALID_PARAMETER);
  1393. return FALSE;
  1394. }
  1395. //
  1396. // Convert machine name to Unicode
  1397. //
  1398. if (pMachineName)
  1399. {
  1400. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  1401. }
  1402. else
  1403. pwszMachineName = NULL;
  1404. //
  1405. // Convert profile name to Unicode
  1406. //
  1407. rc = rc && ConvertToUnicode(pProfileName, &pwszProfileName, TRUE);
  1408. //
  1409. // Call the internal Unicode function
  1410. //
  1411. rc = rc && InternalSetSCSProfile(pwszMachineName, dwSCS, pwszProfileName);
  1412. //
  1413. // Free memory before leaving
  1414. //
  1415. if (pwszProfileName)
  1416. {
  1417. MemFree(pwszProfileName);
  1418. }
  1419. if (pwszMachineName)
  1420. {
  1421. MemFree(pwszMachineName);
  1422. }
  1423. return rc;
  1424. }
  1425. BOOL WINAPI
  1426. SetStandardColorSpaceProfileW(
  1427. PCWSTR pMachineName,
  1428. DWORD dwSCS,
  1429. PCWSTR pProfileName
  1430. )
  1431. {
  1432. TRACEAPI((__TEXT("SetStandardColorSpaceProfileW\n")));
  1433. //
  1434. // Internal function is Unicode in Windows NT, call it directly.
  1435. //
  1436. return InternalSetSCSProfile(pMachineName, dwSCS, pProfileName);
  1437. }
  1438. #else // Windows 95 versions
  1439. BOOL WINAPI
  1440. SetStandardColorSpaceProfileA(
  1441. PCSTR pMachineName,
  1442. DWORD dwSCS,
  1443. PCSTR pProfileName
  1444. )
  1445. {
  1446. TRACEAPI((__TEXT("SetStandardColorSpaceProfileA\n")));
  1447. //
  1448. // Internal function is ANSI in Windows 95, call it directly.
  1449. //
  1450. return InternalSetSCSProfile(pMachineName, dwSCS, pProfileName);
  1451. }
  1452. BOOL WINAPI
  1453. SetStandardColorSpaceProfileW(
  1454. PCWSTR pMachineName,
  1455. DWORD dwSCS,
  1456. PCWSTR pProfileName
  1457. )
  1458. {
  1459. PSTR pszMachineName = NULL; // Ansi machine name
  1460. PSTR pszProfileName = NULL; // Ansi profile name
  1461. BOOL rc = TRUE; // return code
  1462. TRACEAPI((__TEXT("SetStandardColorSpaceProfileW\n")));
  1463. //
  1464. // Validate parameters before we touch them
  1465. //
  1466. if (! pProfileName)
  1467. {
  1468. WARNING((__TEXT("Invalid parameter to SetStandardColorSpaceProfile\n")));
  1469. SetLastError(ERROR_INVALID_PARAMETER);
  1470. return FALSE;
  1471. }
  1472. //
  1473. // Convert machine name to Ansi
  1474. //
  1475. if (pMachineName)
  1476. {
  1477. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  1478. }
  1479. else
  1480. pszMachineName = NULL;
  1481. //
  1482. // Convert profile name to Ansi
  1483. //
  1484. rc = rc && ConvertToAnsi(pProfileName, &pszProfileName, TRUE);
  1485. //
  1486. // Call the internal Ansi function
  1487. //
  1488. rc = rc && InternalSetSCSProfile(pszMachineName, dwSCS, pszProfileName);
  1489. //
  1490. // Free memory before leaving
  1491. //
  1492. if (pszProfileName)
  1493. {
  1494. MemFree(pszProfileName);
  1495. }
  1496. if (pszMachineName)
  1497. {
  1498. MemFree(pszMachineName);
  1499. }
  1500. return rc;
  1501. }
  1502. #endif // ! UNICODE
  1503. /******************************************************************************
  1504. *
  1505. * GetStandardColorSpaceProfile
  1506. *
  1507. * Function:
  1508. * These are the ANSI & Unicode wrappers for InternalGetSCSProfile.
  1509. * Please see InternalGetSCSProfile for more details on this
  1510. * function.
  1511. *
  1512. * Arguments:
  1513. * pMachineName - name identifying machine on which the standard color
  1514. * space profile should be queried
  1515. * dwSCS - ID for the standard color space
  1516. * pBuffer - pointer to buffer to receive profile filename
  1517. * pdwSize - pointer to DWORD specifying size of buffer. On return
  1518. * it has size needed/used
  1519. *
  1520. * Returns:
  1521. * TRUE if successful, NULL otherwise
  1522. *
  1523. ******************************************************************************/
  1524. #ifdef UNICODE // Windows NT versions
  1525. BOOL WINAPI
  1526. GetStandardColorSpaceProfileA(
  1527. PCSTR pMachineName,
  1528. DWORD dwSCS,
  1529. PSTR pBuffer,
  1530. PDWORD pdwSize
  1531. )
  1532. {
  1533. PWSTR pwszMachineName = NULL; // Unicode machine name
  1534. PWSTR pwBuffer = NULL; // Unicode color directory path
  1535. DWORD dwSize; // size of Unicode buffer
  1536. BOOL rc = TRUE; // return code
  1537. TRACEAPI((__TEXT("GetStandardColorSpaceProfileA\n")));
  1538. //
  1539. // Validate parameters before we touch them
  1540. //
  1541. if (! pdwSize ||
  1542. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  1543. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)))
  1544. {
  1545. WARNING((__TEXT("Invalid parameter to GetStandardColorSpaceProfile\n")));
  1546. SetLastError(ERROR_INVALID_PARAMETER);
  1547. return FALSE;
  1548. }
  1549. //
  1550. // Convert machine name to Unicode
  1551. //
  1552. if (pMachineName)
  1553. {
  1554. rc = ConvertToUnicode(pMachineName, &pwszMachineName, TRUE);
  1555. }
  1556. else
  1557. pwszMachineName = NULL;
  1558. dwSize = *pdwSize * sizeof(WCHAR);
  1559. //
  1560. // Create a buffer to get Unicode filename from system
  1561. //
  1562. if (pBuffer && dwSize)
  1563. {
  1564. pwBuffer = (PWSTR)MemAlloc(dwSize);
  1565. if (! pwBuffer)
  1566. {
  1567. WARNING((__TEXT("Error allocating memory for Unicode string\n")));
  1568. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1569. rc = FALSE;
  1570. goto EndGetSCSProfileA;
  1571. }
  1572. }
  1573. rc = rc && InternalGetSCSProfile(pwszMachineName, dwSCS, pwBuffer, &dwSize);
  1574. *pdwSize = dwSize / sizeof(WCHAR);
  1575. //
  1576. // Convert Unicode path to Ansi
  1577. //
  1578. if (pwBuffer)
  1579. {
  1580. rc = rc && ConvertToAnsi(pwBuffer, &pBuffer, FALSE);
  1581. }
  1582. EndGetSCSProfileA:
  1583. if (pwszMachineName)
  1584. {
  1585. MemFree(pwszMachineName);
  1586. }
  1587. if (pwBuffer)
  1588. {
  1589. MemFree(pwBuffer);
  1590. }
  1591. return rc;
  1592. }
  1593. BOOL WINAPI
  1594. GetStandardColorSpaceProfileW(
  1595. PCWSTR pMachineName,
  1596. DWORD dwSCS,
  1597. PWSTR pBuffer,
  1598. PDWORD pdwSize
  1599. )
  1600. {
  1601. TRACEAPI((__TEXT("GetStandardColorSpaceProfileW\n")));
  1602. //
  1603. // Internal function is Unicode in Windows NT, call it directly.
  1604. //
  1605. return InternalGetSCSProfile(pMachineName, dwSCS, pBuffer, pdwSize);
  1606. }
  1607. #else // Windows 95 versions
  1608. BOOL WINAPI
  1609. GetStandardColorSpaceProfileA(
  1610. PCSTR pMachineName,
  1611. DWORD dwSCS,
  1612. PSTR pBuffer,
  1613. PDWORD pdwSize
  1614. )
  1615. {
  1616. TRACEAPI((__TEXT("GetStandardColorSpaceProfileA\n")));
  1617. //
  1618. // Internal function is ANSI in Windows 95, call it directly.
  1619. //
  1620. return InternalGetSCSProfile(pMachineName, dwSCS, pBuffer, pdwSize);
  1621. }
  1622. BOOL WINAPI
  1623. GetStandardColorSpaceProfileW(
  1624. PCWSTR pMachineName,
  1625. DWORD dwSCS,
  1626. PWSTR pBuffer,
  1627. PDWORD pdwSize
  1628. )
  1629. {
  1630. PSTR pszMachineName = NULL; // Ansi machine name
  1631. PSTR pszBuffer = NULL; // Ansi color directory path
  1632. DWORD dwSize; // size of Ansi buffer
  1633. BOOL rc = TRUE; // return code
  1634. TRACEAPI((__TEXT("GetStandardColorSpaceProfileW\n")));
  1635. //
  1636. // Validate parameters before we touch them
  1637. //
  1638. if (! pdwSize ||
  1639. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  1640. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)))
  1641. {
  1642. WARNING((__TEXT("Invalid parameter to GetStandardColorSpaceProfile\n")));
  1643. SetLastError(ERROR_INVALID_PARAMETER);
  1644. return FALSE;
  1645. }
  1646. //
  1647. // Convert machine name to Ansi
  1648. //
  1649. if (pMachineName)
  1650. {
  1651. rc = ConvertToAnsi(pMachineName, &pszMachineName, TRUE);
  1652. }
  1653. else
  1654. pszMachineName = NULL;
  1655. dwSize = *pdwSize / sizeof(WCHAR);
  1656. //
  1657. // Create a buffer to get Ansi profilename from system
  1658. //
  1659. if (pBuffer && dwSize)
  1660. {
  1661. pszBuffer = (PSTR)MemAlloc(dwSize);
  1662. if (! pBuffer)
  1663. {
  1664. WARNING((__TEXT("Error allocating memory for Ansi string\n")));
  1665. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1666. rc = FALSE;
  1667. goto EndGetSCSProfileW;
  1668. }
  1669. }
  1670. rc = rc && InternalGetSCSProfile(pszMachineName, dwSCS, pszBuffer, &dwSize);
  1671. *pdwSize = dwSize * sizeof(WCHAR);
  1672. //
  1673. // Convert Ansi path to Unicode
  1674. //
  1675. if (pszBuffer)
  1676. {
  1677. rc = rc && ConvertToUnicode(pszBuffer, &pBuffer, FALSE);
  1678. }
  1679. EndGetSCSProfileW:
  1680. if (pszMachineName)
  1681. {
  1682. MemFree(pszMachineName);
  1683. }
  1684. if (pszBuffer)
  1685. {
  1686. MemFree(pszBuffer);
  1687. }
  1688. return rc;
  1689. }
  1690. #endif // ! UNICODE
  1691. /******************************************************************************
  1692. *
  1693. * GenerateCopyFilePaths
  1694. *
  1695. * Function:
  1696. * This function is called by the Windows NT spooler to find the
  1697. * directories from which color profiles should be picked up and copied
  1698. * to. This is useful if the locations are version or processor
  1699. * architecture dependent. As color profiles depend on neither, we don't
  1700. * have to do anything, but have to export this function.
  1701. *
  1702. * Arguments:
  1703. * don't care
  1704. *
  1705. * Returns:
  1706. * ERROR_SUCCESS if successful, error code otherwise
  1707. *
  1708. ******************************************************************************/
  1709. DWORD WINAPI
  1710. GenerateCopyFilePaths(
  1711. LPCWSTR pszPrinterName,
  1712. LPCWSTR pszDirectory,
  1713. LPBYTE pSplClientInfo,
  1714. DWORD dwLevel,
  1715. LPWSTR pszSourceDir,
  1716. LPDWORD pcchSourceDirSize,
  1717. LPWSTR pszTargetDir,
  1718. LPDWORD pcchTargetDirSize,
  1719. DWORD dwFlags
  1720. )
  1721. {
  1722. TRACEAPI((__TEXT("GenerateCopyFilePaths\n")));
  1723. return ERROR_SUCCESS;
  1724. }
  1725. /******************************************************************************
  1726. *
  1727. * SpoolerCopyFileEvent
  1728. *
  1729. * Function:
  1730. * This function is called by the Windows NT spooler when one of the
  1731. * following events happens:
  1732. * 1. When someone does a SetPrinterDataEx of the CopyFiles section
  1733. * 2. When a printer connection is made
  1734. * 3. When files for a printer connection get updated
  1735. * 4. When a printer is deleted
  1736. *
  1737. * Arguments:
  1738. * pszPrinterName - friendly name of printer
  1739. * pszKey - "CopyFiles\ICM" for us
  1740. * dwCopyFileEvent - reason for calling
  1741. *
  1742. * Returns:
  1743. * TRUE if successful, NULL otherwise
  1744. *
  1745. ******************************************************************************/
  1746. BOOL WINAPI
  1747. SpoolerCopyFileEvent(
  1748. LPWSTR pszPrinterName,
  1749. LPWSTR pszKey,
  1750. DWORD dwCopyFileEvent
  1751. )
  1752. {
  1753. PTSTR pProfileList, pTemp, pBuffer;
  1754. DWORD dwSize;
  1755. BOOL bRc = FALSE;
  1756. TCHAR szPath[MAX_PATH];
  1757. TRACEAPI((__TEXT("SpoolerCopyFileEvent\n")));
  1758. switch (dwCopyFileEvent)
  1759. {
  1760. case COPYFILE_EVENT_SET_PRINTER_DATAEX:
  1761. //
  1762. // When associating profiles with printer connections, we copy
  1763. // the files to the remote machine, and then do a SePrinterDataEx.
  1764. // This causes this event to be generated on the remote machine. We
  1765. // use this to install the profile. This is not needed after we make
  1766. // our APIs remotable
  1767. //
  1768. // Fall thru'
  1769. //
  1770. TERSE((__TEXT("SetPrinterDataEx event\n")));
  1771. case COPYFILE_EVENT_ADD_PRINTER_CONNECTION:
  1772. case COPYFILE_EVENT_FILES_CHANGED:
  1773. //
  1774. // This event is generated when a printer connection is added or
  1775. // associated profiles have changed. Install all the profiles in
  1776. // the client machine now.
  1777. //
  1778. #if DBG
  1779. if (dwCopyFileEvent == COPYFILE_EVENT_ADD_PRINTER_CONNECTION)
  1780. {
  1781. WARNING((__TEXT("AddPrinterConnection Event\n")));
  1782. }
  1783. else if (dwCopyFileEvent == COPYFILE_EVENT_FILES_CHANGED)
  1784. {
  1785. WARNING((__TEXT("FilesChanged Event\n")));
  1786. }
  1787. #endif
  1788. dwSize = 0;
  1789. if (GetDeviceData((PTSTR)pszPrinterName, CLASS_PRINTER, DEVICE_PROFILE_DATA,
  1790. (PVOID *)&pProfileList, &dwSize, TRUE))
  1791. {
  1792. dwSize = sizeof(szPath);
  1793. if (InternalGetColorDirectory(NULL, szPath, &dwSize))
  1794. {
  1795. lstrcat(szPath, gszBackslash);
  1796. pBuffer = szPath + lstrlen(szPath);
  1797. pTemp = pProfileList;
  1798. while (*pTemp)
  1799. {
  1800. lstrcpy(pBuffer, pTemp);
  1801. InstallColorProfile(NULL, szPath);
  1802. pTemp += lstrlen(pTemp) + 1;
  1803. }
  1804. }
  1805. MemFree(pProfileList);
  1806. }
  1807. break;
  1808. case COPYFILE_EVENT_DELETE_PRINTER:
  1809. //
  1810. // This event is generated when a printer is about to be deleted.
  1811. // Get all profiles associated with the printer and disassociate
  1812. // them now.
  1813. //
  1814. TERSE((__TEXT("DeletePrinterDataEx Event\n")));
  1815. dwSize = 0;
  1816. if (GetDeviceData((PTSTR)pszPrinterName, CLASS_PRINTER, DEVICE_PROFILE_DATA,
  1817. (PVOID *)&pProfileList, &dwSize, TRUE))
  1818. {
  1819. pTemp = pProfileList;
  1820. while (*pTemp)
  1821. {
  1822. DisassociateColorProfileFromDevice(NULL, pTemp, (PTSTR)pszPrinterName);
  1823. pTemp += lstrlen(pTemp) + 1;
  1824. }
  1825. MemFree(pProfileList);
  1826. }
  1827. break;
  1828. }
  1829. bRc = TRUE;
  1830. return bRc;
  1831. }
  1832. /*****************************************************************************/
  1833. /***************************** Internal Functions ****************************/
  1834. /*****************************************************************************/
  1835. /******************************************************************************
  1836. *
  1837. * InternalGetColorDirectory
  1838. *
  1839. * Function:
  1840. * This function returns the path to the color directory on the machine
  1841. * specified.
  1842. * associations should be removed before calling this function. It also
  1843. * optionally deletes the file if the profile was successfully
  1844. * uninstalled.
  1845. *
  1846. * Arguments:
  1847. * pMachineName - name identifying machine on which the path
  1848. * to the color directory is requested
  1849. * pBuffer - pointer to buffer to receive pathname
  1850. * pdwSize - pointer to size of buffer. On return it has size of
  1851. * buffer needed if failure, and used on success
  1852. *
  1853. * Returns:
  1854. * TRUE if successful, FALSE otherwise
  1855. *
  1856. ******************************************************************************/
  1857. BOOL
  1858. InternalGetColorDirectory(
  1859. LPCTSTR pMachineName,
  1860. PTSTR pBuffer,
  1861. DWORD *pdwSize
  1862. )
  1863. {
  1864. DWORD dwBufLen = *pdwSize; // size supplied
  1865. BOOL rc = FALSE; // return value
  1866. //
  1867. // Get the printer driver directory
  1868. //
  1869. #if !defined(_WIN95_)
  1870. DWORD dwNeeded; // size needed
  1871. BOOL bSuccess;
  1872. DWORD dwTempSize;
  1873. bSuccess = FALSE;
  1874. if (!pBuffer && pdwSize && !IsBadWritePtr(pdwSize, sizeof(DWORD)))
  1875. {
  1876. *pdwSize = MAX_PATH;
  1877. //
  1878. // Doing the same thing as GetPrinterDriverDirectory does.
  1879. // When the buffer is NULL, return FALSE and set last error.
  1880. //
  1881. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1882. return FALSE;
  1883. }
  1884. dwTempSize = *pdwSize;
  1885. bSuccess = GetPrinterDriverDirectory(
  1886. (PTSTR)pMachineName,
  1887. NULL,
  1888. 1,
  1889. (PBYTE)pBuffer,
  1890. *pdwSize,
  1891. pdwSize
  1892. );
  1893. if( (!bSuccess) &&
  1894. (GetLastError() == ERROR_INVALID_ENVIRONMENT) )
  1895. {
  1896. //
  1897. // We failed with invalid environment, try this again with a
  1898. // guaranteed valid environment...
  1899. // Could be IA64 -> win2K and win2K with no SP1 will fail as
  1900. // it didn't know about "Windows IA64"
  1901. //
  1902. *pdwSize = dwTempSize;
  1903. bSuccess = GetPrinterDriverDirectory(
  1904. (PTSTR)pMachineName,
  1905. __TEXT("Windows NT x86"),
  1906. 1,
  1907. (PBYTE)pBuffer,
  1908. *pdwSize, pdwSize
  1909. );
  1910. }
  1911. if (bSuccess)
  1912. {
  1913. //
  1914. // This API returns the print$ path appended with the environment
  1915. // directory. e.g. c:\winnt\system32\spool\drivers\w32x86. So we need
  1916. // to go back one step and then append the color directory.
  1917. //
  1918. PWSTR pDriverDir;
  1919. if(pDriverDir = GetFilenameFromPath(pBuffer))
  1920. {
  1921. ASSERT (pDriverDir != NULL);
  1922. *pdwSize -= lstrlen(pDriverDir) * sizeof(WCHAR);
  1923. *pDriverDir = '\0';
  1924. //
  1925. // Calculate size of buffer needed to append color directory
  1926. //
  1927. dwNeeded = *pdwSize + lstrlen(gszColorDir) * sizeof(WCHAR);
  1928. if (pBuffer[lstrlen(pBuffer) - 1] != '\\')
  1929. {
  1930. dwNeeded += sizeof(WCHAR);
  1931. }
  1932. //
  1933. // Update size needed
  1934. //
  1935. *pdwSize = dwNeeded;
  1936. //
  1937. // If supplied buffer is big enough, append our stuff
  1938. //
  1939. if (dwNeeded <= dwBufLen)
  1940. {
  1941. if (pBuffer[lstrlen(pBuffer) - 1] != '\\')
  1942. {
  1943. lstrcat(pBuffer, gszBackslash);
  1944. }
  1945. lstrcat(pBuffer, gszColorDir);
  1946. rc = TRUE;
  1947. }
  1948. else
  1949. {
  1950. WARNING((__TEXT("Input buffer to GetColorDirectory not big enough\n")));
  1951. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1952. }
  1953. }
  1954. }
  1955. else if (GetLastError() == ERROR_INVALID_USER_BUFFER)
  1956. {
  1957. //
  1958. // Spooler sets this error if buffer is NULL. Map it to our error
  1959. //
  1960. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1961. }
  1962. else if (GetLastError() == RPC_S_SERVER_UNAVAILABLE)
  1963. {
  1964. TCHAR achTempPath[MAX_PATH * 2]; // Make sure enough path space.
  1965. //
  1966. // Spooler service is not running. Use hardcoded path
  1967. //
  1968. if (GetSystemDirectory(achTempPath,MAX_PATH) != 0)
  1969. {
  1970. _tcscat(achTempPath,TEXT("\\spool\\drivers\\color"));
  1971. *pdwSize = wcslen(achTempPath) + 1;
  1972. if (pBuffer && (*pdwSize <= dwBufLen))
  1973. {
  1974. _tcscpy(pBuffer,achTempPath);
  1975. rc = TRUE;
  1976. }
  1977. else
  1978. {
  1979. WARNING((__TEXT("Input buffer to GetColorDirectory not big enough\n")));
  1980. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1981. }
  1982. }
  1983. }
  1984. #else
  1985. HKEY hkSetup; // registry key
  1986. DWORD dwErr; // error code
  1987. //
  1988. // Only local color directory query is allowed in Memphis
  1989. //
  1990. if (pMachineName)
  1991. {
  1992. WARNING((__TEXT("Remote color directory query, failing...\n")));
  1993. SetLastError(ERROR_INVALID_PARAMETER);
  1994. return FALSE;
  1995. }
  1996. //
  1997. // On Memphis, get this information from the setup section in the registry.
  1998. // The reason we don't call GetPrinterDriverDirectory is that when we call
  1999. // this function from GDI 16, it tries to go back into 16-bit mode and
  2000. // deadlocks on the Win16 lock.
  2001. //
  2002. if ((dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, gszSetupPath, &hkSetup)) == ERROR_SUCCESS)
  2003. {
  2004. if ((dwErr = RegQueryValueEx(hkSetup, gszICMDir, 0, NULL, (PBYTE)pBuffer,
  2005. pdwSize)) == ERROR_SUCCESS)
  2006. {
  2007. rc = TRUE;
  2008. }
  2009. RegCloseKey(hkSetup);
  2010. }
  2011. if (!rc)
  2012. {
  2013. //
  2014. // Make error codes consistent
  2015. //
  2016. if (dwErr == ERROR_MORE_DATA)
  2017. {
  2018. dwErr = ERROR_INSUFFICIENT_BUFFER;
  2019. }
  2020. WARNING((__TEXT("Error getting color directory: %d\n"), dwErr));
  2021. SetLastError(dwErr);
  2022. }
  2023. //
  2024. // RegQueryValueEx returns TRUE even if the calling buffer is NULL. Our API
  2025. // is supposed to return FALSE. Check for this case.
  2026. //
  2027. if (pBuffer == NULL && rc)
  2028. {
  2029. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2030. rc = FALSE;
  2031. }
  2032. #endif // !defined(_WIN95_)
  2033. return rc;
  2034. }
  2035. /******************************************************************************
  2036. *
  2037. * InternalInstallColorProfile
  2038. *
  2039. * Function:
  2040. * This function installs a given color profile on a a given machine.
  2041. *
  2042. * Arguments:
  2043. * pMachineName - name identifying machine on which the profile
  2044. * should be uninstalled. NULL implies local
  2045. * pProfileName - Fully qualified pathname of profile to uninstall
  2046. * bDelete - TRUE if profile should be deleted in disk
  2047. *
  2048. * Returns:
  2049. * TRUE if successful, NULL otherwise
  2050. *
  2051. * Warning:
  2052. * Currently only local install is supported, so pMachineName should
  2053. * be NULL.
  2054. *
  2055. ******************************************************************************/
  2056. BOOL
  2057. InternalInstallColorProfile(
  2058. LPCTSTR pMachineName,
  2059. LPCTSTR pProfileName
  2060. )
  2061. {
  2062. PROFILEHEADER header; // profile header
  2063. REGDATA regData; // for storing registry data about profile
  2064. HKEY hkICM = NULL; // key to ICM branch in registry
  2065. HKEY hkDevice = NULL; // key to ICM device branch in registry
  2066. DWORD dwSize; // size of registry data for profile
  2067. DWORD dwErr; // error code
  2068. BOOL rc = FALSE; // return code
  2069. PTSTR pFilename; // profile name without path
  2070. TCHAR szDest[MAX_PATH]; // destination path for profile
  2071. TCHAR szClass[5]; // profile class
  2072. BOOL FileExist; // profile already in directory?
  2073. BOOL RegExist; // profile in registry?
  2074. //
  2075. // Validate parameters
  2076. //
  2077. if (!pProfileName)
  2078. {
  2079. WARNING((__TEXT("Invalid parameter to InstallColorProfile\n")));
  2080. SetLastError(ERROR_INVALID_PARAMETER);
  2081. return FALSE;
  2082. }
  2083. //
  2084. // Only local installs are allowed now
  2085. //
  2086. if (pMachineName)
  2087. {
  2088. WARNING((__TEXT("Remote install attempted, failing...\n")));
  2089. SetLastError(ERROR_INVALID_PARAMETER);
  2090. return FALSE;
  2091. }
  2092. //
  2093. // Get rid of the directory path and get a pointer to the filename
  2094. //
  2095. pFilename = GetFilenameFromPath((PTSTR)pProfileName);
  2096. if (! pFilename)
  2097. {
  2098. WARNING((__TEXT("Could not parse file name from profile path %s\n"), pProfileName));
  2099. SetLastError(ERROR_INVALID_PARAMETER);
  2100. goto EndInstallColorProfile;
  2101. }
  2102. //
  2103. // Get the profile class in the form of a string
  2104. //
  2105. if (! GetProfileClassString(pProfileName, szClass, &header))
  2106. {
  2107. WARNING((__TEXT("Installing invalid profile %s\n"), pProfileName));
  2108. SetLastError(ERROR_INVALID_PROFILE);
  2109. goto EndInstallColorProfile;
  2110. }
  2111. //
  2112. // Open the registry path where profiles are kept
  2113. //
  2114. if (((dwErr = RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) != ERROR_SUCCESS) ||
  2115. ((dwErr = RegCreateKey(hkICM, szClass, &hkDevice)) != ERROR_SUCCESS))
  2116. {
  2117. WARNING((__TEXT("Cannot open ICM\\device branch of registry: %d\n"), dwErr));
  2118. SetLastError(dwErr);
  2119. goto EndInstallColorProfile;
  2120. }
  2121. //
  2122. // If registry data exists && the profile is in the directory, then the profile is already installed,
  2123. // in which case, return success. Otherwise, copy profile to color
  2124. // directory (if it's not already there) and add it to the registry (if it's not already there).
  2125. //
  2126. dwSize = sizeof(szDest);
  2127. //
  2128. // Copy the file to the color directory
  2129. //
  2130. if (! InternalGetColorDirectory(NULL, szDest, &dwSize))
  2131. {
  2132. WARNING((__TEXT("Could not get color directory\n")));
  2133. goto EndInstallColorProfile;
  2134. }
  2135. //
  2136. // This creates the directory if it doesn't exist, doesn't do anything
  2137. // if it already exists
  2138. //
  2139. CreateDirectory(szDest, NULL);
  2140. if (szDest[lstrlen(szDest) - 1] != '\\')
  2141. {
  2142. lstrcat(szDest, gszBackslash);
  2143. }
  2144. lstrcat(szDest, pFilename);
  2145. //
  2146. // If the profile is already in the color directory, do not attempt
  2147. // to copy it again; it will fail.
  2148. //
  2149. dwSize = sizeof(REGDATA);
  2150. FileExist = GetFileAttributes(szDest) != (DWORD)-1;
  2151. RegExist = RegQueryValueEx(hkDevice, pFilename, 0, NULL, (PBYTE)&regData, &dwSize) == ERROR_SUCCESS;
  2152. //
  2153. // If the file does exist, short circuit the CopyFile
  2154. // and go on to add it into the registry.
  2155. //
  2156. if (!FileExist && !CopyFile(pProfileName, szDest, FALSE))
  2157. {
  2158. WARNING((__TEXT("Could not copy profile %s to color directory\n"), pProfileName));
  2159. goto EndInstallColorProfile;
  2160. }
  2161. //
  2162. // Add profile to the registry
  2163. //
  2164. if(!RegExist)
  2165. {
  2166. regData.dwRefCount = 0;
  2167. regData.dwManuID = FIX_ENDIAN(header.phManufacturer);
  2168. regData.dwModelID = FIX_ENDIAN(header.phModel);
  2169. if ((dwErr = RegSetValueEx(hkDevice, pFilename, 0, REG_BINARY,
  2170. (PBYTE)&regData, sizeof(REGDATA))) != ERROR_SUCCESS)
  2171. {
  2172. WARNING((__TEXT("Could not set registry data to install profile %s: %d\n"), pFilename, dwErr));
  2173. SetLastError(dwErr);
  2174. goto EndInstallColorProfile;
  2175. }
  2176. }
  2177. rc = TRUE; // Everything went well!
  2178. EndInstallColorProfile:
  2179. if (hkICM)
  2180. {
  2181. RegCloseKey(hkICM);
  2182. }
  2183. if (hkDevice)
  2184. {
  2185. RegCloseKey(hkDevice);
  2186. }
  2187. return rc;
  2188. }
  2189. /******************************************************************************
  2190. *
  2191. * InternalUninstallColorProfile
  2192. *
  2193. * Function:
  2194. * This function uninstalls a given color profile on a a given machine.
  2195. * It fails if the color profile is associated with any device, so all
  2196. * associations should be removed before calling this function. It also
  2197. * optionally deletes the file if the profile was successfully
  2198. * uninstalled.
  2199. *
  2200. * Arguments:
  2201. * pMachineName - name identifying machine on which the profile
  2202. * should be uninstalled. NULL implies local
  2203. * pProfileName - pointer to profile to uninstall
  2204. * bDelete - TRUE if profile should be deleted in disk
  2205. *
  2206. * Returns:
  2207. * TRUE if successful, NULL otherwise
  2208. *
  2209. * Warning:
  2210. * Currently only local uninstall is supported, so pMachineName should
  2211. * be NULL.
  2212. *
  2213. ******************************************************************************/
  2214. BOOL
  2215. InternalUninstallColorProfile(
  2216. LPCTSTR pMachineName,
  2217. LPCTSTR pProfileName,
  2218. BOOL bDelete
  2219. )
  2220. {
  2221. REGDATA regData; // for storing registry data about profile
  2222. HKEY hkICM = NULL; // key to ICM branch in registry
  2223. HKEY hkDevice = NULL; // key to ICM device branch in registry
  2224. DWORD dwSize; // size of registry data for profile
  2225. DWORD dwErr; // error code
  2226. BOOL rc = FALSE; // return code
  2227. PTSTR pFilename; // profile name without path
  2228. TCHAR szColorPath[MAX_PATH]; // full path name of profile
  2229. TCHAR szClass[5]; // profile class
  2230. //
  2231. // Validate parameters
  2232. //
  2233. if (!pProfileName)
  2234. {
  2235. WARNING((__TEXT("Invalid parameter to UninstallColorProfile\n")));
  2236. SetLastError(ERROR_INVALID_PARAMETER);
  2237. return FALSE;
  2238. }
  2239. //
  2240. // Only local installs are allowed now
  2241. //
  2242. if (pMachineName != NULL)
  2243. {
  2244. WARNING((__TEXT("Remote uninstall attempted, failing...\n")));
  2245. SetLastError(ERROR_NOT_SUPPORTED);
  2246. return FALSE;
  2247. }
  2248. //
  2249. // Get rid of the directory path and get a pointer to the filename
  2250. //
  2251. pFilename = GetFilenameFromPath((PTSTR)pProfileName);
  2252. if (! pFilename)
  2253. {
  2254. WARNING((__TEXT("Could not parse file name from profile path\n"), pProfileName));
  2255. SetLastError(ERROR_INVALID_PARAMETER);
  2256. goto EndUninstallColorProfile;
  2257. }
  2258. //
  2259. // Create a fully qualified path name
  2260. //
  2261. dwSize = sizeof(szColorPath);
  2262. if (! InternalGetColorDirectory(NULL, szColorPath, &dwSize))
  2263. {
  2264. WARNING((__TEXT("Could not get color directory\n")));
  2265. goto EndUninstallColorProfile;
  2266. }
  2267. if (szColorPath[lstrlen(szColorPath) - 1] != '\\')
  2268. {
  2269. lstrcat(szColorPath, gszBackslash);
  2270. }
  2271. lstrcat(szColorPath, pFilename);
  2272. //
  2273. // Get the profile class in the form of a string
  2274. //
  2275. if (! GetProfileClassString(szColorPath, szClass, NULL))
  2276. {
  2277. WARNING((__TEXT("Installing invalid profile\n")));
  2278. SetLastError(ERROR_INVALID_PROFILE);
  2279. goto EndUninstallColorProfile;
  2280. }
  2281. //
  2282. // Open the registry path where profiles are kept
  2283. //
  2284. if (((dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) != ERROR_SUCCESS) ||
  2285. ((dwErr = RegOpenKey(hkICM, szClass, &hkDevice)) != ERROR_SUCCESS))
  2286. {
  2287. WARNING((__TEXT("Cannot open ICM\\device branch of registry: %d\n"), dwErr));
  2288. SetLastError(dwErr);
  2289. goto EndUninstallColorProfile;
  2290. }
  2291. //
  2292. // Check if reference count is zero and remove value from registry
  2293. //
  2294. dwSize = sizeof(REGDATA);
  2295. if ((dwErr = RegQueryValueEx(hkDevice, pFilename, 0, NULL, (PBYTE)&regData,
  2296. &dwSize)) != ERROR_SUCCESS)
  2297. {
  2298. WARNING((__TEXT("Trying to uninstall a profile that is not installed %s: %d\n"), pFilename, dwErr));
  2299. SetLastError(dwErr);
  2300. goto EndUninstallColorProfile;
  2301. }
  2302. if (regData.dwRefCount != 0)
  2303. {
  2304. WARNING((__TEXT("Trying to uninstall profile %s whose refcount is %d\n"),
  2305. pFilename, regData.dwRefCount));
  2306. goto EndUninstallColorProfile;
  2307. }
  2308. if ((dwErr = RegDeleteValue(hkDevice, pFilename)) != ERROR_SUCCESS)
  2309. {
  2310. WARNING((__TEXT("Error deleting profile %s from registry: %d\n"), pFilename, dwErr));
  2311. SetLastError(dwErr);
  2312. goto EndUninstallColorProfile;
  2313. }
  2314. //
  2315. // Remove profile from the registry
  2316. //
  2317. if (bDelete)
  2318. {
  2319. //
  2320. // Delete profile from the color directory
  2321. //
  2322. if (! DeleteFile(szColorPath))
  2323. {
  2324. WARNING((__TEXT("Error deleting profile %s: %d\n"), szColorPath, GetLastError()));
  2325. goto EndUninstallColorProfile;
  2326. }
  2327. }
  2328. rc = TRUE; // Everything went well!
  2329. EndUninstallColorProfile:
  2330. if (hkICM)
  2331. {
  2332. RegCloseKey(hkICM);
  2333. }
  2334. if (hkDevice)
  2335. {
  2336. RegCloseKey(hkDevice);
  2337. }
  2338. return rc;
  2339. }
  2340. /******************************************************************************
  2341. *
  2342. * InternalAssociateColorProfileWithDevice
  2343. *
  2344. * Function:
  2345. * This function associates a color profile on a a given machine with a
  2346. * particular device. It fails if the color profile is not installed on
  2347. * the machine. It increases the usage reference count of the profile.
  2348. *
  2349. * Arguments:
  2350. * pMachineName - name identifying machine. NULL implies local
  2351. * pProfileName - pointer to profile to associate
  2352. * pDeviceName - pointer to device name
  2353. *
  2354. * Returns:
  2355. * TRUE if successful, NULL otherwise
  2356. *
  2357. * Warning:
  2358. * Currently only local association is supported, so pMachineName should
  2359. * be NULL.
  2360. *
  2361. ******************************************************************************/
  2362. BOOL
  2363. InternalAssociateColorProfileWithDevice(
  2364. LPCTSTR pMachineName,
  2365. LPCTSTR pProfileName,
  2366. LPCTSTR pDeviceName
  2367. )
  2368. {
  2369. PROFILEHEADER header; // profile header
  2370. REGDATA regData; // for storing registry data about profile
  2371. HKEY hkICM = NULL; // key to ICM branch in registry
  2372. HKEY hkDevice = NULL; // key to ICM device branch in registry
  2373. DWORD dwSize; // size of registry data
  2374. DWORD dwNewSize; // new size of device registry data
  2375. DWORD dwErr; // error code
  2376. BOOL rc = FALSE; // return code
  2377. PTSTR pFilename; // profile name without path
  2378. PTSTR pProfileList = NULL; // list of associated profiles
  2379. TCHAR szColorPath[MAX_PATH]; // full path name of profile
  2380. TCHAR szClass[5]; // profile class
  2381. BOOL bFirstProfile = FALSE; // First profile to be associated for device
  2382. DWORD dwDeviceClass; // device class
  2383. //
  2384. // Validate parameters
  2385. //
  2386. if (! pProfileName ||
  2387. ! pDeviceName)
  2388. {
  2389. WARNING((__TEXT("Invalid parameter to AssociateColorProfileWithDevice\n")));
  2390. SetLastError(ERROR_INVALID_PARAMETER);
  2391. return FALSE;
  2392. }
  2393. //
  2394. // Only local associations are allowed now
  2395. //
  2396. if (pMachineName != NULL)
  2397. {
  2398. WARNING((__TEXT("Remote profile association attempted, failing...\n")));
  2399. SetLastError(ERROR_NOT_SUPPORTED);
  2400. return FALSE;
  2401. }
  2402. //
  2403. // Get rid of the directory path and get a pointer to the filename
  2404. //
  2405. pFilename = GetFilenameFromPath((PTSTR)pProfileName);
  2406. if (! pFilename)
  2407. {
  2408. WARNING((__TEXT("Could not parse file name from profile path %s\n"), pProfileName));
  2409. SetLastError(ERROR_INVALID_PARAMETER);
  2410. goto EndAssociateProfileWithDevice;
  2411. }
  2412. //
  2413. // Create a fully qualified path name
  2414. //
  2415. dwSize = sizeof(szColorPath);
  2416. if (! InternalGetColorDirectory(NULL, szColorPath, &dwSize))
  2417. {
  2418. WARNING((__TEXT("Could not get color directory\n")));
  2419. goto EndAssociateProfileWithDevice;
  2420. }
  2421. if (szColorPath[lstrlen(szColorPath) - 1] != '\\')
  2422. {
  2423. lstrcat(szColorPath, gszBackslash);
  2424. }
  2425. lstrcat(szColorPath, pFilename);
  2426. //
  2427. // Get the profile class in the form of a string
  2428. //
  2429. if (! GetProfileClassString(szColorPath, szClass, &header))
  2430. {
  2431. WARNING((__TEXT("Installing invalid profile %s\n"), szColorPath));
  2432. SetLastError(ERROR_INVALID_PROFILE);
  2433. goto EndAssociateProfileWithDevice;
  2434. }
  2435. //
  2436. // Open the registry path where profiles are kept
  2437. //
  2438. if (((dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) != ERROR_SUCCESS) ||
  2439. ((dwErr = RegOpenKey(hkICM, szClass, &hkDevice)) != ERROR_SUCCESS))
  2440. {
  2441. WARNING((__TEXT("Cannot open ICM\\device branch of registry: %d\n"), dwErr));
  2442. SetLastError(dwErr);
  2443. goto EndAssociateProfileWithDevice;
  2444. }
  2445. //
  2446. // Check if profile is installed
  2447. //
  2448. dwSize = sizeof(REGDATA);
  2449. if ((dwErr = RegQueryValueEx(hkDevice, pFilename, 0, NULL, (PBYTE)&regData,
  2450. &dwSize)) != ERROR_SUCCESS)
  2451. {
  2452. WARNING((__TEXT("Trying to associate a profile that is not installed %s: %d\n"), pFilename, dwErr));
  2453. SetLastError(dwErr);
  2454. goto EndAssociateProfileWithDevice;
  2455. }
  2456. //
  2457. // Treat CLASS_MONITOR as CLASS_COLORSPACE.
  2458. //
  2459. if ((dwDeviceClass = header.phClass) == CLASS_MONITOR)
  2460. {
  2461. //
  2462. // since CLASS_MONTOR profile can be associated any device class.
  2463. //
  2464. dwDeviceClass = CLASS_COLORSPACE;
  2465. }
  2466. //
  2467. // Read in the list of profiles associated with the device
  2468. //
  2469. dwSize = 0;
  2470. if (! GetDeviceData(pDeviceName, dwDeviceClass, DEVICE_PROFILE_DATA,
  2471. (PVOID *)&pProfileList, &dwSize, TRUE))
  2472. {
  2473. pProfileList = NULL; // no data found
  2474. }
  2475. //
  2476. // If the profile is already associated with the device, return success.
  2477. // Do not check if we didn't get a profile list
  2478. //
  2479. if (pProfileList &&
  2480. IsStringInMultiSz(pProfileList, pFilename) == TRUE)
  2481. {
  2482. rc = TRUE;
  2483. goto EndAssociateProfileWithDevice;
  2484. }
  2485. if (dwSize <= sizeof(TCHAR))
  2486. {
  2487. bFirstProfile = TRUE;
  2488. }
  2489. //
  2490. // Add new profile to the list of profiles, and double NULL
  2491. // terminate the MULTI_SZ string.
  2492. //
  2493. if (dwSize > 0)
  2494. {
  2495. //
  2496. // Use a temporary pointer, so that if MemReAlloc fails, we do
  2497. // not have a memory leak - the original pointer needs to be freed
  2498. //
  2499. PTSTR pTemp;
  2500. dwNewSize = dwSize + (lstrlen(pFilename) + 1) * sizeof(TCHAR);
  2501. pTemp = MemReAlloc(pProfileList, dwNewSize);
  2502. if (! pTemp)
  2503. {
  2504. WARNING((__TEXT("Error reallocating pProfileList\n")));
  2505. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2506. goto EndAssociateProfileWithDevice;
  2507. }
  2508. else
  2509. pProfileList = pTemp;
  2510. }
  2511. else
  2512. {
  2513. //
  2514. // Allocate extra character for double NULL termination. Setting
  2515. // dwSize to 1 accomplishes this and lets the lstrcpy below
  2516. // to work correctly.
  2517. //
  2518. dwSize = sizeof(TCHAR); // extra char for double NULL termination
  2519. dwNewSize = dwSize + (lstrlen(pFilename) + 1) * sizeof(TCHAR);
  2520. pProfileList = MemAlloc(dwNewSize);
  2521. if (! pProfileList)
  2522. {
  2523. WARNING((__TEXT("Error allocating pProfileList\n")));
  2524. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2525. goto EndAssociateProfileWithDevice;
  2526. }
  2527. }
  2528. {
  2529. PTSTR pPtr; // temporary pointer
  2530. pPtr = (PTSTR)((PBYTE)pProfileList + dwSize - sizeof(TCHAR));
  2531. lstrcpy(pPtr, pFilename);
  2532. pPtr = (PTSTR)((PBYTE)pProfileList + dwNewSize - sizeof(TCHAR));
  2533. *pPtr = '\0'; // double NULL terminate
  2534. }
  2535. //
  2536. // Set the device data
  2537. //
  2538. if (! SetDeviceData(pDeviceName, dwDeviceClass, DEVICE_PROFILE_DATA,
  2539. pProfileList, dwNewSize))
  2540. {
  2541. WARNING((__TEXT("Error setting device profile data for %s\n"), pDeviceName));
  2542. goto EndAssociateProfileWithDevice;
  2543. }
  2544. //
  2545. // Increment usage count and set it
  2546. //
  2547. regData.dwRefCount++;
  2548. if ((dwErr = RegSetValueEx(hkDevice, pFilename, 0, REG_BINARY,
  2549. (PBYTE)&regData, sizeof(REGDATA))) != ERROR_SUCCESS)
  2550. {
  2551. ERR((__TEXT("Could not set registry data for profile %s: %d\n"), pFilename, dwErr));
  2552. SetLastError(dwErr);
  2553. goto EndAssociateProfileWithDevice;
  2554. }
  2555. #if !defined(_WIN95_)
  2556. if (bFirstProfile)
  2557. {
  2558. ChangeICMSetting(pMachineName, pDeviceName, ICM_ON);
  2559. }
  2560. #endif
  2561. rc = TRUE; // Everything went well!
  2562. EndAssociateProfileWithDevice:
  2563. if (hkICM)
  2564. {
  2565. RegCloseKey(hkICM);
  2566. }
  2567. if (hkDevice)
  2568. {
  2569. RegCloseKey(hkDevice);
  2570. }
  2571. if (pProfileList)
  2572. {
  2573. MemFree(pProfileList);
  2574. }
  2575. return rc;
  2576. }
  2577. /******************************************************************************
  2578. *
  2579. * InternalDisassociateColorProfileFromDevice
  2580. *
  2581. * Function:
  2582. * This function disassociates a color profile on a a given machine from
  2583. * a particular device. It fails if the color profile is not installed
  2584. * on the machine and associated with the device. It decreases the usage
  2585. * reference count of the profile.
  2586. *
  2587. * Arguments:
  2588. * pMachineName - name identifying machine. NULL implies local
  2589. * pProfileName - pointer to profile to disassociate
  2590. * pDeviceName - pointer to device name
  2591. *
  2592. * Returns:
  2593. * TRUE if successful, NULL otherwise
  2594. *
  2595. * Warning:
  2596. * Currently only local disassociation is supported, so pMachineName
  2597. * should be NULL.
  2598. *
  2599. ******************************************************************************/
  2600. BOOL
  2601. InternalDisassociateColorProfileFromDevice(
  2602. LPCTSTR pMachineName,
  2603. LPCTSTR pProfileName,
  2604. LPCTSTR pDeviceName
  2605. )
  2606. {
  2607. PROFILEHEADER header; // profile header
  2608. REGDATA regData; // for storing registry data about profile
  2609. HKEY hkICM = NULL; // key to ICM branch in registry
  2610. HKEY hkDevice = NULL; // key to ICM device branch in registry
  2611. DWORD dwSize; // size of registry data
  2612. DWORD dwNewSize; // new size of device registry data
  2613. DWORD dwErr; // error code
  2614. BOOL rc = FALSE; // return code
  2615. PTSTR pFilename; // profile name without path
  2616. PTSTR pProfileList = NULL; // list of associated profiles
  2617. TCHAR szColorPath[MAX_PATH]; // full path name of profile
  2618. TCHAR szClass[5]; // profile class
  2619. BOOL bLastProfile = FALSE; // whether last profile is being removed
  2620. DWORD dwDeviceClass; // device class
  2621. //
  2622. // Validate parameters
  2623. //
  2624. if (! pProfileName ||
  2625. ! pDeviceName)
  2626. {
  2627. WARNING((__TEXT("Invalid parameter to DisassociateColorProfileFromDevice\n")));
  2628. SetLastError(ERROR_INVALID_PARAMETER);
  2629. return FALSE;
  2630. }
  2631. //
  2632. // Only local associations are allowed now
  2633. //
  2634. if (pMachineName != NULL)
  2635. {
  2636. WARNING((__TEXT("Remote profile disassociation attempted, failing...\n")));
  2637. SetLastError(ERROR_NOT_SUPPORTED);
  2638. return FALSE;
  2639. }
  2640. //
  2641. // Get rid of the directory path and get a pointer to the filename
  2642. //
  2643. pFilename = GetFilenameFromPath((PTSTR)pProfileName);
  2644. if (! pFilename)
  2645. {
  2646. WARNING((__TEXT("Could not parse file name from profile path %s\n"), pProfileName));
  2647. SetLastError(ERROR_INVALID_PARAMETER);
  2648. goto EndDisassociateProfileWithDevice;
  2649. }
  2650. //
  2651. // Create a fully qualified path name
  2652. //
  2653. dwSize = sizeof(szColorPath);
  2654. if (! InternalGetColorDirectory(NULL, szColorPath, &dwSize))
  2655. {
  2656. WARNING((__TEXT("Could not get color directory\n")));
  2657. goto EndDisassociateProfileWithDevice;
  2658. }
  2659. if (szColorPath[lstrlen(szColorPath) - 1] != '\\')
  2660. {
  2661. lstrcat(szColorPath, gszBackslash);
  2662. }
  2663. lstrcat(szColorPath, pFilename);
  2664. //
  2665. // Get the profile class in the form of a string
  2666. //
  2667. if (! GetProfileClassString(szColorPath, szClass, &header))
  2668. {
  2669. WARNING((__TEXT("Installing invalid profile %s\n"), szColorPath));
  2670. SetLastError(ERROR_INVALID_PROFILE);
  2671. goto EndDisassociateProfileWithDevice;
  2672. }
  2673. //
  2674. // Open the registry path where profiles are kept
  2675. //
  2676. if (((dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) != ERROR_SUCCESS) ||
  2677. ((dwErr = RegOpenKey(hkICM, szClass, &hkDevice)) != ERROR_SUCCESS))
  2678. {
  2679. WARNING((__TEXT("Cannot open ICM\\device branch of registry: %d\n"), dwErr));
  2680. SetLastError(dwErr);
  2681. goto EndDisassociateProfileWithDevice;
  2682. }
  2683. //
  2684. // Check if profile is installed
  2685. //
  2686. dwSize = sizeof(REGDATA);
  2687. if ((dwErr = RegQueryValueEx(hkDevice, pFilename, 0, NULL, (PBYTE)&regData,
  2688. &dwSize)) != ERROR_SUCCESS)
  2689. {
  2690. WARNING((__TEXT("Trying to disassociate a profile that is not installed %s: %d\n"), pFilename, dwErr));
  2691. SetLastError(dwErr);
  2692. goto EndDisassociateProfileWithDevice;
  2693. }
  2694. //
  2695. // Treat CLASS_MONITOR as CLASS_COLORSPACE.
  2696. //
  2697. if ((dwDeviceClass = header.phClass) == CLASS_MONITOR)
  2698. {
  2699. //
  2700. // since CLASS_MONTOR profile can be associated any device class.
  2701. //
  2702. dwDeviceClass = CLASS_COLORSPACE;
  2703. }
  2704. //
  2705. // Read in the list of profiles associated with the device
  2706. //
  2707. dwSize = 0;
  2708. if (! GetDeviceData(pDeviceName, dwDeviceClass, DEVICE_PROFILE_DATA,
  2709. (PVOID *)&pProfileList, &dwSize, TRUE))
  2710. {
  2711. pProfileList = NULL; // no data found
  2712. }
  2713. //
  2714. // If the profile is not associated with the device, return failure
  2715. //
  2716. if (! pProfileList ||
  2717. ! IsStringInMultiSz(pProfileList, pFilename))
  2718. {
  2719. WARNING((__TEXT("Trying to disassociate a profile that is not associated %s\n"), pFilename));
  2720. SetLastError(ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE);
  2721. goto EndDisassociateProfileWithDevice;
  2722. }
  2723. //
  2724. // Remove profile from the list of profiles, and double NULL
  2725. // terminate the MULTI_SZ string.
  2726. //
  2727. dwNewSize = RemoveStringFromMultiSz(pProfileList, pFilename, dwSize);
  2728. //
  2729. // Set the device data
  2730. //
  2731. if (! SetDeviceData(pDeviceName, dwDeviceClass, DEVICE_PROFILE_DATA,
  2732. pProfileList, dwNewSize))
  2733. {
  2734. WARNING((__TEXT("Error setting device profile data for %s\n"), pDeviceName));
  2735. goto EndDisassociateProfileWithDevice;
  2736. }
  2737. if (dwNewSize <= sizeof(TCHAR))
  2738. {
  2739. bLastProfile = TRUE;
  2740. }
  2741. //
  2742. // Decrement usage count and set it
  2743. //
  2744. regData.dwRefCount--;
  2745. if ((dwErr = RegSetValueEx(hkDevice, pFilename, 0, REG_BINARY,
  2746. (PBYTE)&regData, sizeof(REGDATA))) != ERROR_SUCCESS)
  2747. {
  2748. ERR((__TEXT("Could not set registry data for profile %s: %d\n"), pFilename, dwErr));
  2749. SetLastError(dwErr);
  2750. goto EndDisassociateProfileWithDevice;
  2751. }
  2752. #if !defined(_WIN95_)
  2753. if (bLastProfile)
  2754. {
  2755. ChangeICMSetting(pMachineName, pDeviceName, ICM_OFF);
  2756. }
  2757. #endif
  2758. rc = TRUE; // Everything went well!
  2759. EndDisassociateProfileWithDevice:
  2760. if (hkICM)
  2761. {
  2762. RegCloseKey(hkICM);
  2763. }
  2764. if (hkDevice)
  2765. {
  2766. RegCloseKey(hkDevice);
  2767. }
  2768. if (pProfileList)
  2769. {
  2770. MemFree(pProfileList);
  2771. }
  2772. return rc;
  2773. }
  2774. /******************************************************************************
  2775. *
  2776. * InternalEnumColorProfiles
  2777. *
  2778. * Function:
  2779. * These functions enumerates color profiles satisfying the given
  2780. * enumeration criteria. It searches among all installed profiles, and
  2781. * on return fills out a buffer with a series of NULL terminated profile
  2782. * filenames double NULL terminated at the end.
  2783. *
  2784. * Arguments:
  2785. * pMachineName - name identifying machine on which the enumeration
  2786. * needs to be done
  2787. * pEnumRecord - pointer to enumeration criteria
  2788. * pBuffer - pointer to buffer to receive result, can be NULL
  2789. * pdwSize - pointer to buffer size. On return it is actual number
  2790. * of bytes copied/needed.
  2791. * pnProfiles - pointer to DWORD. On return, it is number of profiles
  2792. * copied to pBuffer.
  2793. *
  2794. * Returns:
  2795. * TRUE if successful, NULL otherwise
  2796. *
  2797. * Warning:
  2798. * Currently only local enumeration is supported, so pMachineName should
  2799. * be NULL.
  2800. *
  2801. ******************************************************************************/
  2802. BOOL
  2803. InternalEnumColorProfiles(
  2804. LPCTSTR pMachineName,
  2805. PENUMTYPE pEnumRecord,
  2806. PBYTE pBuffer,
  2807. PDWORD pdwSize,
  2808. PDWORD pnProfiles
  2809. )
  2810. {
  2811. REGDATA regData; // for storing registry data about profile
  2812. HKEY hkICM = NULL; // key to ICM branch in registry
  2813. HKEY hkDevice = NULL; // key to ICM device branch in registry
  2814. PTSTR pProfileList = NULL; // list of associated profiles
  2815. PTSTR pTempProfileList; // temporary copy of profile list
  2816. DWORD dwSize; // size of profile value
  2817. DWORD dwDataSize; // size of profile data
  2818. DWORD dwInputSize; // incoming size of buffer
  2819. DWORD i, j; // counter variables
  2820. DWORD dwErr; // error code
  2821. BOOL rc = FALSE; // return code
  2822. TCHAR szFullPath[MAX_PATH]; // full path of profile to open
  2823. PTSTR pProfile; // pointer to profile name in full path
  2824. DWORD dwLen; // length of color directory string
  2825. DWORD bSkipMatch; // true for skipping exact profile matching
  2826. MATCHTYPE match; // Type of profile match
  2827. PBYTE pBufferStart; // Start of user given buffer
  2828. DWORD dwSizeOfStruct; // size of ENUMTYPE structure
  2829. DWORD dwVersion; // ENUMTYPE structure version
  2830. //
  2831. // Validate parameters
  2832. //
  2833. if (! pdwSize ||
  2834. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  2835. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)) ||
  2836. (pnProfiles && IsBadWritePtr(pnProfiles, sizeof(DWORD))) ||
  2837. ! pEnumRecord ||
  2838. IsBadReadPtr(pEnumRecord, sizeof(DWORD)*3)) // probe until ENUMTYPE.dwFields
  2839. {
  2840. ParameterError_InternalEnumColorProfiles:
  2841. WARNING((__TEXT("Invalid parameter to EnumColorProfiles\n")));
  2842. SetLastError(ERROR_INVALID_PARAMETER);
  2843. return FALSE;
  2844. }
  2845. //
  2846. // Check structure size based on its version.
  2847. //
  2848. dwSizeOfStruct = pEnumRecord->dwSize;
  2849. dwVersion = pEnumRecord->dwVersion;
  2850. if (dwVersion >= ENUM_TYPE_VERSION)
  2851. {
  2852. if (dwSizeOfStruct < sizeof(ENUMTYPE))
  2853. goto ParameterError_InternalEnumColorProfiles;
  2854. }
  2855. else if (dwVersion == 0x0200)
  2856. {
  2857. if (dwSizeOfStruct < sizeof(ENUMTYPE)-sizeof(DWORD))
  2858. goto ParameterError_InternalEnumColorProfiles;
  2859. //
  2860. // Version 2 should not have ET_DEVICECLASS bit
  2861. //
  2862. if (pEnumRecord->dwFields & ET_DEVICECLASS)
  2863. goto ParameterError_InternalEnumColorProfiles;
  2864. WARNING((__TEXT("Old version ENUMTYPE to InternalEnumColorProfiles\n")));
  2865. }
  2866. else
  2867. {
  2868. goto ParameterError_InternalEnumColorProfiles;
  2869. }
  2870. if (IsBadReadPtr(pEnumRecord, dwSizeOfStruct))
  2871. {
  2872. goto ParameterError_InternalEnumColorProfiles;
  2873. }
  2874. //
  2875. // Only local enumerations are allowed now
  2876. //
  2877. if (pMachineName != NULL)
  2878. {
  2879. WARNING((__TEXT("Remote profile enumeration attempted, failing...\n")));
  2880. SetLastError(ERROR_NOT_SUPPORTED);
  2881. return FALSE;
  2882. }
  2883. dwInputSize = *pdwSize;
  2884. //
  2885. // Get color directory
  2886. //
  2887. dwLen = sizeof(szFullPath);
  2888. if (! InternalGetColorDirectory(NULL, szFullPath, &dwLen))
  2889. {
  2890. WARNING((__TEXT("Error getting color directory\n")));
  2891. return FALSE;
  2892. }
  2893. if (szFullPath[lstrlen(szFullPath) - 1] != '\\')
  2894. {
  2895. lstrcat(szFullPath, gszBackslash);
  2896. }
  2897. pProfile = &szFullPath[lstrlen(szFullPath)];
  2898. dwLen = lstrlen(szFullPath) * sizeof(TCHAR);
  2899. //
  2900. // Initialize return parameters
  2901. //
  2902. *pdwSize = 0;
  2903. if (pnProfiles)
  2904. *pnProfiles = 0;
  2905. if (pBuffer && dwInputSize >= sizeof(TCHAR))
  2906. {
  2907. *((PTSTR)pBuffer) = '\0';
  2908. }
  2909. //
  2910. // Check if we are looking for the profiles of a particular device or
  2911. // not because we enumerate them from different places.
  2912. //
  2913. if (pEnumRecord->dwFields & ET_DEVICENAME)
  2914. {
  2915. DWORD *pbSkipMatch = &bSkipMatch;
  2916. DWORD dwDeviceClass;
  2917. if (! pEnumRecord->pDeviceName)
  2918. {
  2919. WARNING((__TEXT("Invalid parameter to EnumColorProfiles\n")));
  2920. SetLastError(ERROR_INVALID_PARAMETER);
  2921. goto EndEnumerateColorProfiles;
  2922. }
  2923. //
  2924. // Get list of profiles associated with the device. If we don't
  2925. // know what device it is, specify ColorSpace, which tries all three
  2926. //
  2927. if (pEnumRecord->dwFields & ET_DEVICECLASS)
  2928. {
  2929. dwDeviceClass = pEnumRecord->dwDeviceClass;
  2930. }
  2931. else
  2932. {
  2933. dwDeviceClass = CLASS_COLORSPACE;
  2934. }
  2935. //
  2936. // Get the device configuration whether we do exact matching or not.
  2937. //
  2938. dwSize = sizeof(DWORD);
  2939. if (! GetDeviceData(pEnumRecord->pDeviceName, dwDeviceClass, DEVICE_PROFILE_ENUMMODE,
  2940. (PVOID *)&pbSkipMatch, &dwSize, FALSE))
  2941. {
  2942. bSkipMatch = FALSE;
  2943. }
  2944. //
  2945. // Get the profile data.
  2946. //
  2947. dwSize = 0;
  2948. if (! GetDeviceData(pEnumRecord->pDeviceName, dwDeviceClass, DEVICE_PROFILE_DATA,
  2949. (PVOID *)&pProfileList, &dwSize, TRUE))
  2950. {
  2951. pProfileList = NULL; // no data found
  2952. }
  2953. if(! pProfileList)
  2954. {
  2955. //
  2956. // No profiles associated with this device
  2957. //
  2958. rc = TRUE;
  2959. if (pBuffer && dwInputSize >= sizeof(TCHAR)*2)
  2960. {
  2961. *((PTSTR)pBuffer + 1) = '\0';
  2962. }
  2963. goto EndEnumerateColorProfiles;
  2964. }
  2965. //
  2966. // Run through the list of profiles and check each one to see if it
  2967. // matches the enumeration criteria. If it does, and the buffer is
  2968. // large enough, copy it to the buffer, and increment the byte count
  2969. // and number of profiles enumerated.
  2970. //
  2971. pBufferStart = pBuffer;
  2972. pTempProfileList = pProfileList;
  2973. while (*pTempProfileList)
  2974. {
  2975. lstrcpy(pProfile, pTempProfileList);
  2976. if (bSkipMatch)
  2977. {
  2978. match = EXACT_MATCH;
  2979. }
  2980. else
  2981. {
  2982. match = DoesProfileMatchEnumRecord(szFullPath, pEnumRecord);
  2983. }
  2984. if (match != NOMATCH)
  2985. {
  2986. *pdwSize += (lstrlen(pTempProfileList) + 1) * sizeof(TCHAR);
  2987. //
  2988. // Check strictly less than because you need one more for
  2989. // the final NULL termination
  2990. //
  2991. if (pBuffer && (*pdwSize < dwInputSize))
  2992. {
  2993. if (match == MATCH)
  2994. {
  2995. lstrcpy((PTSTR)pBuffer, pTempProfileList);
  2996. }
  2997. else
  2998. {
  2999. //
  3000. // Exact match, add to beginning of buffer
  3001. //
  3002. InsertInBuffer(pBufferStart, pBuffer, pTempProfileList);
  3003. }
  3004. pBuffer += (lstrlen(pTempProfileList) + 1) * sizeof(TCHAR);
  3005. }
  3006. if (pnProfiles)
  3007. (*pnProfiles)++;
  3008. }
  3009. pTempProfileList += lstrlen(pTempProfileList) + 1;
  3010. }
  3011. }
  3012. else
  3013. {
  3014. DWORD dwNumClasses;
  3015. PTSTR *ppszEnumClasses;
  3016. PTSTR pszEnumClassArray[2];
  3017. //
  3018. // We are not looking at a particular device, so enumerate
  3019. // profiles from the registry
  3020. //
  3021. if (pEnumRecord->dwFields & ET_DEVICECLASS)
  3022. {
  3023. //
  3024. // If device class is specified, enumrate the specified device class and color
  3025. // space class which can be associated to any device.
  3026. //
  3027. pszEnumClassArray[0] = ConvertClassIdToClassString(pEnumRecord->dwDeviceClass);
  3028. pszEnumClassArray[1] = ConvertClassIdToClassString(CLASS_COLORSPACE);
  3029. if (!pszEnumClassArray[0] || !pszEnumClassArray[1])
  3030. {
  3031. WARNING((__TEXT("Invalid DeviceClass to EnumColorProfiles\n")));
  3032. SetLastError(ERROR_INVALID_PARAMETER);
  3033. goto EndEnumerateColorProfiles;
  3034. }
  3035. ppszEnumClasses = pszEnumClassArray;
  3036. dwNumClasses = 2;
  3037. }
  3038. else
  3039. {
  3040. ppszEnumClasses = gpszClasses;
  3041. dwNumClasses = sizeof(gpszClasses)/sizeof(PTSTR);
  3042. }
  3043. //
  3044. // Open the registry path where profiles are kept (and create it if not exist)
  3045. //
  3046. if ((dwErr = RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) != ERROR_SUCCESS)
  3047. {
  3048. WARNING((__TEXT("Cannot open ICM branch of registry: %d\n"), dwErr));
  3049. SetLastError(dwErr);
  3050. goto EndEnumerateColorProfiles;
  3051. }
  3052. pBufferStart = pBuffer;
  3053. for (i=0; i<dwNumClasses; i++,ppszEnumClasses++)
  3054. {
  3055. DWORD nValues; // number of name-values in key
  3056. if (RegOpenKey(hkICM, *ppszEnumClasses, &hkDevice) != ERROR_SUCCESS)
  3057. {
  3058. continue; // go to next key
  3059. }
  3060. if ((dwErr = RegQueryInfoKey(hkDevice, NULL, NULL, 0, NULL, NULL, NULL,
  3061. &nValues, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS)
  3062. {
  3063. WARNING((__TEXT("Cannot count values in device branch of registry: %d\n"), dwErr));
  3064. RegCloseKey(hkDevice);
  3065. SetLastError(dwErr);
  3066. goto EndEnumerateColorProfiles;
  3067. }
  3068. //
  3069. // Go through the list of profiles and return everything that
  3070. // satisfies the enumeration criteria
  3071. //
  3072. for (j=0; j<nValues; j++)
  3073. {
  3074. dwSize = sizeof(szFullPath) - dwLen;
  3075. dwDataSize = sizeof(REGDATA);
  3076. if (RegEnumValue(hkDevice, j, pProfile, &dwSize, 0,
  3077. NULL, (PBYTE)&regData, &dwDataSize) == ERROR_SUCCESS)
  3078. {
  3079. match = DoesProfileMatchEnumRecord(szFullPath, pEnumRecord);
  3080. if (match != NOMATCH)
  3081. {
  3082. *pdwSize += (lstrlen(pProfile) + 1) * sizeof(TCHAR);
  3083. if (pBuffer && (*pdwSize < dwInputSize))
  3084. {
  3085. if (match == MATCH)
  3086. {
  3087. lstrcpy((PTSTR)pBuffer, pProfile);
  3088. }
  3089. else
  3090. {
  3091. //
  3092. // Exact match, add to beginning of buffer
  3093. //
  3094. InsertInBuffer(pBufferStart, pBuffer, pProfile);
  3095. }
  3096. pBuffer += (lstrlen(pProfile) + 1) * sizeof(TCHAR);
  3097. }
  3098. if (pnProfiles)
  3099. (*pnProfiles)++;
  3100. }
  3101. }
  3102. }
  3103. RegCloseKey(hkDevice);
  3104. }
  3105. }
  3106. *pdwSize += sizeof(TCHAR); // extra NULL termination
  3107. if (pBuffer && *pdwSize <= dwInputSize)
  3108. {
  3109. *((PTSTR)pBuffer) = '\0';
  3110. rc = TRUE;
  3111. }
  3112. else
  3113. {
  3114. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  3115. }
  3116. EndEnumerateColorProfiles:
  3117. if (hkICM)
  3118. {
  3119. RegCloseKey(hkICM);
  3120. }
  3121. if (pProfileList)
  3122. {
  3123. MemFree(pProfileList);
  3124. }
  3125. return rc;
  3126. }
  3127. VOID
  3128. InsertInBuffer(
  3129. PBYTE pStart,
  3130. PBYTE pEnd,
  3131. PTSTR pString
  3132. )
  3133. {
  3134. DWORD cnt = (lstrlen(pString) + 1) * sizeof(TCHAR);
  3135. MyCopyMemory(pStart+cnt, pStart, (DWORD)(pEnd - pStart));
  3136. lstrcpy((PTSTR)pStart, pString);
  3137. return;
  3138. }
  3139. /******************************************************************************
  3140. *
  3141. * InternalSetSCSProfile
  3142. *
  3143. * Function:
  3144. * These functions regsiters the given profile for the standard color
  3145. * space specified. This will register it in the OS and can be queried
  3146. * using GetStandardColorSpaceProfile.
  3147. *
  3148. * Arguments:
  3149. * pMachineName - name identifying machine on which the standard color
  3150. * space profile should be registered
  3151. * dwSCS - ID for the standard color space
  3152. * pProfileName - pointer to profile filename
  3153. *
  3154. * Returns:
  3155. * TRUE if successful, NULL otherwise
  3156. *
  3157. * Warning:
  3158. * Currently only local registration is supported, so pMachineName should
  3159. * be NULL.
  3160. *
  3161. ******************************************************************************/
  3162. BOOL
  3163. InternalSetSCSProfile(
  3164. LPCTSTR pMachineName,
  3165. DWORD dwSCS,
  3166. LPCTSTR pProfileName
  3167. )
  3168. {
  3169. HKEY hkICM = NULL; // key to ICM branch in registry
  3170. HKEY hkRegProf = NULL; // key to registered color spaces branch
  3171. DWORD dwSize; // size of registry data
  3172. DWORD dwErr; // error code
  3173. BOOL rc = FALSE; // return code
  3174. TCHAR szProfileID[5]; // profile class
  3175. //
  3176. // Validate parameters
  3177. //
  3178. if (!pProfileName)
  3179. {
  3180. WARNING((__TEXT("Invalid parameter to SetStandardColorSpaceProfile\n")));
  3181. SetLastError(ERROR_INVALID_PARAMETER);
  3182. return FALSE;
  3183. }
  3184. //
  3185. // Only local registration is allowed now
  3186. //
  3187. if (pMachineName != NULL)
  3188. {
  3189. WARNING((__TEXT("Remote SCS profile registration attempted, failing...\n")));
  3190. SetLastError(ERROR_NOT_SUPPORTED);
  3191. return FALSE;
  3192. }
  3193. dwSize = (lstrlen(pProfileName) + 1) * sizeof(TCHAR);
  3194. //
  3195. // Open the registry location where this is kept
  3196. //
  3197. if (((dwErr = RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) == ERROR_SUCCESS) &&
  3198. ((dwErr = RegCreateKey(hkICM, gszRegisteredProfiles, &hkRegProf))== ERROR_SUCCESS))
  3199. {
  3200. ConvertDwordToString(dwSCS, szProfileID);
  3201. if ((dwErr = RegSetValueEx(hkRegProf, szProfileID, 0, REG_SZ,
  3202. (PBYTE)pProfileName, dwSize)) == ERROR_SUCCESS)
  3203. {
  3204. rc = TRUE;
  3205. }
  3206. }
  3207. if (hkICM)
  3208. {
  3209. RegCloseKey(hkICM);
  3210. }
  3211. if (hkRegProf)
  3212. {
  3213. RegCloseKey(hkRegProf);
  3214. }
  3215. if (!rc)
  3216. {
  3217. WARNING((__TEXT("InternalSetSCSProfile failed: %d\n"), dwErr));
  3218. SetLastError(dwErr);
  3219. }
  3220. return rc;
  3221. }
  3222. /******************************************************************************
  3223. *
  3224. * InternalGetSCSProfile
  3225. *
  3226. * Function:
  3227. * These functions retrieves the profile regsitered for the standard color
  3228. * space specified.
  3229. *
  3230. * Arguments:
  3231. * pMachineName - name identifying machine on which the standard color
  3232. * space profile should be queried
  3233. * dwSCS - ID for the standard color space
  3234. * pBuffer - pointer to buffer to receive profile filename
  3235. * pdwSize - pointer to DWORD specifying size of buffer. On return
  3236. * it has size needed/used
  3237. *
  3238. * Returns:
  3239. * TRUE if successful, NULL otherwise
  3240. *
  3241. * Warning:
  3242. * Currently only local query is supported, so pMachineName should
  3243. * be NULL.
  3244. *
  3245. ******************************************************************************/
  3246. BOOL
  3247. InternalGetSCSProfile(
  3248. LPCTSTR pMachineName,
  3249. DWORD dwSCS,
  3250. PTSTR pBuffer,
  3251. PDWORD pdwSize
  3252. )
  3253. {
  3254. HKEY hkICM = NULL; // key to ICM branch in registry
  3255. HKEY hkRegProf = NULL; // key to registered color spaces branch
  3256. DWORD dwErr; // error code
  3257. DWORD dwSize;
  3258. BOOL rc = FALSE; // return code
  3259. TCHAR szProfileID[5]; // profile class
  3260. //
  3261. // Validate parameters
  3262. //
  3263. if (! pdwSize ||
  3264. IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
  3265. (pBuffer && IsBadWritePtr(pBuffer, *pdwSize)))
  3266. {
  3267. WARNING((__TEXT("Invalid parameter to GetStandardColorSpaceProfile\n")));
  3268. SetLastError(ERROR_INVALID_PARAMETER);
  3269. return FALSE;
  3270. }
  3271. //
  3272. // Only local query is allowed now
  3273. //
  3274. if (pMachineName != NULL)
  3275. {
  3276. WARNING((__TEXT("Remote SCS profile query attempted, failing...\n")));
  3277. SetLastError(ERROR_NOT_SUPPORTED);
  3278. return FALSE;
  3279. }
  3280. dwSize = *pdwSize;
  3281. //
  3282. // Look in the registry for a profile registered for this color space ID
  3283. //
  3284. if (((dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM)) == ERROR_SUCCESS) &&
  3285. ((dwErr = RegOpenKey(hkICM, gszRegisteredProfiles, &hkRegProf)) == ERROR_SUCCESS))
  3286. {
  3287. ConvertDwordToString(dwSCS, szProfileID);
  3288. if ((dwErr = RegQueryValueEx(hkRegProf, szProfileID, NULL, NULL,
  3289. (PBYTE)pBuffer, pdwSize)) == ERROR_SUCCESS)
  3290. {
  3291. rc = TRUE;
  3292. }
  3293. }
  3294. if (hkICM)
  3295. {
  3296. RegCloseKey(hkICM);
  3297. }
  3298. if (hkRegProf)
  3299. {
  3300. RegCloseKey(hkRegProf);
  3301. }
  3302. if (!rc && (dwSCS == LCS_sRGB || dwSCS == LCS_WINDOWS_COLOR_SPACE))
  3303. {
  3304. *pdwSize = dwSize;
  3305. rc = GetColorDirectory(NULL, pBuffer, pdwSize);
  3306. if (!rc && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  3307. {
  3308. return FALSE;
  3309. }
  3310. *pdwSize += (lstrlen(gszBackslash) + lstrlen(gszsRGBProfile)) * sizeof(TCHAR);
  3311. if (*pdwSize <= dwSize && pBuffer)
  3312. {
  3313. lstrcat(pBuffer, gszBackslash);
  3314. lstrcat(pBuffer, gszsRGBProfile);
  3315. rc = TRUE;
  3316. }
  3317. else
  3318. {
  3319. dwErr = ERROR_INSUFFICIENT_BUFFER;
  3320. }
  3321. }
  3322. if (!rc)
  3323. {
  3324. WARNING((__TEXT("InternalGetSCSProfile failed: %d\n"), dwErr));
  3325. SetLastError(dwErr);
  3326. }
  3327. //
  3328. // If pBuffer is NULL, RegQueryValueEx return TRUE. Our API should return FALSE
  3329. // in this case. Handle this.
  3330. //
  3331. if (pBuffer == NULL && rc)
  3332. {
  3333. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  3334. rc = FALSE;
  3335. }
  3336. return rc;
  3337. }
  3338. /******************************************************************************
  3339. *
  3340. * ConvertDwordToString
  3341. *
  3342. * Function:
  3343. * This function converts a DWORD into a string. The string passed in
  3344. * is large enough. It converts to Unicode or Ansi depending on how
  3345. * this is compiled.
  3346. *
  3347. * Arguments:
  3348. * dword - DWORD to convert
  3349. * pString - pointer to buffer to hold the result
  3350. *
  3351. * Returns:
  3352. * Nothing
  3353. *
  3354. ******************************************************************************/
  3355. VOID
  3356. ConvertDwordToString(
  3357. DWORD dword,
  3358. PTSTR pString
  3359. )
  3360. {
  3361. int i; // counter
  3362. for (i=0; i<4; i++)
  3363. {
  3364. pString[i] = (TCHAR)(((char*)&dword)[3-i]);
  3365. }
  3366. pString[4] = '\0';
  3367. return;
  3368. }
  3369. /******************************************************************************
  3370. *
  3371. * ConvertClassIdToClassString
  3372. *
  3373. * Function:
  3374. * This function converts a DWORD Device Class Id into a its device string
  3375. *
  3376. * Arguments:
  3377. * dwClassId - Device class id.
  3378. *
  3379. * Returns:
  3380. * pointer to a string
  3381. *
  3382. ******************************************************************************/
  3383. PTSTR
  3384. ConvertClassIdToClassString(
  3385. DWORD dwClassId
  3386. )
  3387. {
  3388. switch (dwClassId)
  3389. {
  3390. case CLASS_MONITOR:
  3391. return (gpszClasses[INDEX_CLASS_MONITOR]);
  3392. case CLASS_PRINTER:
  3393. return (gpszClasses[INDEX_CLASS_PRINTER]);
  3394. case CLASS_SCANNER:
  3395. return (gpszClasses[INDEX_CLASS_SCANNER]);
  3396. case CLASS_COLORSPACE:
  3397. return (gpszClasses[INDEX_CLASS_COLORSPACE]);
  3398. default:
  3399. return NULL;
  3400. }
  3401. }
  3402. /******************************************************************************
  3403. *
  3404. * GetProfileClassString
  3405. *
  3406. * Function:
  3407. * This function returns the profile class from the header as a string.
  3408. * It also validates the profile.
  3409. *
  3410. * Arguments:
  3411. * pProfileName - name of profile
  3412. * pClass - pointer to buffer to hold the profile class string
  3413. * pHeader - if this is non NULL, it returns the header here
  3414. *
  3415. * Returns:
  3416. * TRUE on success, FALSE otherwise
  3417. *
  3418. ******************************************************************************/
  3419. BOOL
  3420. GetProfileClassString(
  3421. LPCTSTR pProfileName,
  3422. PTSTR pClass,
  3423. PPROFILEHEADER pHeader
  3424. )
  3425. {
  3426. PROFILEHEADER header; // color profile header
  3427. PROFILE prof; // profile object for opening profile
  3428. HPROFILE hProfile = NULL; // handle to opened profile
  3429. BOOL bValidProfile = FALSE; // validation of the profile
  3430. BOOL rc = FALSE; // return code
  3431. //
  3432. // Open a handle to the profile
  3433. //
  3434. prof.dwType = PROFILE_FILENAME;
  3435. prof.pProfileData = (PVOID)pProfileName;
  3436. prof.cbDataSize = (lstrlen(pProfileName) + 1) * sizeof(TCHAR);
  3437. hProfile = OpenColorProfile(&prof, PROFILE_READ, FILE_SHARE_READ,
  3438. OPEN_EXISTING);
  3439. if (! hProfile)
  3440. {
  3441. WARNING((__TEXT("Error opening profile %s\n"), pProfileName));
  3442. goto EndGetProfileClassString;
  3443. }
  3444. //
  3445. // Check the validation of the profile.
  3446. //
  3447. if (! IsColorProfileValid(hProfile,&bValidProfile) || ! bValidProfile)
  3448. {
  3449. WARNING((__TEXT("Error invalid profile %s\n"), pProfileName));
  3450. goto EndGetProfileClassString;
  3451. }
  3452. //
  3453. // Get the profile class
  3454. //
  3455. if (! pHeader)
  3456. {
  3457. pHeader = &header;
  3458. }
  3459. if (! GetColorProfileHeader(hProfile, pHeader))
  3460. {
  3461. ERR((__TEXT("Error getting color profile header for %s\n"), pProfileName));
  3462. goto EndGetProfileClassString;
  3463. }
  3464. ConvertDwordToString(pHeader->phClass, pClass);
  3465. rc= TRUE;
  3466. EndGetProfileClassString:
  3467. if (hProfile)
  3468. {
  3469. CloseColorProfile(hProfile);
  3470. }
  3471. return rc;
  3472. }
  3473. /******************************************************************************
  3474. *
  3475. * GetFilenameFromPath
  3476. *
  3477. * Function:
  3478. * This function takes a fully qualified pathname and returns a pointer
  3479. * to the filename part alone
  3480. *
  3481. * Arguments:
  3482. * pPathName - pointer to pathname
  3483. *
  3484. * Returns:
  3485. * Pointer to filename on success, NULL otherwise
  3486. *
  3487. ******************************************************************************/
  3488. PTSTR
  3489. GetFilenameFromPath(
  3490. PTSTR pPathName
  3491. )
  3492. {
  3493. DWORD dwLen; // length of pathname
  3494. PTSTR pPathNameStart = pPathName;
  3495. dwLen = lstrlen(pPathName);
  3496. if (dwLen == 0)
  3497. {
  3498. return NULL;
  3499. }
  3500. //
  3501. // Go to the end of the pathname, and start going backwards till
  3502. // you reach the beginning or a backslash
  3503. //
  3504. pPathName += dwLen;
  3505. //
  3506. // Currently 'pPathName' points null-terminate character, so move
  3507. // the pointer to last character.
  3508. //
  3509. do
  3510. {
  3511. pPathName = CharPrev(pPathNameStart,pPathName);
  3512. if (*pPathName == TEXT('\\'))
  3513. {
  3514. pPathName = CharNext(pPathName);
  3515. break;
  3516. }
  3517. //
  3518. // Loop until fist
  3519. //
  3520. } while (pPathNameStart < pPathName);
  3521. //
  3522. // if *pPathName is zero, then we had a string that ends in a backslash
  3523. //
  3524. return *pPathName ? pPathName : NULL;
  3525. }
  3526. /******************************************************************************
  3527. *
  3528. * GetDeviceData
  3529. *
  3530. * Function:
  3531. * This function is a wrapper for IGetDeviceData. For devices like monitor,
  3532. * printer & scanner it calls the internal function. If we are asked
  3533. * to get the device data for a "colorspace device", we try monitor, printer
  3534. * and scanner till one succeeds or they all fail. This is done so that we
  3535. * we can associate sRGB like profiles with any device.
  3536. *
  3537. * Arguments:
  3538. * pDeviceName - pointer to name of the device
  3539. * dwClass - device type like monitor, printer etc.
  3540. * ppDeviceData - pointer to pointer to buffer to receive data
  3541. * pdwSize - pointer to size of buffer. On return it is size of
  3542. * data returned/size needed.
  3543. * bAllocate - If TRUE, allocate memory for data
  3544. *
  3545. * Returns:
  3546. * TRUE if successful, FALSE otherwise
  3547. *
  3548. ******************************************************************************/
  3549. BOOL
  3550. GetDeviceData(
  3551. LPCTSTR pDeviceName,
  3552. DWORD dwClass,
  3553. DWORD dwDataType,
  3554. PVOID *ppDeviceData,
  3555. PDWORD pdwSize,
  3556. BOOL bAllocate
  3557. )
  3558. {
  3559. BOOL rc = FALSE;
  3560. if (dwClass == CLASS_MONITOR ||
  3561. dwClass == CLASS_PRINTER ||
  3562. dwClass == CLASS_SCANNER)
  3563. {
  3564. rc = IGetDeviceData(pDeviceName, dwClass, dwDataType, ppDeviceData, pdwSize, bAllocate);
  3565. }
  3566. else if (dwClass == CLASS_COLORSPACE)
  3567. {
  3568. rc = IGetDeviceData(pDeviceName, CLASS_MONITOR, dwDataType, ppDeviceData, pdwSize, bAllocate) ||
  3569. IGetDeviceData(pDeviceName, CLASS_PRINTER, dwDataType, ppDeviceData, pdwSize, bAllocate) ||
  3570. IGetDeviceData(pDeviceName, CLASS_SCANNER, dwDataType, ppDeviceData, pdwSize, bAllocate);
  3571. }
  3572. return rc;
  3573. }
  3574. /******************************************************************************
  3575. *
  3576. * IGetDeviceData
  3577. *
  3578. * Function:
  3579. * This function retrieves ICM data stored with the different devices.
  3580. *
  3581. * Arguments:
  3582. * pDeviceName - pointer to name of the device
  3583. * dwClass - device type like monitor, printer etc.
  3584. * ppDeviceData - pointer to pointer to buffer to receive data
  3585. * pdwSize - pointer to size of buffer. On return it is size of
  3586. * data returned/size needed.
  3587. * bAllocate - If TRUE, allocate memory for data
  3588. *
  3589. * Returns:
  3590. * TRUE if successful, FALSE otherwise
  3591. *
  3592. ******************************************************************************/
  3593. BOOL
  3594. IGetDeviceData(
  3595. LPCTSTR pDeviceName,
  3596. DWORD dwClass,
  3597. DWORD dwDataType,
  3598. PVOID *ppDeviceData,
  3599. PDWORD pdwSize,
  3600. BOOL bAllocate
  3601. )
  3602. {
  3603. PFNOPENDEVICE fnOpenDevice;
  3604. PFNCLOSEDEVICE fnCloseDevice;
  3605. PFNGETDEVICEDATA fnGetData;
  3606. HANDLE hDevice;
  3607. DWORD dwSize;
  3608. LPTSTR pDataKey;
  3609. LPTSTR pDataValue;
  3610. BOOL rc = FALSE;
  3611. //
  3612. // Set up function pointers so we can write common code
  3613. //
  3614. switch (dwClass)
  3615. {
  3616. case CLASS_PRINTER:
  3617. fnOpenDevice = (PFNOPENDEVICE)OpenPrtr;
  3618. fnCloseDevice = (PFNCLOSEDEVICE)ClosePrtr;
  3619. fnGetData = (PFNGETDEVICEDATA)GetPrtrData;
  3620. break;
  3621. case CLASS_MONITOR:
  3622. fnOpenDevice = (PFNOPENDEVICE)OpenMonitor;
  3623. fnCloseDevice = (PFNCLOSEDEVICE)CloseMonitor;
  3624. fnGetData = (PFNGETDEVICEDATA)GetMonitorData;
  3625. break;
  3626. case CLASS_SCANNER:
  3627. fnOpenDevice = (PFNOPENDEVICE)OpenScanner;
  3628. fnCloseDevice = (PFNCLOSEDEVICE)CloseScanner;
  3629. fnGetData = (PFNGETDEVICEDATA)GetScannerData;
  3630. break;
  3631. default:
  3632. return FALSE;
  3633. }
  3634. //
  3635. // Set up registry keywords.
  3636. //
  3637. switch (dwDataType)
  3638. {
  3639. case DEVICE_PROFILE_DATA:
  3640. pDataKey = gszICMProfileListKey;
  3641. //
  3642. // The way to store printer profile is different than others... trim it.
  3643. //
  3644. if (dwClass == CLASS_PRINTER)
  3645. {
  3646. pDataValue = gszFiles;
  3647. }
  3648. else
  3649. {
  3650. pDataValue = gszICMProfileListValue;
  3651. }
  3652. break;
  3653. case DEVICE_PROFILE_ENUMMODE:
  3654. pDataKey = gszICMDeviceDataKey;
  3655. pDataValue = gszICMProfileEnumMode;
  3656. break;
  3657. default:
  3658. return FALSE;
  3659. }
  3660. //
  3661. // Open the device and get a handle to it
  3662. //
  3663. if (! (*fnOpenDevice)((PTSTR)pDeviceName, &hDevice, NULL))
  3664. {
  3665. return FALSE;
  3666. }
  3667. if (bAllocate || (ppDeviceData == NULL))
  3668. {
  3669. DWORD retcode;
  3670. //
  3671. // We need to allocate memory. Find out how much we need, and
  3672. // allocate it.
  3673. //
  3674. dwSize = 0;
  3675. retcode = (*fnGetData)(hDevice, pDataKey, pDataValue, NULL, NULL, 0, &dwSize);
  3676. if ((retcode != ERROR_SUCCESS) && // Win 95 returns this
  3677. (retcode != ERROR_MORE_DATA)) // NT returns this
  3678. {
  3679. VERBOSE((__TEXT("GetDeviceData failed for %s\n"), pDeviceName));
  3680. goto EndGetDeviceData;
  3681. }
  3682. *pdwSize = dwSize;
  3683. if (ppDeviceData == NULL)
  3684. {
  3685. //
  3686. // Caller wants to know the data size.
  3687. //
  3688. rc = TRUE;
  3689. goto EndGetDeviceData;
  3690. }
  3691. else
  3692. {
  3693. //
  3694. // Allocate buffer.
  3695. //
  3696. *ppDeviceData = MemAlloc(dwSize);
  3697. if (! *ppDeviceData)
  3698. {
  3699. WARNING((__TEXT("Error allocating memory\n")));
  3700. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3701. goto EndGetDeviceData;
  3702. }
  3703. }
  3704. }
  3705. //
  3706. // Get the data
  3707. //
  3708. if ((*fnGetData)(hDevice, pDataKey, pDataValue, NULL, (PBYTE)*ppDeviceData,
  3709. *pdwSize, pdwSize) == ERROR_SUCCESS)
  3710. {
  3711. rc = TRUE;
  3712. }
  3713. EndGetDeviceData:
  3714. (*fnCloseDevice)(hDevice);
  3715. return rc;
  3716. }
  3717. /******************************************************************************
  3718. *
  3719. * SetDeviceData
  3720. *
  3721. * Function:
  3722. * This function is a wrapper for ISetDeviceData. For devices like monitor,
  3723. * printer & scanner it calls the internal function. If we are asked
  3724. * to set the device data for a "colorspace device", we try monitor, printer
  3725. * and scanner till one succeeds or they all fail. This is done so that we
  3726. * we can associate sRGB like profiles with any device.
  3727. *
  3728. * Arguments:
  3729. * pDeviceName - pointer to name of the device
  3730. * dwClass - device type like monitor, printer etc.
  3731. * pDeviceData - pointer buffer containing data
  3732. * dwSize - size of data
  3733. *
  3734. * Returns:
  3735. * TRUE if successful, FALSE otherwise
  3736. *
  3737. ******************************************************************************/
  3738. BOOL
  3739. SetDeviceData(
  3740. LPCTSTR pDeviceName,
  3741. DWORD dwClass,
  3742. DWORD dwDataType,
  3743. PVOID pDeviceData,
  3744. DWORD dwSize
  3745. )
  3746. {
  3747. BOOL rc = FALSE;
  3748. if (dwClass == CLASS_MONITOR ||
  3749. dwClass == CLASS_PRINTER ||
  3750. dwClass == CLASS_SCANNER)
  3751. {
  3752. rc = ISetDeviceData(pDeviceName, dwClass, dwDataType, pDeviceData, dwSize);
  3753. }
  3754. else if (dwClass == CLASS_COLORSPACE)
  3755. {
  3756. rc = ISetDeviceData(pDeviceName, CLASS_MONITOR, dwDataType, pDeviceData, dwSize) ||
  3757. ISetDeviceData(pDeviceName, CLASS_PRINTER, dwDataType, pDeviceData, dwSize) ||
  3758. ISetDeviceData(pDeviceName, CLASS_SCANNER, dwDataType, pDeviceData, dwSize);
  3759. }
  3760. return rc;
  3761. }
  3762. /******************************************************************************
  3763. *
  3764. * ISetDeviceData
  3765. *
  3766. * Function:
  3767. * This function sets ICM data stored with the different devices.
  3768. *
  3769. * Arguments:
  3770. * pDeviceName - pointer to name of the device
  3771. * dwClass - device type like monitor, printer etc.
  3772. * pDeviceData - pointer buffer containing data
  3773. * dwSize - size of data
  3774. *
  3775. * Returns:
  3776. * TRUE if successful, FALSE otherwise
  3777. *
  3778. ******************************************************************************/
  3779. BOOL
  3780. ISetDeviceData(
  3781. LPCTSTR pDeviceName,
  3782. DWORD dwClass,
  3783. DWORD dwDataType,
  3784. PVOID pDeviceData,
  3785. DWORD dwSize
  3786. )
  3787. {
  3788. PRINTER_DEFAULTS pd;
  3789. PFNOPENDEVICE fnOpenDevice;
  3790. PFNCLOSEDEVICE fnCloseDevice;
  3791. PFNSETDEVICEDATA fnSetData;
  3792. HANDLE hDevice;
  3793. LPTSTR pDataKey;
  3794. LPTSTR pDataValue;
  3795. DWORD dwRegType = REG_BINARY;
  3796. BOOL rc = FALSE;
  3797. //
  3798. // Set up function pointers so we can write common code
  3799. //
  3800. switch (dwClass)
  3801. {
  3802. case CLASS_PRINTER:
  3803. fnOpenDevice = (PFNOPENDEVICE)OpenPrtr;
  3804. fnCloseDevice = (PFNCLOSEDEVICE)ClosePrtr;
  3805. fnSetData = (PFNSETDEVICEDATA)SetPrtrData;
  3806. pd.pDatatype = __TEXT("RAW");
  3807. pd.pDevMode = NULL;
  3808. pd.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
  3809. break;
  3810. case CLASS_MONITOR:
  3811. fnOpenDevice = (PFNOPENDEVICE)OpenMonitor;
  3812. fnCloseDevice = (PFNCLOSEDEVICE)CloseMonitor;
  3813. fnSetData = (PFNSETDEVICEDATA)SetMonitorData;
  3814. break;
  3815. case CLASS_SCANNER:
  3816. fnOpenDevice = (PFNOPENDEVICE)OpenScanner;
  3817. fnCloseDevice = (PFNCLOSEDEVICE)CloseScanner;
  3818. fnSetData = (PFNSETDEVICEDATA)SetScannerData;
  3819. break;
  3820. default:
  3821. return FALSE;
  3822. }
  3823. //
  3824. // Set up registry keywords.
  3825. //
  3826. switch (dwDataType)
  3827. {
  3828. case DEVICE_PROFILE_DATA:
  3829. pDataKey = gszICMProfileListKey;
  3830. //
  3831. // The way to store printer profile is different than others... trim it.
  3832. //
  3833. if (dwClass == CLASS_PRINTER)
  3834. {
  3835. pDataValue = gszFiles;
  3836. dwRegType = REG_MULTI_SZ;
  3837. }
  3838. else
  3839. {
  3840. pDataValue = gszICMProfileListValue;
  3841. }
  3842. break;
  3843. case DEVICE_PROFILE_ENUMMODE:
  3844. pDataKey = gszICMDeviceDataKey;
  3845. pDataValue = gszICMProfileEnumMode;
  3846. break;
  3847. default:
  3848. return FALSE;
  3849. }
  3850. //
  3851. // Open the device and get a handle to it
  3852. //
  3853. if (! (*fnOpenDevice)((PTSTR)pDeviceName, &hDevice, (PTSTR)&pd))
  3854. {
  3855. WARNING((__TEXT("Error opening device %s\n"), pDeviceName));
  3856. return FALSE;
  3857. }
  3858. //
  3859. // Set the data
  3860. //
  3861. if ((*fnSetData)(hDevice, pDataKey, pDataValue, dwRegType, (PBYTE)pDeviceData,
  3862. dwSize) == ERROR_SUCCESS)
  3863. {
  3864. rc = TRUE;
  3865. }
  3866. #if !defined(_WIN95_)
  3867. //
  3868. // If this is printer class, need some more data for profile list.
  3869. //
  3870. if ((rc == TRUE) && (dwClass == CLASS_PRINTER) && (dwDataType == DEVICE_PROFILE_DATA))
  3871. {
  3872. if (((*fnSetData)(hDevice, pDataKey, gszDirectory, REG_SZ, (PBYTE)gszColorDir,
  3873. (lstrlen(gszColorDir) + 1)*sizeof(TCHAR)) != ERROR_SUCCESS) ||
  3874. ((*fnSetData)(hDevice, pDataKey, gszModule, REG_SZ, (PBYTE)gszMSCMS,
  3875. (lstrlen(gszMSCMS) + 1)*sizeof(TCHAR)) != ERROR_SUCCESS))
  3876. {
  3877. rc = FALSE;
  3878. }
  3879. }
  3880. #endif
  3881. (*fnCloseDevice)(hDevice);
  3882. return rc;
  3883. }
  3884. /******************************************************************************
  3885. *
  3886. * IsStringInMultiSz
  3887. *
  3888. * Function:
  3889. * This functions checks if a given multi-sz string has the given string
  3890. * as one of the strings, and returns TRUE if it does.
  3891. *
  3892. * Arguments:
  3893. * pMultiSzString - multi sz string to look in
  3894. * pString - string to find
  3895. *
  3896. * Returns:
  3897. * TRUE
  3898. *
  3899. ******************************************************************************/
  3900. BOOL
  3901. IsStringInMultiSz(
  3902. PTSTR pMultiSzString,
  3903. PTSTR pString
  3904. )
  3905. {
  3906. BOOL rc = FALSE; // return code
  3907. while (*pMultiSzString)
  3908. {
  3909. if (! lstrcmpi(pMultiSzString, pString))
  3910. {
  3911. rc = TRUE;
  3912. break;
  3913. }
  3914. pMultiSzString += lstrlen(pMultiSzString) + 1;
  3915. }
  3916. return rc;
  3917. }
  3918. /******************************************************************************
  3919. *
  3920. * RemoveStringFromMultiSz
  3921. *
  3922. * Function:
  3923. * This functions removes a given string from a multi-sz string.
  3924. *
  3925. * Arguments:
  3926. * pMultiSzString - multi sz string to look in
  3927. * pString - string to remove
  3928. * dwSize - size in bytes of multi-sz string
  3929. *
  3930. * Returns:
  3931. * TRUE
  3932. *
  3933. ******************************************************************************/
  3934. DWORD
  3935. RemoveStringFromMultiSz(
  3936. PTSTR pMultiSzString,
  3937. PTSTR pString,
  3938. DWORD dwSize
  3939. )
  3940. {
  3941. DWORD dwCount = dwSize; // count of bytes remaining
  3942. while (*pMultiSzString)
  3943. {
  3944. dwCount -= (lstrlen(pMultiSzString) + 1) * sizeof(TCHAR);
  3945. if (! lstrcmpi(pMultiSzString, pString))
  3946. {
  3947. break;
  3948. }
  3949. pMultiSzString += lstrlen(pMultiSzString) + 1;
  3950. }
  3951. MyCopyMemory((PBYTE)pMultiSzString, (PBYTE)(pMultiSzString + lstrlen(pString) + 1), dwCount);
  3952. return dwSize - sizeof(TCHAR) * (lstrlen(pString) + 1);
  3953. }
  3954. /******************************************************************************
  3955. *
  3956. * DoesProfileMatchEnumRecord
  3957. *
  3958. * Function:
  3959. * This functions checks if a profile matches the criteria given in
  3960. * the enumeration record. Note that it does not check if the profile
  3961. * belongs to the device specified by pDeviceName. So that check must
  3962. * have happened before itself.
  3963. *
  3964. * Arguments:
  3965. * pProfileName - profile to look at
  3966. * pEnumRecord - pointer to criteria to check against
  3967. *
  3968. * Returns:
  3969. * MATCH or EXACT_MATCH if the profile matches the criteria, NOMATCH otherwise
  3970. *
  3971. ******************************************************************************/
  3972. #define SET(pEnumRecord, bit) ((pEnumRecord)->dwFields & (bit))
  3973. MATCHTYPE
  3974. DoesProfileMatchEnumRecord(
  3975. PTSTR pProfileName,
  3976. PENUMTYPE pEnumRecord
  3977. )
  3978. {
  3979. PROFILEHEADER header; // color profile header
  3980. PROFILE prof; // profile object for opening profile
  3981. HPROFILE hProfile = NULL; // handle to opened profile
  3982. MATCHTYPE rc = NOMATCH; // return code
  3983. //
  3984. // Open a handle to the profile
  3985. //
  3986. prof.dwType = PROFILE_FILENAME;
  3987. prof.pProfileData = (PVOID)pProfileName;
  3988. prof.cbDataSize = (lstrlen(pProfileName) + 1) * sizeof(TCHAR);
  3989. hProfile = OpenColorProfile(&prof, PROFILE_READ, FILE_SHARE_READ,
  3990. OPEN_EXISTING);
  3991. if (! hProfile)
  3992. {
  3993. WARNING((__TEXT("Error opening profile %s\n"), pProfileName));
  3994. goto EndDoesProfileMatchEnumRecord;
  3995. }
  3996. //
  3997. // Get the profile header
  3998. //
  3999. if (! GetColorProfileHeader(hProfile, &header))
  4000. {
  4001. ERR((__TEXT("Error getting color profile header for %s\n"), pProfileName));
  4002. goto EndDoesProfileMatchEnumRecord;
  4003. }
  4004. if ((!SET(pEnumRecord, ET_CMMTYPE) || (pEnumRecord->dwCMMType == header.phCMMType)) &&
  4005. (!SET(pEnumRecord, ET_CLASS) || (pEnumRecord->dwClass == header.phClass)) &&
  4006. (!SET(pEnumRecord, ET_DATACOLORSPACE) || (pEnumRecord->dwDataColorSpace == header.phDataColorSpace)) &&
  4007. (!SET(pEnumRecord, ET_CONNECTIONSPACE) || (pEnumRecord->dwConnectionSpace == header.phConnectionSpace)) &&
  4008. (!SET(pEnumRecord, ET_SIGNATURE) || (pEnumRecord->dwSignature == header.phSignature)) &&
  4009. (!SET(pEnumRecord, ET_PLATFORM) || (pEnumRecord->dwPlatform == header.phPlatform)) &&
  4010. (!SET(pEnumRecord, ET_PROFILEFLAGS) || (pEnumRecord->dwProfileFlags == header.phProfileFlags)) &&
  4011. (!SET(pEnumRecord, ET_MANUFACTURER) || (pEnumRecord->dwManufacturer == header.phManufacturer)) &&
  4012. (!SET(pEnumRecord, ET_MODEL) || (pEnumRecord->dwModel == header.phModel)) &&
  4013. (!SET(pEnumRecord, ET_ATTRIBUTES) || (pEnumRecord->dwAttributes[0] == header.phAttributes[0] &&
  4014. pEnumRecord->dwAttributes[1] == header.phAttributes[1])) &&
  4015. (!SET(pEnumRecord, ET_RENDERINGINTENT) || (pEnumRecord->dwRenderingIntent == header.phRenderingIntent)) &&
  4016. (!SET(pEnumRecord, ET_CREATOR) || (pEnumRecord->dwCreator == header.phCreator)))
  4017. {
  4018. rc = EXACT_MATCH;
  4019. }
  4020. //
  4021. // Check for resolution, media type and halftoning match
  4022. //
  4023. if (rc != NOMATCH && SET(pEnumRecord, ET_RESOLUTION|ET_MEDIATYPE|ET_DITHERMODE))
  4024. {
  4025. rc = CheckResMedHftnMatch(hProfile, pEnumRecord);
  4026. }
  4027. EndDoesProfileMatchEnumRecord:
  4028. if (hProfile)
  4029. {
  4030. CloseColorProfile(hProfile);
  4031. }
  4032. return rc;
  4033. }
  4034. /******************************************************************************
  4035. *
  4036. * CheckResMedHftnMatch
  4037. *
  4038. * Function:
  4039. * This functions checks if a profile matches the resolution,
  4040. * media type and halftoning criteria specified by the enumeration record.
  4041. * It allows an exact match, as well as an ambiguous match. If the
  4042. * profile doesn't specify the criteria, it is considered to ambiguously
  4043. * match the specification.
  4044. * is desired.
  4045. *
  4046. * Arguments:
  4047. * hProfile - handle identifying profile
  4048. * pEnumRecord - pointer to criteria to check against
  4049. *
  4050. * Returns:
  4051. * MATCH or EXACT_MATCH if the profile matches the criteria, NOMATCH otherwise
  4052. *
  4053. ******************************************************************************/
  4054. MATCHTYPE
  4055. CheckResMedHftnMatch(
  4056. HPROFILE hProfile,
  4057. PENUMTYPE pEnumRecord
  4058. )
  4059. {
  4060. PDEVICESETTINGS pDevSettings = NULL;
  4061. PPLATFORMENTRY pPlatform;
  4062. PSETTINGCOMBOS pCombo;
  4063. PSETTINGS pSetting;
  4064. DWORD dwMSData[4];
  4065. DWORD dwSize, i, iMax, j, jMax;
  4066. MATCHTYPE rc = MATCH; // Assume ambiguous match
  4067. BOOL bReference;
  4068. //
  4069. // Check if the profile has the new device settings tag
  4070. //
  4071. dwSize = 0;
  4072. GetColorProfileElement(hProfile, TAG_DEVICESETTINGS, 0, &dwSize, NULL, &bReference);
  4073. if (dwSize > 0)
  4074. {
  4075. if (!(pDevSettings = (PDEVICESETTINGS)GlobalAllocPtr(GHND, dwSize)))
  4076. {
  4077. WARNING((__TEXT("Error allocating memory\n")));
  4078. return NOMATCH;
  4079. }
  4080. if (GetColorProfileElement(hProfile, TAG_DEVICESETTINGS, 0, &dwSize, (PBYTE)pDevSettings, &bReference))
  4081. {
  4082. pPlatform = &pDevSettings->PlatformEntry[0];
  4083. //
  4084. // Navigate to the place where Microsoft specific settings are kept
  4085. //
  4086. i = 0;
  4087. iMax = FIX_ENDIAN(pDevSettings->nPlatforms);
  4088. while ((i < iMax) && (pPlatform->PlatformID != ID_MSFT_REVERSED))
  4089. {
  4090. i++;
  4091. pPlatform = (PPLATFORMENTRY)((PBYTE)pPlatform + FIX_ENDIAN(pPlatform->dwSize));
  4092. }
  4093. if (i >= iMax)
  4094. {
  4095. //
  4096. // There are no MS specific settings, assume this profile is valid
  4097. // for all settings (ambigous match)
  4098. //
  4099. goto EndCheckResMedHftnMatch;
  4100. }
  4101. //
  4102. // Found MS specific data. Now go through each combination of settings
  4103. //
  4104. pCombo = &pPlatform->SettingCombos[0];
  4105. iMax = FIX_ENDIAN(pPlatform->nSettingCombos);
  4106. for (i=0; i<iMax; i++)
  4107. {
  4108. //
  4109. // Go through each setting in the combination
  4110. //
  4111. pSetting = &pCombo->Settings[0];
  4112. jMax = FIX_ENDIAN(pCombo->nSettings);
  4113. for (j=0; j<jMax; j++)
  4114. {
  4115. if (pSetting->dwSettingType == ID_MEDIATYPE_REVERSED)
  4116. {
  4117. if (SET(pEnumRecord, ET_MEDIATYPE) &&
  4118. !DwordMatches(pSetting, pEnumRecord->dwMediaType))
  4119. {
  4120. goto NextCombo;
  4121. }
  4122. }
  4123. else if (pSetting->dwSettingType == ID_DITHER_REVERSED)
  4124. {
  4125. if (SET(pEnumRecord, ET_DITHERMODE) &&
  4126. !DwordMatches(pSetting, pEnumRecord->dwDitheringMode))
  4127. {
  4128. goto NextCombo;
  4129. }
  4130. }
  4131. else if (pSetting->dwSettingType == ID_RESLN_REVERSED)
  4132. {
  4133. if (SET(pEnumRecord, ET_RESOLUTION) &&
  4134. !QwordMatches(pSetting, &pEnumRecord->dwResolution[0]))
  4135. {
  4136. goto NextCombo;
  4137. }
  4138. }
  4139. pSetting = (PSETTINGS)((PBYTE)pSetting + sizeof(SETTINGS) - sizeof(DWORD) +
  4140. FIX_ENDIAN(pSetting->dwSizePerValue) * FIX_ENDIAN(pSetting->nValues));
  4141. }
  4142. //
  4143. // This combination worked!
  4144. //
  4145. rc = EXACT_MATCH;
  4146. goto EndCheckResMedHftnMatch;
  4147. NextCombo:
  4148. pCombo = (PSETTINGCOMBOS)((PBYTE)pCombo + FIX_ENDIAN(pCombo->dwSize));
  4149. }
  4150. rc = NOMATCH;
  4151. goto EndCheckResMedHftnMatch;
  4152. }
  4153. else
  4154. {
  4155. rc = NOMATCH;
  4156. goto EndCheckResMedHftnMatch;
  4157. }
  4158. }
  4159. else
  4160. {
  4161. //
  4162. // Check if the old MSxx tags are present
  4163. //
  4164. dwSize = sizeof(dwMSData);
  4165. if (SET(pEnumRecord, ET_MEDIATYPE))
  4166. {
  4167. if (GetColorProfileElement(hProfile, TAG_MS01, 0, &dwSize, dwMSData, &bReference))
  4168. {
  4169. rc = EXACT_MATCH; // Assume exact match
  4170. if (pEnumRecord->dwMediaType != FIX_ENDIAN(dwMSData[2]))
  4171. {
  4172. return NOMATCH;
  4173. }
  4174. }
  4175. }
  4176. dwSize = sizeof(dwMSData);
  4177. if (SET(pEnumRecord, ET_DITHERMODE))
  4178. {
  4179. if (GetColorProfileElement(hProfile, TAG_MS02, 0, &dwSize, dwMSData, &bReference))
  4180. {
  4181. rc = EXACT_MATCH; // Assume exact match
  4182. if (pEnumRecord->dwDitheringMode != FIX_ENDIAN(dwMSData[2]))
  4183. {
  4184. return NOMATCH;
  4185. }
  4186. }
  4187. }
  4188. dwSize = sizeof(dwMSData);
  4189. if (SET(pEnumRecord, ET_RESOLUTION))
  4190. {
  4191. if (GetColorProfileElement(hProfile, TAG_MS03, 0, &dwSize, dwMSData, &bReference))
  4192. {
  4193. rc = EXACT_MATCH; // Assume exact match
  4194. if (pEnumRecord->dwResolution[0] != FIX_ENDIAN(dwMSData[2]) ||
  4195. pEnumRecord->dwResolution[1] != FIX_ENDIAN(dwMSData[3]))
  4196. {
  4197. return NOMATCH;
  4198. }
  4199. }
  4200. }
  4201. }
  4202. EndCheckResMedHftnMatch:
  4203. if (pDevSettings)
  4204. {
  4205. GlobalFreePtr(pDevSettings);
  4206. }
  4207. return rc;
  4208. }
  4209. BOOL
  4210. DwordMatches(
  4211. PSETTINGS pSetting,
  4212. DWORD dwValue
  4213. )
  4214. {
  4215. DWORD i, iMax;
  4216. PDWORD pValue;
  4217. dwValue = FIX_ENDIAN(dwValue); // so we don't have to do this in the loop
  4218. //
  4219. // Go through all the values. If any of them match, return TRUE.
  4220. //
  4221. pValue = &pSetting->Value[0];
  4222. iMax = FIX_ENDIAN(pSetting->nValues);
  4223. for (i=0; i<iMax; i++)
  4224. {
  4225. if (dwValue == *pValue)
  4226. {
  4227. return TRUE;
  4228. }
  4229. pValue++; // We know that it is a DWORD
  4230. }
  4231. return FALSE;
  4232. }
  4233. BOOL
  4234. QwordMatches(
  4235. PSETTINGS pSetting,
  4236. PDWORD pdwValue
  4237. )
  4238. {
  4239. DWORD i, iMax, dwValue1, dwValue2;
  4240. PDWORD pValue;
  4241. dwValue1 = FIX_ENDIAN(*pdwValue); // so we don't have to do this in the loop
  4242. dwValue2 = FIX_ENDIAN(*(pdwValue+1));
  4243. //
  4244. // Go through all the values. If any of them match, return TRUE.
  4245. //
  4246. pValue = &pSetting->Value[0];
  4247. iMax = FIX_ENDIAN(pSetting->nValues);
  4248. for (i=0; i<iMax; i++)
  4249. {
  4250. if ((dwValue1 == *pValue) && (dwValue2 == *(pValue + 1)))
  4251. {
  4252. return TRUE;
  4253. }
  4254. pValue += 2; // We know that it is a QWORD
  4255. }
  4256. return FALSE;
  4257. }
  4258. /******************************************************************************
  4259. *
  4260. * OpenPrtr
  4261. *
  4262. * Function:
  4263. * On Memphis, we cannot call OpenPrinter() because it calls into 16-bit
  4264. * code, so if we call this function from GDI-16, we deadlock. So we
  4265. * look into the registry directly.
  4266. *
  4267. * Arguments:
  4268. * pDeviceName - pointer to name of the device
  4269. * phDevice - pointer that receives the handle.
  4270. * pDummy - dummy parameter
  4271. *
  4272. * Returns:
  4273. * TRUE if successful, FALSE otherwise
  4274. *
  4275. ******************************************************************************/
  4276. BOOL WINAPI
  4277. OpenPrtr(
  4278. PTSTR pDeviceName,
  4279. LPHANDLE phDevice,
  4280. PTSTR pDummy
  4281. )
  4282. {
  4283. #if !defined(_WIN95_)
  4284. return OpenPrinter(pDeviceName, phDevice, (LPPRINTER_DEFAULTS)pDummy);
  4285. #else
  4286. HKEY hkDevice = NULL; // printers branch of registry
  4287. HKEY hkPrtr = NULL; // Friendly name branch of registry
  4288. DWORD dwErr; // error code
  4289. BOOL rc = FALSE; // return code
  4290. *phDevice = NULL;
  4291. if (((dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, gszRegPrinter, &hkDevice)) != ERROR_SUCCESS) ||
  4292. ((dwErr = RegOpenKey(hkDevice, pDeviceName, &hkPrtr)) != ERROR_SUCCESS) ||
  4293. ((dwErr = RegOpenKey(hkPrtr, gszPrinterData, (HKEY *)phDevice)) != ERROR_SUCCESS))
  4294. {
  4295. WARNING((__TEXT("Cannot open printer data branch of registry for %s: %d\n"), pDeviceName, dwErr));
  4296. SetLastError(dwErr);
  4297. goto EndOpenPrtr;
  4298. }
  4299. rc = TRUE;
  4300. EndOpenPrtr:
  4301. if (hkDevice)
  4302. {
  4303. RegCloseKey(hkDevice);
  4304. }
  4305. if (hkPrtr)
  4306. {
  4307. RegCloseKey(hkPrtr);
  4308. }
  4309. return rc;
  4310. #endif
  4311. }
  4312. /******************************************************************************
  4313. *
  4314. * ClosePrtr
  4315. *
  4316. * Function:
  4317. * This function closes the printer handle opened by OpenPrtr.
  4318. *
  4319. * Arguments:
  4320. * hDevice - open handle
  4321. *
  4322. * Returns:
  4323. * TRUE if successful, FALSE otherwise
  4324. *
  4325. ******************************************************************************/
  4326. BOOL WINAPI
  4327. ClosePrtr(
  4328. HANDLE hDevice
  4329. )
  4330. {
  4331. #if !defined(_WIN95_)
  4332. return ClosePrinter(hDevice);
  4333. #else
  4334. DWORD dwErr;
  4335. dwErr = RegCloseKey((HKEY)hDevice);
  4336. SetLastError(dwErr);
  4337. return dwErr == ERROR_SUCCESS;
  4338. #endif
  4339. }
  4340. /******************************************************************************
  4341. *
  4342. * GetPrtrData
  4343. *
  4344. * Function:
  4345. * This functions returns ICM data stored with the printer instance
  4346. *
  4347. * Arguments:
  4348. * hDevice - open printer handle
  4349. * pKey - registry key for compatibility with GetPrinterDataEx
  4350. * pName - name of registry value
  4351. * pdwType - pointer to dword that receives type of value
  4352. * pData - pointer to buffer to receive data
  4353. * dwSize - size of buffer
  4354. * pdwNeeded - on return, this has size of buffer filled/needed
  4355. *
  4356. * Returns:
  4357. * ERROR_SUCCESS if successful, error code otherwise
  4358. *
  4359. ******************************************************************************/
  4360. DWORD WINAPI
  4361. GetPrtrData(
  4362. HANDLE hDevice,
  4363. PTSTR pKey,
  4364. PTSTR pName,
  4365. PDWORD pdwType,
  4366. PBYTE pData,
  4367. DWORD dwSize,
  4368. PDWORD pdwNeeded
  4369. )
  4370. {
  4371. #if !defined(_WIN95_)
  4372. return GetPrinterDataEx(hDevice, pKey, pName, pdwType, pData, dwSize, pdwNeeded);
  4373. #else
  4374. *pdwNeeded = dwSize;
  4375. return RegQueryValueEx((HKEY)hDevice, pName, 0, NULL, pData, pdwNeeded);
  4376. #endif
  4377. }
  4378. /******************************************************************************
  4379. *
  4380. * SetPrtrData
  4381. *
  4382. * Function:
  4383. * This functions stores ICM data with the printer instance
  4384. *
  4385. * Arguments:
  4386. * hDevice - open printer handle
  4387. * pKey - registry key for compatibility with SetPrinterDataEx
  4388. * pName - name of registry value
  4389. * dwType - type of value
  4390. * pData - pointer to data buffer
  4391. * dwSize - size of buffer
  4392. *
  4393. * Returns:
  4394. * ERROR_SUCCESS if successful, error code otherwise
  4395. *
  4396. ******************************************************************************/
  4397. DWORD WINAPI
  4398. SetPrtrData(
  4399. HANDLE hDevice,
  4400. PTSTR pKey,
  4401. PTSTR pName,
  4402. DWORD dwType,
  4403. PBYTE pData,
  4404. DWORD dwSize
  4405. )
  4406. {
  4407. #if !defined(_WIN95_)
  4408. return SetPrinterDataEx(hDevice, pKey, pName, dwType, pData, dwSize);
  4409. #else
  4410. return RegSetValueEx((HKEY)hDevice, pName, 0, dwType, pData, dwSize);
  4411. #endif
  4412. }
  4413. /******************************************************************************
  4414. *
  4415. * OpenMonitor
  4416. *
  4417. * Function:
  4418. * This function returns a handle to the monitor
  4419. *
  4420. * Arguments:
  4421. * pDeviceName - pointer to name of the device
  4422. * phDevice - pointer that receives the handle.
  4423. * pDummy - dummy parameter
  4424. *
  4425. * Returns:
  4426. * TRUE if successful, FALSE otherwise
  4427. *
  4428. ******************************************************************************/
  4429. BOOL WINAPI
  4430. OpenMonitor(
  4431. PTSTR pDeviceName,
  4432. LPHANDLE phDevice,
  4433. PTSTR pDummy
  4434. )
  4435. {
  4436. #ifdef _WIN95_
  4437. //
  4438. // For Windows 9x platform.
  4439. //
  4440. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  4441. HKEY hkICM = NULL;
  4442. HKEY hkDriver = NULL; // software branch of registry
  4443. DWORD dwSize; // size of buffer
  4444. TCHAR szName[MAX_PATH]; // buffer
  4445. BOOL rc = FALSE; // return value
  4446. SP_DEVINFO_DATA spdid;
  4447. int i; // instance counter
  4448. if (!LoadSetupAPIDll())
  4449. {
  4450. WARNING((__TEXT("Error loading setupapi.dll: %d\n"), GetLastError()));
  4451. return FALSE;
  4452. }
  4453. hDevInfo = (*fpSetupDiGetClassDevs)((LPGUID)&GUID_DEVCLASS_MONITOR, NULL, NULL, DIGCF_PRESENT);
  4454. if (hDevInfo == INVALID_HANDLE_VALUE)
  4455. {
  4456. WARNING((__TEXT("Error getting hDevInfo: %d\n"), GetLastError()));
  4457. goto EndOpenMonitor;
  4458. }
  4459. i = 0;
  4460. while (! rc)
  4461. {
  4462. ZeroMemory(&spdid, sizeof(SP_DEVINFO_DATA));
  4463. spdid.cbSize = sizeof(SP_DEVINFO_DATA);
  4464. if (! (*fpSetupDiEnumDeviceInfo)(hDevInfo, i, &spdid))
  4465. {
  4466. if (i == 0 && !lstrcmpi(pDeviceName, gszDisplay))
  4467. {
  4468. //
  4469. // PnP support not in - open ICM key in registry
  4470. //
  4471. TCHAR szICMMonitorData[] = __TEXT("ICMMonitorData");
  4472. WARNING((__TEXT("PnP support absent - Using DISPLAY\n")));
  4473. //
  4474. // Open the registry path where monitor data is kept
  4475. //
  4476. if ((RegOpenKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM) != ERROR_SUCCESS) ||
  4477. (RegCreateKey(hkICM, szICMMonitorData, &hkDriver) != ERROR_SUCCESS))
  4478. {
  4479. WARNING((__TEXT("Cannot open ICMMonitorData branch of registry\n")));
  4480. goto EndOpenMonitor;
  4481. }
  4482. rc = TRUE;
  4483. }
  4484. break;
  4485. }
  4486. //
  4487. // Get PnP ID. Check and see if the monitor name matches it.
  4488. //
  4489. dwSize = sizeof(szName);
  4490. if ((*fpSetupDiGetDeviceInstanceId)(hDevInfo, &spdid, szName, dwSize, NULL) &&
  4491. ! lstrcmp(szName, pDeviceName))
  4492. {
  4493. hkDriver = (*fpSetupDiOpenDevRegKey)(hDevInfo, &spdid, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
  4494. if (hkDriver == INVALID_HANDLE_VALUE)
  4495. {
  4496. WARNING((__TEXT("Could not open monitor s/w key for all access\n")));
  4497. hkDriver = (*fpSetupDiOpenDevRegKey)(hDevInfo, &spdid, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
  4498. if (hkDriver == INVALID_HANDLE_VALUE)
  4499. {
  4500. WARNING((__TEXT("Error opening s/w registry key for read access: %x\n"), GetLastError()));
  4501. goto EndOpenMonitor;
  4502. }
  4503. }
  4504. rc = TRUE;
  4505. }
  4506. i++;
  4507. }
  4508. EndOpenMonitor:
  4509. if (hkICM)
  4510. {
  4511. RegCloseKey(hkICM);
  4512. }
  4513. if (hDevInfo != INVALID_HANDLE_VALUE)
  4514. {
  4515. (*fpSetupDiDestroyDeviceInfoList)(hDevInfo);
  4516. }
  4517. *phDevice = (HANDLE)hkDriver;
  4518. return rc;
  4519. #else
  4520. //
  4521. // For Windows NT (later than 5.0) platform
  4522. //
  4523. TCHAR szRegPath[MAX_PATH];
  4524. HKEY hkDriver = NULL;
  4525. //
  4526. // Copy device class root key.
  4527. //
  4528. lstrcpy(szRegPath,gszDeviceClass);
  4529. lstrcat(szRegPath,gszMonitorGUID);
  4530. if (!lstrcmpi(pDeviceName, gszDisplay))
  4531. {
  4532. WARNING((__TEXT("PnP support absent - Using DISPLAY\n")));
  4533. //
  4534. // PnP support not in - just open "0000" device.
  4535. //
  4536. lstrcat(szRegPath,TEXT("\\0000"));
  4537. }
  4538. else
  4539. {
  4540. // Someone changed the input pDeviceName from uppercase to lowercase
  4541. // and our substring search failed. (RAID #282646)
  4542. // Add code to do an uppercase compare instead.
  4543. TCHAR *pszBuffer = _tcsdup(pDeviceName); // make a local copy
  4544. if(pszBuffer)
  4545. {
  4546. _tcsupr(pszBuffer); // convert it to uppercase
  4547. // we know that gszMonitorGUID is upcase already.
  4548. // do an upcase substr compare.
  4549. if (_tcsstr(pszBuffer, gszMonitorGUID))
  4550. {
  4551. //
  4552. // Extract monitor number from DeviceName
  4553. //
  4554. TCHAR *pDeviceNumber = _tcsrchr(pDeviceName,TEXT('\\'));
  4555. if (pDeviceNumber)
  4556. {
  4557. lstrcat(szRegPath,pDeviceNumber);
  4558. }
  4559. else
  4560. {
  4561. lstrcat(szRegPath,TEXT("\\0000"));
  4562. }
  4563. }
  4564. else
  4565. {
  4566. //
  4567. // This is not valid monitor name.
  4568. // Go to error out, but don't forget to free the memory
  4569. // we allocated above seeing as we skip the free below
  4570. // this code block.
  4571. //
  4572. free(pszBuffer);
  4573. goto EndOpenMonitor;
  4574. }
  4575. free(pszBuffer);
  4576. }
  4577. else
  4578. {
  4579. goto EndOpenMonitor; // failed to allocate temporary buffer.
  4580. }
  4581. }
  4582. //
  4583. // Open the registry path where monitor data is kept
  4584. //
  4585. if (RegOpenKey(HKEY_LOCAL_MACHINE, szRegPath, &hkDriver) != ERROR_SUCCESS)
  4586. {
  4587. WARNING((__TEXT("Cannot open %s key\n"),szRegPath));
  4588. hkDriver = NULL;
  4589. }
  4590. EndOpenMonitor:
  4591. *phDevice = (HANDLE) hkDriver;
  4592. return (hkDriver != NULL);
  4593. #endif // _WIN95_
  4594. }
  4595. /******************************************************************************
  4596. *
  4597. * CloseMonitor
  4598. *
  4599. * Function:
  4600. * This function closes the monitor handle opened by OpenMonitor
  4601. *
  4602. * Arguments:
  4603. * hDevice - open handle
  4604. *
  4605. * Returns:
  4606. * TRUE if successful, FALSE otherwise
  4607. *
  4608. ******************************************************************************/
  4609. BOOL WINAPI
  4610. CloseMonitor(
  4611. HANDLE hDevice
  4612. )
  4613. {
  4614. DWORD dwErr;
  4615. dwErr = RegCloseKey((HKEY)hDevice);
  4616. SetLastError(dwErr);
  4617. return (dwErr == ERROR_SUCCESS);
  4618. }
  4619. /******************************************************************************
  4620. *
  4621. * GetMonitorData
  4622. *
  4623. * Function:
  4624. * This functions returns ICM data stored with the monitor instance
  4625. *
  4626. * Arguments:
  4627. * hDevice - open monitor handle
  4628. * pKey - registry key for compatibility with GetPrinterDataEx
  4629. * pName - name of registry value
  4630. * pdwType - pointer to dword that receives type of value
  4631. * pData - pointer to buffer to receive data
  4632. * dwSize - size of buffer
  4633. * pdwNeeded - on return, this has size of buffer filled/needed
  4634. *
  4635. * Returns:
  4636. * ERROR_SUCCESS if successful, error code otherwise
  4637. *
  4638. ******************************************************************************/
  4639. DWORD WINAPI
  4640. GetMonitorData(
  4641. HANDLE hDevice,
  4642. PTSTR pKey,
  4643. PTSTR pName,
  4644. PDWORD pdwType,
  4645. PBYTE pData,
  4646. DWORD dwSize,
  4647. PDWORD pdwNeeded
  4648. )
  4649. {
  4650. DWORD dwType, dwTemp;
  4651. DWORD rc;
  4652. *pdwNeeded = dwSize;
  4653. rc = RegQueryValueEx((HKEY)hDevice, pName, 0, &dwType, pData, pdwNeeded);
  4654. if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
  4655. {
  4656. if (dwType == REG_SZ)
  4657. {
  4658. PTSTR pFilename;
  4659. //
  4660. // Old style value, convert to double null terminated binary
  4661. //
  4662. if (pData)
  4663. {
  4664. pFilename = GetFilenameFromPath((PTSTR)pData);
  4665. if ( (pFilename) &&
  4666. (pFilename != (PTSTR)pData) )
  4667. {
  4668. lstrcpy((PTSTR)pData, pFilename);
  4669. }
  4670. *pdwNeeded = lstrlen((PTSTR)pData) * sizeof(TCHAR);
  4671. }
  4672. *pdwNeeded += sizeof(TCHAR); // for double NULL termination
  4673. if ((dwSize >= *pdwNeeded) && pData)
  4674. {
  4675. *((PTSTR)pData + lstrlen((PTSTR)pData) + 1) = '\0';
  4676. //
  4677. // Set the profile name in new format
  4678. //
  4679. RegSetValueEx((HKEY)hDevice, pName, 0, REG_BINARY, pData, (lstrlen((PTSTR)pData)+2)*sizeof(TCHAR));
  4680. }
  4681. }
  4682. else if (*pdwNeeded == 1)
  4683. {
  4684. //
  4685. // If we have picked up the data and it is a 1 byte non-zero
  4686. // value, it is an 1 based index in a list of
  4687. // predefined profiles. Deal with this case.
  4688. //
  4689. // If pData is NULL, then we don't know if it is non-zero or
  4690. // not, so we assume it is and ask for a large enough buffer.
  4691. //
  4692. if (!pData || *pData != 0)
  4693. {
  4694. //
  4695. // Old style 1-based index value
  4696. //
  4697. if ((dwSize >= MAX_PATH) && pData)
  4698. {
  4699. HKEY hkICM = NULL;
  4700. HKEY hkDevice = NULL;
  4701. REGDATA regData;
  4702. //
  4703. // Make sure buggy inf doesn't crash us
  4704. //
  4705. if (pData[0] > sizeof(gszDispProfiles)/sizeof(gszDispProfiles[0]))
  4706. {
  4707. WARNING((__TEXT("Predefined profile index too large: %d\n"), pData[0]));
  4708. goto EndCompatMode;
  4709. }
  4710. lstrcpy((PTSTR)pData, gszDispProfiles[pData[0] - 1]);
  4711. *((PTSTR)pData + lstrlen((PTSTR)pData) + 1) = '\0';
  4712. //
  4713. // We need to update reference count as it wasn't set up
  4714. // using the new API
  4715. //
  4716. // Open the registry path where profiles are kept
  4717. //
  4718. if ((RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM) != ERROR_SUCCESS) ||
  4719. (RegCreateKey(hkICM, __TEXT("mntr"), &hkDevice) != ERROR_SUCCESS))
  4720. {
  4721. WARNING((__TEXT("Cannot open ICM\\device branch of registry\n")));
  4722. goto EndCompatMode;
  4723. }
  4724. //
  4725. // If registry data exists, then the profile is already installed,
  4726. // in which case, increment use count, otherwise add entry
  4727. //
  4728. dwTemp = sizeof(REGDATA);
  4729. if (RegQueryValueEx(hkDevice, (PTSTR)pData, 0, NULL, (PBYTE)&regData,
  4730. &dwTemp) == ERROR_SUCCESS)
  4731. {
  4732. regData.dwRefCount++;
  4733. }
  4734. else
  4735. {
  4736. regData.dwRefCount = 1;
  4737. regData.dwManuID = 'enon'; // it is our profile
  4738. regData.dwModelID = 'enon';
  4739. }
  4740. if (RegSetValueEx(hkDevice, (PTSTR)pData, 0, REG_BINARY,
  4741. (PBYTE)&regData, sizeof(REGDATA)) != ERROR_SUCCESS)
  4742. {
  4743. WARNING((__TEXT("Error setting registry value\n")));
  4744. goto EndCompatMode;
  4745. }
  4746. //
  4747. // Set the profile name in new format
  4748. //
  4749. RegSetValueEx((HKEY)hDevice, pName, 0, REG_BINARY, pData,
  4750. (lstrlen((PTSTR)pData) + 2)*sizeof(TCHAR));
  4751. EndCompatMode:
  4752. if (hkICM)
  4753. {
  4754. RegCloseKey(hkICM);
  4755. }
  4756. if (hkDevice)
  4757. {
  4758. RegCloseKey(hkDevice);
  4759. }
  4760. }
  4761. *pdwNeeded = MAX_PATH;
  4762. }
  4763. }
  4764. }
  4765. if ((rc == ERROR_SUCCESS) && (*pdwNeeded > dwSize))
  4766. {
  4767. rc = ERROR_MORE_DATA;
  4768. }
  4769. return rc;
  4770. }
  4771. /******************************************************************************
  4772. *
  4773. * SetMonitorData
  4774. *
  4775. * Function:
  4776. * This functions stores ICM data with the monitor instance
  4777. *
  4778. * Arguments:
  4779. * hDevice - open monitor handle
  4780. * pKey - registry key for compatibility with SetPrinterDataEx
  4781. * pName - name of registry value
  4782. * dwType - type of value
  4783. * pData - pointer to data buffer
  4784. * dwSize - size of buffer
  4785. *
  4786. * Returns:
  4787. * ERROR_SUCCESS if successful, error code otherwise
  4788. *
  4789. ******************************************************************************/
  4790. DWORD WINAPI
  4791. SetMonitorData(
  4792. HANDLE hDevice,
  4793. PTSTR pKey,
  4794. PTSTR pName,
  4795. DWORD dwType,
  4796. PBYTE pData,
  4797. DWORD dwSize
  4798. )
  4799. {
  4800. return RegSetValueEx((HKEY)hDevice, pName, 0, dwType, pData, dwSize);
  4801. }
  4802. /******************************************************************************
  4803. *
  4804. * OpenScanner
  4805. *
  4806. * Function:
  4807. * This function returns a handle to the scanner
  4808. *
  4809. * Arguments:
  4810. * pDeviceName - pointer to name of the device
  4811. * phDevice - pointer that receives the handle.
  4812. * pDummy - dummy parameter
  4813. *
  4814. * Returns:
  4815. * TRUE
  4816. *
  4817. ******************************************************************************/
  4818. BOOL WINAPI
  4819. OpenScanner(
  4820. PTSTR pDeviceName,
  4821. LPHANDLE phDevice,
  4822. PTSTR pDummy
  4823. )
  4824. {
  4825. PFNSTICREATEINSTANCE pStiCreateInstance;
  4826. PSCANNERDATA psd = NULL;
  4827. HRESULT hres;
  4828. BOOL bRc = FALSE;
  4829. if (!(psd = (PSCANNERDATA)MemAlloc(sizeof(SCANNERDATA))))
  4830. {
  4831. WARNING((__TEXT("Error allocating memory for scanner data\n")));
  4832. return FALSE;
  4833. }
  4834. if (!(psd->pDeviceName = MemAlloc((lstrlen(pDeviceName) + 1) * sizeof(WCHAR))))
  4835. {
  4836. WARNING((__TEXT("Error allocating memory for scanner name\n")));
  4837. goto EndOpenScanner;
  4838. }
  4839. #ifdef UNICODE
  4840. lstrcpy(psd->pDeviceName, pDeviceName);
  4841. #else
  4842. if (! ConvertToUnicode(pDeviceName, &psd->pDeviceName, FALSE))
  4843. {
  4844. WARNING((__TEXT("Error converting scanner name to Unicode\n")));
  4845. goto EndOpenScanner;
  4846. }
  4847. #endif
  4848. if (!(psd->hModule = LoadLibrary(gszStiDll)))
  4849. {
  4850. WARNING((__TEXT("Error loading sti.dll: %d\n"), GetLastError()));
  4851. goto EndOpenScanner;
  4852. }
  4853. if (!(pStiCreateInstance = (PFNSTICREATEINSTANCE)GetProcAddress(psd->hModule, gszStiCreateInstance)))
  4854. {
  4855. WARNING((__TEXT("Error getting proc StiCreateInstance\n")));
  4856. goto EndOpenScanner;
  4857. }
  4858. hres = (*pStiCreateInstance)(GetModuleHandle(NULL), STI_VERSION, &psd->pSti, NULL);
  4859. if (FAILED(hres))
  4860. {
  4861. WARNING((__TEXT("Error creating sti instance: %d\n"), hres));
  4862. goto EndOpenScanner;
  4863. }
  4864. *phDevice = (HANDLE)psd;
  4865. bRc = TRUE;
  4866. EndOpenScanner:
  4867. if (!bRc && psd)
  4868. {
  4869. CloseScanner((HANDLE)psd);
  4870. }
  4871. return bRc;
  4872. }
  4873. /******************************************************************************
  4874. *
  4875. * CloseScanner
  4876. *
  4877. * Function:
  4878. * This function closes the monitor handle opened by OpenMonitor
  4879. *
  4880. * Arguments:
  4881. * hDevice - handle of device
  4882. *
  4883. * Returns:
  4884. * TRUE
  4885. *
  4886. ******************************************************************************/
  4887. BOOL WINAPI
  4888. CloseScanner(
  4889. HANDLE hDevice
  4890. )
  4891. {
  4892. PSCANNERDATA psd = (PSCANNERDATA)hDevice;
  4893. if (psd)
  4894. {
  4895. if (psd->pSti)
  4896. {
  4897. psd->pSti->lpVtbl->Release(psd->pSti);
  4898. }
  4899. if (psd->pDeviceName)
  4900. {
  4901. MemFree(psd->pDeviceName);
  4902. }
  4903. if (psd->hModule)
  4904. {
  4905. FreeLibrary(psd->hModule);
  4906. }
  4907. MemFree(psd);
  4908. }
  4909. return TRUE;
  4910. }
  4911. /******************************************************************************
  4912. *
  4913. * GetScannerData
  4914. *
  4915. * Function:
  4916. * This functions returns ICM data stored with the scannerr instance
  4917. *
  4918. * Arguments:
  4919. * hDevice - open scanner handle
  4920. * pKey - registry key for compatibility with GetPrinterDataEx
  4921. * pName - name of registry value
  4922. * pdwType - pointer to dword that receives type of value
  4923. * pData - pointer to buffer to receive data
  4924. * dwSize - size of buffer
  4925. * pdwNeeded - on return, this has size of buffer filled/needed
  4926. *
  4927. * Returns:
  4928. * ERROR_SUCCESS if successful, error code otherwise
  4929. *
  4930. ******************************************************************************/
  4931. DWORD WINAPI
  4932. GetScannerData(
  4933. HANDLE hDevice,
  4934. PTSTR pKey,
  4935. PTSTR pName,
  4936. PDWORD pdwType,
  4937. PBYTE pData,
  4938. DWORD dwSize,
  4939. PDWORD pdwNeeded
  4940. )
  4941. {
  4942. PSCANNERDATA psd = (PSCANNERDATA)hDevice;
  4943. HRESULT hres;
  4944. #ifndef UNICODE
  4945. PWSTR pwszName;
  4946. //
  4947. // STI interface "ALWAYS" expects Unicode.
  4948. //
  4949. hres = ConvertToUnicode(pName, &pwszName, TRUE);
  4950. if (!hres)
  4951. {
  4952. return (ERROR_INVALID_PARAMETER);
  4953. }
  4954. pName = (PSTR)pwszName;
  4955. #endif
  4956. *pdwNeeded = dwSize;
  4957. hres = psd->pSti->lpVtbl->GetDeviceValue(psd->pSti, psd->pDeviceName, (PWSTR)pName, pdwType, pData, pdwNeeded);
  4958. #ifndef UNICODE
  4959. MemFree(pwszName);
  4960. #endif
  4961. return hres;
  4962. }
  4963. /******************************************************************************
  4964. *
  4965. * SetScannerData
  4966. *
  4967. * Function:
  4968. * This functions stores ICM data with the scanner instance
  4969. *
  4970. * Arguments:
  4971. * hDevice - open scanner handle
  4972. * pKey - registry key for compatibility with SetPrinterDataEx
  4973. * pName - name of registry value
  4974. * dwType - type of value
  4975. * pData - pointer to data buffer
  4976. * dwSize - size of buffer
  4977. *
  4978. * Returns:
  4979. * ERROR_SUCCESS if successful, error code otherwise
  4980. *
  4981. ******************************************************************************/
  4982. DWORD WINAPI
  4983. SetScannerData(
  4984. HANDLE hDevice,
  4985. PTSTR pKey,
  4986. PTSTR pName,
  4987. DWORD dwType,
  4988. PBYTE pData,
  4989. DWORD dwSize
  4990. )
  4991. {
  4992. PSCANNERDATA psd = (PSCANNERDATA)hDevice;
  4993. HRESULT hres;
  4994. #ifndef UNICODE
  4995. PWSTR pwszName;
  4996. //
  4997. // STI interface "ALWAYS" expects Unicode.
  4998. //
  4999. hres = ConvertToUnicode(pName, &pwszName, TRUE);
  5000. if (!hres)
  5001. {
  5002. return (ERROR_INVALID_PARAMETER);
  5003. }
  5004. pName = (PSTR)pwszName;
  5005. #endif
  5006. hres = psd->pSti->lpVtbl->SetDeviceValue(psd->pSti, psd->pDeviceName, (PWSTR)pName, dwType, pData, dwSize);
  5007. #ifndef UNICODE
  5008. MemFree(pwszName);
  5009. #endif
  5010. return hres;
  5011. }
  5012. //
  5013. // Internal functions
  5014. //
  5015. BOOL WINAPI
  5016. InternalGetDeviceConfig(
  5017. LPCTSTR pDeviceName,
  5018. DWORD dwDeviceClass,
  5019. DWORD dwConfigType,
  5020. PVOID pConfigData,
  5021. PDWORD pdwSize
  5022. )
  5023. {
  5024. DWORD dwDataType;
  5025. DWORD dwSizeRequired = 0;
  5026. BOOL rc = FALSE;
  5027. switch (dwConfigType)
  5028. {
  5029. case MSCMS_PROFILE_ENUM_MODE:
  5030. dwDataType = DEVICE_PROFILE_ENUMMODE;
  5031. break;
  5032. default:
  5033. WARNING((__TEXT("Invalid parameter to InternalGetDeviceConfig\n")));
  5034. SetLastError(ERROR_INVALID_PARAMETER);
  5035. return FALSE;
  5036. }
  5037. //
  5038. // Query the size of the data.
  5039. //
  5040. if (GetDeviceData(pDeviceName,dwDeviceClass,dwDataType,NULL,&dwSizeRequired,FALSE))
  5041. {
  5042. if ((dwSizeRequired <= *pdwSize) && (pConfigData != NULL))
  5043. {
  5044. //
  5045. // If buffer is enough, get the data.
  5046. //
  5047. if (GetDeviceData(pDeviceName,dwDeviceClass,dwDataType,
  5048. (PVOID *)&pConfigData,pdwSize,FALSE))
  5049. {
  5050. rc = TRUE;
  5051. }
  5052. else
  5053. {
  5054. WARNING((__TEXT("Failed on GetDeviceData to query data\n")));
  5055. SetLastError(ERROR_INVALID_PARAMETER);
  5056. }
  5057. }
  5058. else
  5059. {
  5060. //
  5061. // Return nessesary buffer size to caller.
  5062. //
  5063. *pdwSize = dwSizeRequired;
  5064. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  5065. }
  5066. }
  5067. else
  5068. {
  5069. WARNING((__TEXT("Failed on GetDeviceData to query data size\n")));
  5070. SetLastError(ERROR_INVALID_PARAMETER);
  5071. }
  5072. return rc;
  5073. }
  5074. BOOL WINAPI
  5075. InternalSetDeviceConfig(
  5076. LPCTSTR pDeviceName,
  5077. DWORD dwDeviceClass,
  5078. DWORD dwConfigType,
  5079. PVOID pConfigData,
  5080. DWORD dwSize
  5081. )
  5082. {
  5083. DWORD dwDataType;
  5084. switch (dwConfigType)
  5085. {
  5086. case MSCMS_PROFILE_ENUM_MODE:
  5087. dwDataType = DEVICE_PROFILE_ENUMMODE;
  5088. break;
  5089. default:
  5090. WARNING((__TEXT("Invalid parameter to InternalGetDeviceConfig\n")));
  5091. SetLastError(ERROR_INVALID_PARAMETER);
  5092. return FALSE;
  5093. }
  5094. //
  5095. // Save the data.
  5096. //
  5097. return (SetDeviceData(pDeviceName,dwDeviceClass,dwDataType,pConfigData,dwSize));
  5098. }
  5099. #ifdef _WIN95_
  5100. //
  5101. // Win9x specific functions are here.
  5102. //
  5103. BOOL
  5104. LoadSetupAPIDll(
  5105. VOID
  5106. )
  5107. {
  5108. EnterCriticalSection(&critsec);
  5109. if (ghModSetupAPIDll == NULL)
  5110. {
  5111. ghModSetupAPIDll = LoadLibrary(TEXT("setupapi.dll"));
  5112. if (ghModSetupAPIDll)
  5113. {
  5114. fpSetupDiOpenDevRegKey = (FP_SetupDiOpenDevRegKey)
  5115. GetProcAddress(ghModSetupAPIDll,"SetupDiOpenDevRegKey");
  5116. fpSetupDiDestroyDeviceInfoList = (FP_SetupDiDestroyDeviceInfoList)
  5117. GetProcAddress(ghModSetupAPIDll,"SetupDiDestroyDeviceInfoList");
  5118. fpSetupDiEnumDeviceInfo = (FP_SetupDiEnumDeviceInfo)
  5119. GetProcAddress(ghModSetupAPIDll,"SetupDiEnumDeviceInfo");
  5120. fpSetupDiGetDeviceInstanceId = (FP_SetupDiGetDeviceInstanceId)
  5121. GetProcAddress(ghModSetupAPIDll,"SetupDiGetDeviceInstanceIdA");
  5122. fpSetupDiGetClassDevs = (FP_SetupDiGetClassDevs)
  5123. GetProcAddress(ghModSetupAPIDll,"SetupDiGetClassDevsA");
  5124. if ((fpSetupDiOpenDevRegKey == NULL) ||
  5125. (fpSetupDiDestroyDeviceInfoList == NULL) ||
  5126. (fpSetupDiEnumDeviceInfo == NULL) ||
  5127. (fpSetupDiGetDeviceInstanceId == NULL) ||
  5128. (fpSetupDiGetClassDevs == NULL))
  5129. {
  5130. WARNING((__TEXT("Could not find Export function in setupapi.dll\n")));
  5131. FreeLibrary(ghModSetupAPIDll);
  5132. ghModSetupAPIDll = NULL;
  5133. }
  5134. }
  5135. }
  5136. LeaveCriticalSection(&critsec);
  5137. return (!!ghModSetupAPIDll);
  5138. }
  5139. #else
  5140. //
  5141. // Win NT specific functions are here.
  5142. //
  5143. VOID
  5144. ChangeICMSetting(
  5145. LPCTSTR pMachineName,
  5146. LPCTSTR pDeviceName,
  5147. DWORD dwICMMode
  5148. )
  5149. {
  5150. PRINTER_INFO_8 *ppi8;
  5151. PRINTER_INFO_9 *ppi9;
  5152. PRINTER_DEFAULTS pd;
  5153. HANDLE hPrinter;
  5154. DWORD dwSize;
  5155. BYTE temp[2*1024]; // sufficient for devmode
  5156. pd.pDatatype = NULL;
  5157. pd.pDevMode = NULL;
  5158. pd.DesiredAccess = PRINTER_ALL_ACCESS;
  5159. if (!OpenPrinter((PTSTR)pDeviceName, &hPrinter, &pd))
  5160. return;
  5161. //
  5162. // Get and update system devmode
  5163. //
  5164. ppi8 = (PRINTER_INFO_8 *)&temp;
  5165. if (GetPrinter(hPrinter, 8, (PBYTE)ppi8, sizeof(temp), &dwSize) &&
  5166. ppi8->pDevMode)
  5167. {
  5168. switch (dwICMMode)
  5169. {
  5170. case ICM_ON:
  5171. case ICM_OFF:
  5172. ppi8->pDevMode->dmFields |= DM_ICMMETHOD;
  5173. if (dwICMMode == ICM_ON)
  5174. ppi8->pDevMode->dmICMMethod = DMICMMETHOD_SYSTEM;
  5175. else
  5176. ppi8->pDevMode->dmICMMethod = DMICMMETHOD_NONE;
  5177. SetPrinter(hPrinter, 8, (PBYTE)ppi8, 0);
  5178. break;
  5179. }
  5180. }
  5181. //
  5182. // If the user has a per-user devmode, update this as well
  5183. //
  5184. ppi9 = (PRINTER_INFO_9 *)&temp;
  5185. if (GetPrinter(hPrinter, 9, (PBYTE)ppi9, sizeof(temp), &dwSize) &&
  5186. ppi9->pDevMode)
  5187. {
  5188. switch (dwICMMode)
  5189. {
  5190. case ICM_ON:
  5191. case ICM_OFF:
  5192. ppi9->pDevMode->dmFields |= DM_ICMMETHOD;
  5193. if (dwICMMode == ICM_ON)
  5194. ppi9->pDevMode->dmICMMethod = DMICMMETHOD_SYSTEM;
  5195. else
  5196. ppi9->pDevMode->dmICMMethod = DMICMMETHOD_NONE;
  5197. SetPrinter(hPrinter, 9, (PBYTE)ppi9, 0);
  5198. break;
  5199. }
  5200. }
  5201. ClosePrinter(hPrinter);
  5202. return;
  5203. }
  5204. #endif // _WIN95_