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

404 lines
8.8 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. devmode.c
  6. Abstract:
  7. Handles per-user devmode implementation.
  8. Author:
  9. Environment:
  10. User Mode -Win32
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "client.h"
  16. /********************************************************************
  17. Forward prototypes
  18. ********************************************************************/
  19. LPWSTR
  20. FormatPrinterForRegistryKey(
  21. LPWSTR pSource,
  22. LPWSTR pScratch
  23. );
  24. BOOL
  25. bGetDevModeLocation(
  26. IN PSPOOL pSpool,
  27. OUT PHKEY phKey,
  28. OUT LPCWSTR *ppszValue
  29. );
  30. const WCHAR gszPrinterConnections[] = L"Printers\\Connections\\";
  31. const WCHAR gszDevMode[] = L"DevMode";
  32. const WCHAR gszDevModePerUserLocal[] = L"Printers\\DevModePerUser";
  33. /********************************************************************
  34. Public functions
  35. ********************************************************************/
  36. BOOL
  37. bSetDevModePerUser(
  38. PSPOOL pSpool,
  39. PDEVMODE pDevMode
  40. )
  41. /*++
  42. Routine Description:
  43. Sets the per-user DevMode in HKCU.
  44. Arguments:
  45. pSpool - Printer to set.
  46. pDevMode - DevMode to save. If NULL, deletes value.
  47. Return Value:
  48. TRUE - Success
  49. FALSE - Failure
  50. --*/
  51. {
  52. HKEY hKey = NULL;
  53. BOOL bReturn = FALSE;
  54. LPWSTR pszValue = NULL;
  55. DWORD dwStatus = ERROR_SUCCESS;
  56. //
  57. // Retrieve the location of the DevMode.
  58. //
  59. bReturn = bGetDevModeLocation( pSpool,
  60. &hKey,
  61. &pszValue );
  62. if( bReturn ){
  63. if( !pDevMode ){
  64. //
  65. // NULL, so delete the value.
  66. //
  67. dwStatus = RegDeleteValue( hKey, pszValue );
  68. } else {
  69. dwStatus = RegSetValueEx( hKey,
  70. pszValue,
  71. 0,
  72. REG_BINARY,
  73. (PBYTE)pDevMode,
  74. pDevMode->dmSize +
  75. pDevMode->dmDriverExtra );
  76. }
  77. RegCloseKey( hKey );
  78. }
  79. if( dwStatus != ERROR_SUCCESS ){
  80. SetLastError( dwStatus );
  81. bReturn = FALSE;
  82. }
  83. return bReturn;
  84. }
  85. BOOL
  86. bGetDevModePerUser(
  87. PSPOOL pSpool,
  88. PDEVMODE *ppDevMode
  89. )
  90. /*++
  91. Routine Description:
  92. Retrieves the per-user DevMode based on the current user.
  93. Arguments:
  94. pSpool - Printer to use.
  95. ppDevMode - Receives pointer to devmode. Must be freed by callee.
  96. Return Value:
  97. TRUE - Success: able to check if per-user DevMode exists. *ppDevMode
  98. is NULL if no per-user DevMode is there. (TRUE does not indicate
  99. that a per-user DevMode was found, only that we successfully checked.)
  100. FALSE - Failure.
  101. --*/
  102. {
  103. HKEY hKey = NULL;
  104. BOOL bReturn = FALSE;
  105. LPWSTR pszValue = NULL;
  106. LONG Status = ERROR_SUCCESS;
  107. *ppDevMode = NULL;
  108. //
  109. // Retrieve the location of the DevMode.
  110. //
  111. if( bGetDevModeLocation( pSpool,
  112. &hKey,
  113. &pszValue )){
  114. DWORD cbDevModePerUser;
  115. //
  116. // Key exists. See if we can read it and get the per-user DevMode.
  117. //
  118. Status = RegQueryInfoKey( hKey,
  119. NULL,
  120. NULL,
  121. NULL,
  122. NULL,
  123. NULL,
  124. NULL,
  125. NULL,
  126. NULL,
  127. &cbDevModePerUser,
  128. NULL,
  129. NULL );
  130. if( Status == ERROR_SUCCESS ){
  131. *ppDevMode = AllocSplMem( cbDevModePerUser );
  132. if( *ppDevMode ){
  133. Status = RegQueryValueEx( hKey,
  134. pszValue,
  135. NULL,
  136. NULL,
  137. (PBYTE)*ppDevMode,
  138. &cbDevModePerUser );
  139. if( Status == ERROR_SUCCESS ){
  140. bReturn = TRUE;
  141. }
  142. }
  143. if( !bReturn ){
  144. FreeSplMem( *ppDevMode );
  145. *ppDevMode = NULL;
  146. }
  147. //
  148. // Allow ERROR_FILE_NOT_FOUND to return success. *ppDevMode
  149. // is still NULL, but we return TRUE to indicate that we
  150. // successfully checked the registry--we just didn't find one.
  151. //
  152. if( Status == ERROR_FILE_NOT_FOUND ){
  153. bReturn = TRUE;
  154. }
  155. }
  156. RegCloseKey( hKey );
  157. }
  158. if( !bReturn ){
  159. SetLastError( Status );
  160. }
  161. return bReturn;
  162. }
  163. BOOL
  164. bCompatibleDevMode(
  165. PSPOOL pSpool,
  166. PDEVMODE pDevModeBase,
  167. PDEVMODE pDevModeNew
  168. )
  169. /*++
  170. Routine Description:
  171. Check if two DevModes are compatible (e.g., they can be used
  172. interchangably).
  173. This is done by checking size and version information. Not
  174. foolproof, but the best we can do since we can't look at private
  175. information.
  176. Arguments:
  177. pSpool - Printer to check.
  178. pDevModeBase - Known good DevMode.
  179. pDevModeNew - DevMode to check.
  180. Return Value:
  181. TRUE - Appears compatible.
  182. FALSE - Not compatible.
  183. --*/
  184. {
  185. if( !pDevModeBase || ! pDevModeNew ){
  186. return FALSE;
  187. }
  188. return pDevModeBase->dmSize == pDevModeNew->dmSize &&
  189. pDevModeBase->dmDriverExtra == pDevModeNew->dmDriverExtra &&
  190. pDevModeBase->dmSpecVersion == pDevModeNew->dmSpecVersion &&
  191. pDevModeBase->dmDriverVersion == pDevModeNew->dmDriverVersion;
  192. }
  193. /********************************************************************
  194. Support Functions
  195. ********************************************************************/
  196. LPWSTR
  197. FormatPrinterForRegistryKey(
  198. LPWSTR pSource,
  199. LPWSTR pScratch
  200. )
  201. {
  202. if (pScratch != pSource) {
  203. //
  204. // Copy the string into the scratch buffer:
  205. //
  206. wcscpy(pScratch, pSource);
  207. }
  208. //
  209. // Check each character, and, if it's a backslash,
  210. // convert it to a comma:
  211. //
  212. for (pSource = pScratch; *pSource; pSource++) {
  213. if (*pSource == L'\\')
  214. *pSource = L',';
  215. }
  216. return pScratch;
  217. }
  218. BOOL
  219. bGetDevModeLocation(
  220. IN PSPOOL pSpool,
  221. OUT PHKEY phKey,
  222. OUT LPCWSTR *ppszValue
  223. )
  224. /*++
  225. Routine Description:
  226. Retrieves the location of the per-user DevMode.
  227. On success, caller is responsible for closing phKey. ppszValue's
  228. life is dependent on pSpool.
  229. Arguments:
  230. pSpool - Printer to use.
  231. phKey - Receives R/W key of per-user DevMode. On success, this
  232. must be closed by caller.
  233. ppszValue - Receives value of per-user DevMode (where to read/write).
  234. Return Value:
  235. TRUE - Success
  236. FALSE - Failure, LastError set.
  237. --*/
  238. {
  239. WCHAR szPrinterScratch[MAX_PRINTER_NAME + COUNTOF( gszPrinterConnections )];
  240. BOOL bReturn = FALSE;
  241. DWORD dwError = ERROR_SUCCESS;
  242. //
  243. // If it starts with two backslashes, it may be either a connection
  244. // or a masq printer.
  245. //
  246. if( pSpool->pszPrinter[0] == L'\\' && pSpool->pszPrinter[1] == L'\\' ){
  247. //
  248. // Query the registry for pSpool->pszPrinter and look for DevMode.
  249. // First look at the HKCU:Printer\Connections.
  250. //
  251. wcscpy( szPrinterScratch, gszPrinterConnections );
  252. FormatPrinterForRegistryKey(
  253. pSpool->pszPrinter,
  254. &szPrinterScratch[ COUNTOF( gszPrinterConnections )-1] );
  255. dwError = RegOpenKeyEx( HKEY_CURRENT_USER,
  256. szPrinterScratch,
  257. 0,
  258. KEY_READ | KEY_WRITE,
  259. phKey );
  260. if( dwError == ERROR_SUCCESS ){
  261. *ppszValue = gszDevMode;
  262. bReturn = TRUE;
  263. }
  264. }
  265. if( !bReturn ){
  266. DWORD dwIgnore;
  267. //
  268. // Not a connection or didn't exist in the connections key.
  269. // Look in the Printers\DevModePerUser key.
  270. //
  271. dwError = RegCreateKeyEx( HKEY_CURRENT_USER,
  272. gszDevModePerUserLocal,
  273. 0,
  274. NULL,
  275. 0,
  276. KEY_READ | KEY_WRITE,
  277. NULL,
  278. phKey,
  279. &dwIgnore );
  280. if( dwError == ERROR_SUCCESS ){
  281. *ppszValue = pSpool->pszPrinter;
  282. bReturn = TRUE;
  283. }
  284. }
  285. if( !bReturn ){
  286. SetLastError( dwError );
  287. }
  288. return bReturn;
  289. }