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.

555 lines
14 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 "local.h"
  16. #include <offsets.h>
  17. /********************************************************************
  18. Forward prototypes
  19. ********************************************************************/
  20. BOOL
  21. bGetDevModeLocation(
  22. IN HKEY hKeyUser, OPTIONAL
  23. IN LPCWSTR pszPrinter,
  24. OUT PHKEY phKey,
  25. OUT LPCWSTR *ppszValue
  26. );
  27. const WCHAR gszPrinterConnections[] = L"Printers\\Connections\\";
  28. const WCHAR gszDevMode[] = L"DevMode";
  29. const WCHAR gszDevModePerUserLocal[] = L"Printers\\DevModePerUser";
  30. /********************************************************************
  31. Private Functions
  32. ********************************************************************/
  33. DWORD
  34. RegOpenConnectionKey(
  35. HKEY hKeyUser,
  36. LPWSTR pszPrinter,
  37. PHKEY phKey
  38. )
  39. {
  40. PWCHAR pszPrinterScratch = NULL;
  41. DWORD dwRetValue = ERROR_SUCCESS;
  42. DWORD cchSize = MAX_UNC_PRINTER_NAME + PRINTER_NAME_SUFFIX_MAX + COUNTOF( gszPrinterConnections );
  43. if (pszPrinter &&
  44. wcslen(pszPrinter) < MAX_UNC_PRINTER_NAME + PRINTER_NAME_SUFFIX_MAX) {
  45. if (pszPrinterScratch = AllocSplMem(cchSize * sizeof(WCHAR))) {
  46. StringCchCopy(pszPrinterScratch, cchSize, gszPrinterConnections);
  47. FormatPrinterForRegistryKey(pszPrinter,
  48. &pszPrinterScratch[ COUNTOF( gszPrinterConnections )-1],
  49. cchSize - COUNTOF( gszPrinterConnections ) - 1);
  50. dwRetValue = RegOpenKeyEx(hKeyUser,
  51. pszPrinterScratch,
  52. 0,
  53. KEY_READ | KEY_WRITE,
  54. phKey );
  55. FreeSplMem(pszPrinterScratch);
  56. } else {
  57. dwRetValue = GetLastError();
  58. }
  59. } else {
  60. dwRetValue = ERROR_INVALID_PARAMETER;
  61. }
  62. return dwRetValue;
  63. }
  64. /********************************************************************
  65. Public functions
  66. ********************************************************************/
  67. BOOL
  68. bSetDevModePerUser(
  69. HANDLE hKeyUser,
  70. LPCWSTR pszPrinter,
  71. PDEVMODE pDevMode
  72. )
  73. /*++
  74. Routine Description:
  75. Sets the per-user DevMode in HKCU.
  76. Arguments:
  77. hKeyUser - HKEY_CURRENT_USER handle. OPTIONAL
  78. pszPrinter - Printer to set.
  79. pDevMode - DevMode to save. If NULL, deletes value.
  80. Return Value:
  81. TRUE - Success
  82. FALSE - Failure
  83. --*/
  84. {
  85. HKEY hKey = NULL;
  86. LPWSTR pszValue = NULL;
  87. DWORD Status;
  88. if( !pszPrinter ){
  89. SetLastError( ERROR_INVALID_HANDLE );
  90. return FALSE;
  91. }
  92. //
  93. // Retrieve the location of the DevMode.
  94. //
  95. if( !bGetDevModeLocation( hKeyUser,
  96. pszPrinter,
  97. &hKey,
  98. &pszValue )){
  99. return FALSE;
  100. }
  101. if( !pDevMode ){
  102. //
  103. // NULL, so delete the value.
  104. //
  105. Status = RegDeleteValue( hKey, pszValue );
  106. //
  107. // If value not found, don't fail.
  108. //
  109. if( Status == ERROR_FILE_NOT_FOUND ){
  110. Status = ERROR_SUCCESS;
  111. }
  112. } else {
  113. Status = RegSetValueEx( hKey,
  114. pszValue,
  115. 0,
  116. REG_BINARY,
  117. (PBYTE)pDevMode,
  118. pDevMode->dmSize +
  119. pDevMode->dmDriverExtra );
  120. if( Status == ERROR_SUCCESS ){
  121. //
  122. // Notify everyone that the DevMode has changed.
  123. //
  124. SendNotifyMessage( HWND_BROADCAST,
  125. WM_DEVMODECHANGE,
  126. 0,
  127. (LPARAM)pszPrinter );
  128. }
  129. }
  130. RegCloseKey( hKey );
  131. if( Status != ERROR_SUCCESS ){
  132. SetLastError( Status );
  133. return FALSE;
  134. }
  135. return TRUE;
  136. }
  137. BOOL
  138. bGetDevModePerUser(
  139. HKEY hKeyUser,
  140. LPCWSTR pszPrinter,
  141. PDEVMODE *ppDevMode
  142. )
  143. /*++
  144. Routine Description:
  145. Retrieves the per-user DevMode based on the current user.
  146. Arguments:
  147. hKeyUser - HKEY_CURRENT_USER handle. OPTIONAL
  148. pszPrinter - Printer to get.
  149. ppDevMode - Receives pointer to devmode. Must be freed by callee.
  150. Return Value:
  151. TRUE - Success: able to check if per-user DevMode exists. *ppDevMode
  152. is NULL if no per-user DevMode is there. (TRUE does not indicate
  153. that a per-user DevMode was found, only that we successfully checked.)
  154. FALSE - Failure.
  155. --*/
  156. {
  157. HKEY hKey = NULL;
  158. LPWSTR pszValue = NULL;
  159. LONG Status;
  160. *ppDevMode = NULL;
  161. if( !pszPrinter ){
  162. SetLastError( ERROR_INVALID_HANDLE );
  163. return FALSE;
  164. }
  165. //
  166. // Retrieve the location of the DevMode.
  167. //
  168. if( !bGetDevModeLocation( hKeyUser,
  169. pszPrinter,
  170. &hKey,
  171. &pszValue )){
  172. Status = GetLastError();
  173. } else {
  174. DWORD cbDevModePerUser;
  175. //
  176. // Key exists. See if we can read it and get the per-user DevMode.
  177. //
  178. Status = RegQueryInfoKey( hKey,
  179. NULL,
  180. NULL,
  181. NULL,
  182. NULL,
  183. NULL,
  184. NULL,
  185. NULL,
  186. NULL,
  187. &cbDevModePerUser,
  188. NULL,
  189. NULL );
  190. if( Status == ERROR_SUCCESS ){
  191. if( cbDevModePerUser >= MIN_DEVMODE_SIZEW ){
  192. *ppDevMode = AllocSplMem( cbDevModePerUser );
  193. if( !*ppDevMode ){
  194. Status = GetLastError();
  195. } else {
  196. Status = RegQueryValueEx( hKey,
  197. pszValue,
  198. NULL,
  199. NULL,
  200. (PBYTE)*ppDevMode,
  201. &cbDevModePerUser );
  202. if (ERROR_SUCCESS == Status) {
  203. Status = StatusFromHResult(SplIsValidDevmodeW(*ppDevMode, cbDevModePerUser));
  204. //
  205. // If the devmode isn't valid, delete it and treat it
  206. // as if the devmode cannot be found.
  207. //
  208. if (ERROR_SUCCESS != Status) {
  209. //
  210. // If we can delete the key, just consider it as if
  211. // it does not exist.
  212. //
  213. if (ERROR_SUCCESS == RegDeleteValue(hKey, pszValue)) {
  214. Status = ERROR_FILE_NOT_FOUND;
  215. }
  216. }
  217. }
  218. if( Status != ERROR_SUCCESS ){
  219. FreeSplMem( *ppDevMode );
  220. *ppDevMode = NULL;
  221. }
  222. //
  223. // Allow ERROR_FILE_NOT_FOUND to return success. *ppDevMode
  224. // is still NULL, but we return TRUE to indicate that we
  225. // successfully checked the registry--we just didn't find one.
  226. //
  227. if( Status == ERROR_FILE_NOT_FOUND ){
  228. Status = ERROR_SUCCESS;
  229. }
  230. }
  231. }
  232. }
  233. RegCloseKey( hKey );
  234. }
  235. if( Status != ERROR_SUCCESS ){
  236. SetLastError( Status );
  237. return FALSE;
  238. }
  239. return TRUE;
  240. }
  241. BOOL
  242. bCompatibleDevMode(
  243. PPRINTHANDLE pPrintHandle,
  244. PDEVMODE pDevModeBase,
  245. PDEVMODE pDevModeNew
  246. )
  247. /*++
  248. Routine Description:
  249. Check if two DevModes are compatible (e.g., they can be used
  250. interchangably).
  251. This is done by checking size and version information. Not
  252. foolproof, but the best we can do since we can't look at private
  253. information.
  254. Arguments:
  255. pPrintHandle - Printer to check.
  256. pDevModeBase - Known good DevMode.
  257. pDevModeNew - DevMode to check.
  258. Return Value:
  259. TRUE - Appears compatible.
  260. FALSE - Not compatible.
  261. --*/
  262. {
  263. if( !pDevModeBase || ! pDevModeNew ){
  264. return FALSE;
  265. }
  266. return pDevModeBase->dmSize == pDevModeNew->dmSize &&
  267. pDevModeBase->dmDriverExtra == pDevModeNew->dmDriverExtra &&
  268. pDevModeBase->dmSpecVersion == pDevModeNew->dmSpecVersion &&
  269. pDevModeBase->dmDriverVersion == pDevModeNew->dmDriverVersion;
  270. }
  271. /********************************************************************
  272. Support Functions
  273. ********************************************************************/
  274. BOOL
  275. bGetDevModeLocation(
  276. IN HKEY hKeyUser, OPTIONAL
  277. IN LPCWSTR pszPrinter,
  278. OUT PHKEY phKey,
  279. OUT LPCWSTR *ppszValue
  280. )
  281. /*++
  282. Routine Description:
  283. Retrieves the location of the per-user DevMode.
  284. On success, caller is responsible for closing phKey. ppszValue's
  285. life is dependent on pszPrinter.
  286. Arguments:
  287. hKeyUser - HKEY_CURRENT_USER key--optional. If not specified, current
  288. impersonation used.
  289. pszPrinter - Printer to use.
  290. phKey - Receives R/W key of per-user DevMode. On success, this
  291. must be closed by caller.
  292. ppszValue - Receives value of per-user DevMode (where to read/write).
  293. Return Value:
  294. TRUE - Success
  295. FALSE - Failure, LastError set.
  296. --*/
  297. {
  298. HANDLE hKeyClose = NULL;
  299. DWORD Status;
  300. *phKey = NULL;
  301. *ppszValue = NULL;
  302. if( !hKeyUser ){
  303. hKeyUser = GetClientUserHandle( KEY_READ|KEY_WRITE );
  304. hKeyClose = hKeyUser;
  305. }
  306. if( !hKeyUser ){
  307. //
  308. // Failed to get impersonation information. Probably because
  309. // we're not impersonating, so there's no per-user information.
  310. //
  311. Status = GetLastError();
  312. } else {
  313. //
  314. // If it starts with two backslashes, it may be either a connection
  315. // or a masq printer.
  316. //
  317. if( pszPrinter[0] == L'\\' && pszPrinter[1] == L'\\' )
  318. {
  319. //
  320. // Query the registry for pszPrinter and look for DevMode.
  321. // First look at the HKCU:Printer\Connections.
  322. //
  323. if((Status = RegOpenConnectionKey(hKeyUser,(LPWSTR)pszPrinter,phKey)) == ERROR_SUCCESS)
  324. {
  325. *ppszValue = gszDevMode;
  326. }
  327. }
  328. //
  329. // If we didn't find it in Printer\Connection, then it
  330. // must be a local or masq printer.
  331. //
  332. if( !*ppszValue ){
  333. DWORD dwIgnore;
  334. //
  335. // Not a connection or didn't exist in the connections key.
  336. // Look in the Printers\DevModePerUser key.
  337. //
  338. Status = RegCreateKeyEx( hKeyUser,
  339. gszDevModePerUserLocal,
  340. 0,
  341. NULL,
  342. 0,
  343. KEY_READ | KEY_WRITE,
  344. NULL,
  345. phKey,
  346. &dwIgnore );
  347. if( Status == ERROR_SUCCESS ){
  348. *ppszValue = pszPrinter;
  349. }
  350. }
  351. }
  352. if( hKeyClose ){
  353. RegCloseKey( hKeyClose );
  354. }
  355. if( Status != ERROR_SUCCESS ){
  356. SetLastError( Status );
  357. return FALSE;
  358. }
  359. return TRUE;
  360. }
  361. BOOL bGetDevModePerUserEvenForShares(
  362. HKEY hKeyUser,
  363. LPCWSTR pszPrinter,
  364. PDEVMODE *ppDevMode
  365. )
  366. {
  367. BOOL RetVal = FALSE;
  368. HANDLE hPrinter;
  369. if(OpenPrinter((LPWSTR)pszPrinter,&hPrinter,NULL))
  370. {
  371. DWORD PrntrInfoSize=0,PrntrInfoSizeReq=0;
  372. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  373. if(!GetPrinter(hPrinter,
  374. 2,
  375. (LPBYTE)pPrinterInfo2,
  376. PrntrInfoSize,
  377. &PrntrInfoSizeReq) &&
  378. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  379. (pPrinterInfo2 = (PPRINTER_INFO_2)AllocSplMem((PrntrInfoSize = PrntrInfoSizeReq))) &&
  380. GetPrinter(hPrinter,
  381. 2,
  382. (LPBYTE)pPrinterInfo2,
  383. PrntrInfoSize,
  384. &PrntrInfoSizeReq))
  385. {
  386. RetVal = bGetDevModePerUser( hKeyUser,
  387. pPrinterInfo2->pPrinterName,
  388. ppDevMode );
  389. }
  390. if(hPrinter)
  391. ClosePrinter(hPrinter);
  392. if(pPrinterInfo2)
  393. FreeSplMem(pPrinterInfo2);
  394. }
  395. else
  396. {
  397. RetVal = bGetDevModePerUser( hKeyUser,
  398. pszPrinter,
  399. ppDevMode );
  400. }
  401. return(RetVal);
  402. }