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.

5492 lines
143 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. winspla.c
  6. Abstract:
  7. Ansi end to winspool.drv
  8. Author:
  9. Environment:
  10. User Mode -Win32
  11. Revision History:
  12. amaxa July 2000 - Modified GetPrinterData(Ex)A and SetPrinterData(Ex)A to
  13. have the same behavior like the unicode functions.
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "client.h"
  18. #include "defprn.h"
  19. #include "winsprlp.h"
  20. typedef int (FAR WINAPI *INT_FARPROC)();
  21. typedef struct {
  22. BOOL bOsVersionEx;
  23. union {
  24. OSVERSIONINFOW *pOsVersion;
  25. OSVERSIONINFOEXW *pOsVersionEx;
  26. } Unicode;
  27. union {
  28. OSVERSIONINFOA *pOsVersion;
  29. OSVERSIONINFOEXA *pOsVersionEx;
  30. } Ansi;
  31. } OSVERSIONWRAP;
  32. WCHAR *szCurDevMode = L"Printers\\DevModes2";
  33. BOOL
  34. KickoffThread(
  35. LPWSTR pName,
  36. HWND hWnd,
  37. LPWSTR pPortName,
  38. INT_FARPROC pfn
  39. );
  40. LPWSTR
  41. AllocateUnicodeStringWithSize(
  42. LPSTR pPrinterName,
  43. DWORD cbBytes
  44. );
  45. VOID
  46. ValidatePaperFields(
  47. LPCWSTR pUnicodeDeviceName,
  48. LPCWSTR pUnicodePort,
  49. LPDEVMODEW pDevModeIn
  50. );
  51. #define NULL_TERMINATED 0
  52. DWORD
  53. UnicodeToAnsi(
  54. IN LPBYTE pUnicode,
  55. IN DWORD cchUnicode,
  56. IN OUT LPBYTE pData,
  57. IN DWORD cbData,
  58. IN OUT DWORD *pcbCopied OPTIONAL
  59. );
  60. /* AnsiToUnicodeString
  61. *
  62. * Parameters:
  63. *
  64. * pAnsi - A valid source ANSI string.
  65. *
  66. * pUnicode - A pointer to a buffer large enough to accommodate
  67. * the converted string.
  68. *
  69. * StringLength - The length of the source ANSI string.
  70. * If 0 (NULL_TERMINATED), the string is assumed to be
  71. * null-terminated.
  72. *
  73. * Return:
  74. *
  75. * The return value from MultiByteToWideChar, the number of
  76. * wide characters returned.
  77. *
  78. */
  79. INT AnsiToUnicodeString( LPSTR pAnsi, LPWSTR pUnicode, DWORD StringLength )
  80. {
  81. INT iReturn;
  82. if( StringLength == NULL_TERMINATED )
  83. StringLength = strlen( pAnsi );
  84. iReturn = MultiByteToWideChar(CP_THREAD_ACP,
  85. MB_PRECOMPOSED,
  86. pAnsi,
  87. StringLength + 1,
  88. pUnicode,
  89. StringLength + 1 );
  90. //
  91. // Ensure NULL termination.
  92. //
  93. pUnicode[StringLength] = 0;
  94. return iReturn;
  95. }
  96. /* UnicodeToAnsiString
  97. *
  98. * Parameters:
  99. *
  100. * pUnicode - A valid source Unicode string.
  101. *
  102. * pANSI - A pointer to a buffer large enough to accommodate
  103. * the converted string.
  104. *
  105. * StringLength - The length of the source Unicode string.
  106. * If 0 (NULL_TERMINATED), the string is assumed to be
  107. * null-terminated.
  108. *
  109. *
  110. * Notes:
  111. * With DBCS enabled, we will allocate twice the size of the
  112. * buffer including the null terminator to take care of double
  113. * byte character strings - KrishnaG
  114. *
  115. * pUnicode is truncated to StringLength characters.
  116. *
  117. * Return:
  118. *
  119. * The return value from WideCharToMultiByte, the number of
  120. * multi-byte characters returned.
  121. *
  122. */
  123. INT
  124. UnicodeToAnsiString(
  125. LPWSTR pUnicode,
  126. LPSTR pAnsi,
  127. DWORD StringLength)
  128. {
  129. LPSTR pTempBuf = NULL;
  130. INT rc = 0;
  131. LPWSTR pAlignedUnicode = NULL;
  132. if ((ULONG_PTR)pUnicode != (((ULONG_PTR) (pUnicode) + (sizeof(WCHAR) - 1))&~(sizeof(WCHAR) - 1))) {
  133. //
  134. // Calculate the length of the unaligned string.
  135. //
  136. if(StringLength == NULL_TERMINATED) {
  137. for (StringLength = 0;
  138. !( ((LPSTR)pUnicode)[StringLength] == '\0' &&
  139. ((LPSTR)pUnicode)[StringLength+1] == '\0' );
  140. StringLength += 2)
  141. ;
  142. StringLength /= 2;
  143. } else {
  144. //
  145. // WideCharToMultiByte doesn't NULL terminate if we're copying
  146. // just part of the string, so terminate here.
  147. //
  148. ((LPSTR)(pUnicode + StringLength))[0] = '\0';
  149. ((LPSTR)(pUnicode + StringLength))[1] = '\0';
  150. }
  151. StringLength++;
  152. pAlignedUnicode = LocalAlloc(LPTR, StringLength * sizeof(WCHAR));
  153. if (pAlignedUnicode) {
  154. memcpy(pAlignedUnicode, pUnicode, StringLength * sizeof(WCHAR));
  155. }
  156. } else {
  157. pAlignedUnicode = pUnicode;
  158. if(StringLength == NULL_TERMINATED) {
  159. //
  160. // StringLength is just the
  161. // number of characters in the string
  162. //
  163. StringLength = wcslen(pAlignedUnicode);
  164. }
  165. //
  166. // WideCharToMultiByte doesn't NULL terminate if we're copying
  167. // just part of the string, so terminate here.
  168. //
  169. pAlignedUnicode[StringLength] = 0;
  170. StringLength++;
  171. }
  172. //
  173. // Unfortunately, WideCharToMultiByte doesn't do conversion in place,
  174. // so allocate a temporary buffer, which we can then copy:
  175. //
  176. if( pAnsi == (LPSTR)pAlignedUnicode )
  177. {
  178. pTempBuf = LocalAlloc( LPTR, StringLength * sizeof(WCHAR) );
  179. pAnsi = pTempBuf;
  180. }
  181. if( pAnsi && pAlignedUnicode )
  182. {
  183. rc = WideCharToMultiByte( CP_THREAD_ACP,
  184. 0,
  185. pAlignedUnicode,
  186. StringLength,
  187. pAnsi,
  188. StringLength*2,
  189. NULL,
  190. NULL );
  191. }
  192. //
  193. // If pTempBuf is non-null, we must copy the resulting string
  194. // so that it looks as if we did it in place:
  195. //
  196. if( pTempBuf )
  197. {
  198. if( rc > 0 )
  199. {
  200. pAnsi = (LPSTR)pAlignedUnicode;
  201. if (FAILED(StringCbCopyExA( pAnsi, StringLength * sizeof(WCHAR), pTempBuf, NULL, NULL, STRSAFE_FILL_ON_FAILURE)))
  202. {
  203. rc = 0;
  204. }
  205. }
  206. LocalFree( pTempBuf );
  207. }
  208. if (pAlignedUnicode != pUnicode) {
  209. LocalFree(pAlignedUnicode);
  210. }
  211. return rc;
  212. }
  213. void
  214. ConvertUnicodeToAnsiStrings(
  215. LPBYTE pStructure,
  216. LPDWORD pOffsets
  217. )
  218. {
  219. register DWORD i=0;
  220. LPWSTR pUnicode;
  221. LPSTR pAnsi;
  222. while (pOffsets[i] != -1) {
  223. pUnicode = *(LPWSTR *)(pStructure+pOffsets[i]);
  224. pAnsi = (LPSTR)pUnicode;
  225. if (pUnicode) {
  226. UnicodeToAnsiString(pUnicode, pAnsi, NULL_TERMINATED);
  227. }
  228. i++;
  229. }
  230. }
  231. LPWSTR
  232. AllocateUnicodeString(
  233. LPSTR pPrinterName
  234. )
  235. {
  236. LPWSTR pUnicodeString;
  237. if (!pPrinterName)
  238. return NULL;
  239. pUnicodeString = LocalAlloc(LPTR, strlen(pPrinterName)*sizeof(WCHAR) +
  240. sizeof(WCHAR));
  241. if (pUnicodeString)
  242. AnsiToUnicodeString(pPrinterName, pUnicodeString, NULL_TERMINATED);
  243. return pUnicodeString;
  244. }
  245. LPWSTR
  246. AllocateUnicodeStringWithSize(
  247. LPSTR pData,
  248. DWORD cbData
  249. )
  250. {
  251. LPWSTR pUnicodeString = NULL;
  252. DWORD iReturn;
  253. if (pData &&
  254. (pUnicodeString = LocalAlloc(LPTR, cbData*sizeof(WCHAR))))
  255. {
  256. iReturn = MultiByteToWideChar(CP_THREAD_ACP,
  257. MB_PRECOMPOSED,
  258. pData,
  259. cbData,
  260. pUnicodeString,
  261. cbData);
  262. if (iReturn != cbData)
  263. {
  264. LocalFree(pUnicodeString);
  265. pUnicodeString = NULL;
  266. }
  267. }
  268. return pUnicodeString;
  269. }
  270. LPWSTR
  271. FreeUnicodeString(
  272. LPWSTR pUnicodeString
  273. )
  274. {
  275. if (!pUnicodeString)
  276. return NULL;
  277. return LocalFree(pUnicodeString);
  278. }
  279. LPBYTE
  280. AllocateUnicodeStructure(
  281. LPBYTE pAnsiStructure,
  282. DWORD cbStruct,
  283. LPDWORD pOffsets
  284. )
  285. {
  286. DWORD i, j;
  287. LPWSTR *ppUnicodeString;
  288. LPSTR *ppAnsiString;
  289. LPBYTE pUnicodeStructure;
  290. if (!pAnsiStructure) {
  291. return NULL;
  292. }
  293. pUnicodeStructure = LocalAlloc(LPTR, cbStruct);
  294. if (pUnicodeStructure) {
  295. memcpy(pUnicodeStructure, pAnsiStructure, cbStruct);
  296. for (i = 0 ; pOffsets[i] != -1 ; ++i) {
  297. ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[i]);
  298. ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[i]);
  299. *ppUnicodeString = AllocateUnicodeString(*ppAnsiString);
  300. if (*ppAnsiString && !*ppUnicodeString) {
  301. for( j = 0 ; j < i ; ++j) {
  302. ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[j]);
  303. FreeUnicodeString(*ppUnicodeString);
  304. }
  305. LocalFree(pUnicodeStructure);
  306. pUnicodeStructure = NULL;
  307. break;
  308. }
  309. }
  310. }
  311. return pUnicodeStructure;
  312. }
  313. DWORD
  314. CopyOsVersionUnicodeToAnsi(
  315. IN OUT OSVERSIONWRAP Arg
  316. )
  317. /*++
  318. Routine Name:
  319. CopyOsVersionUnicodeToAnsi
  320. Routine Description:
  321. Copies the contents of the UNICODE structure OSVERSIONINFO(EX) into the ANSI structure.
  322. Arguments:
  323. An OSVERSIONWRAP structure
  324. Return Value:
  325. Win32 error core
  326. --*/
  327. {
  328. DWORD dwError = ERROR_INVALID_PARAMETER;
  329. OSVERSIONINFOEXW *pIn = Arg.Unicode.pOsVersionEx;
  330. OSVERSIONINFOEXA *pOut = Arg.Ansi.pOsVersionEx;
  331. if (pIn && pOut)
  332. {
  333. dwError = ERROR_SUCCESS;
  334. pOut->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  335. pOut->dwMajorVersion = pIn->dwMajorVersion;
  336. pOut->dwMinorVersion = pIn->dwMinorVersion;
  337. pOut->dwBuildNumber = pIn->dwBuildNumber;
  338. pOut->dwPlatformId = pIn->dwPlatformId;
  339. //
  340. // Initialize the array of chars szCSDVersion to 0 so that we are consistent with
  341. // the return of the UNICODE versions of GetPrinterData(Ex).
  342. //
  343. memset(pOut->szCSDVersion, 0, COUNTOF(pOut->szCSDVersion));
  344. UnicodeToAnsiString(pIn->szCSDVersion, pOut->szCSDVersion, NULL_TERMINATED);
  345. //
  346. // Copy the rest of the Ex structure
  347. //
  348. if (Arg.bOsVersionEx)
  349. {
  350. pOut->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
  351. pOut->wServicePackMajor = pIn->wServicePackMajor;
  352. pOut->wServicePackMinor = pIn->wServicePackMinor;
  353. pOut->wSuiteMask = pIn->wSuiteMask;
  354. pOut->wProductType = pIn->wProductType;
  355. pOut->wReserved = pIn->wReserved;
  356. }
  357. }
  358. return dwError;
  359. }
  360. DWORD
  361. ComputeMaxStrlenW(
  362. LPWSTR pString,
  363. DWORD cchBufMax)
  364. /*++
  365. Routine Description:
  366. Returns the length of the Unicode string, EXCLUDING the NULL. If the
  367. string (plus NULL) won't fit into the cchBufMax, then the string len is
  368. decreased.
  369. Arguments:
  370. Return Value:
  371. --*/
  372. {
  373. DWORD cchLen;
  374. //
  375. // Include space for the NULL.
  376. //
  377. cchBufMax--;
  378. cchLen = wcslen(pString);
  379. if (cchLen > cchBufMax)
  380. return cchBufMax;
  381. return cchLen;
  382. }
  383. DWORD
  384. ComputeMaxStrlenA(
  385. LPSTR pString,
  386. DWORD cchBufMax)
  387. /*++
  388. Routine Description:
  389. Returns the length of the Ansi string, EXCLUDING the NULL. If the
  390. string (plus NULL) won't fit into the cchBufMax, then the string len is
  391. decreased.
  392. Arguments:
  393. Return Value:
  394. --*/
  395. {
  396. DWORD cchLen;
  397. //
  398. // Include space for the NULL.
  399. //
  400. cchBufMax--;
  401. cchLen = lstrlenA(pString);
  402. if (cchLen > cchBufMax)
  403. return cchBufMax;
  404. return cchLen;
  405. }
  406. /***************************** Function Header ******************************
  407. * AllocateUnicodeDevMode
  408. * Allocate a UNICODE version of the DEVMODE structure, and optionally
  409. * copy the contents of the ANSI version passed in.
  410. *
  411. * RETURNS:
  412. * Address of newly allocated structure, 0 if storage not available.
  413. *
  414. *
  415. ***************************************************************************/
  416. LPDEVMODEW
  417. AllocateUnicodeDevMode(
  418. LPDEVMODEA pANSIDevMode
  419. )
  420. {
  421. LPDEVMODEW pUnicodeDevMode;
  422. LPBYTE p1, p2;
  423. DWORD dwSize;
  424. //
  425. // If the devmode is NULL, then return NULL -- KrishnaG
  426. //
  427. if ( !pANSIDevMode || !pANSIDevMode->dmSize ) {
  428. return NULL;
  429. }
  430. SPLASSERT(BoolFromHResult(SplIsValidDevmodeNoSizeA(pANSIDevMode)));
  431. //
  432. // Determine output structure size. This has two components: the
  433. // DEVMODEW structure size, plus any private data area. The latter
  434. // is only meaningful when a structure is passed in.
  435. //
  436. dwSize = pANSIDevMode->dmSize + pANSIDevMode->dmDriverExtra
  437. + sizeof(DEVMODEW) - sizeof(DEVMODEA);
  438. pUnicodeDevMode = (LPDEVMODEW) LocalAlloc(LPTR, dwSize);
  439. if( !pUnicodeDevMode ) {
  440. return NULL;
  441. }
  442. //
  443. // Copy dmDeviceName which is a string
  444. //
  445. if (pANSIDevMode->dmDeviceName)
  446. {
  447. AnsiToUnicodeString(pANSIDevMode->dmDeviceName,
  448. pUnicodeDevMode->dmDeviceName,
  449. ComputeMaxStrlenA(pANSIDevMode->dmDeviceName,
  450. sizeof pANSIDevMode->dmDeviceName));
  451. }
  452. //
  453. // Does the devmode we got have a dmFormName? (Windows 3.1 had
  454. // DevMode of size 40 and did not have dmFormName)
  455. //
  456. if ( (LPBYTE)pANSIDevMode + pANSIDevMode->dmSize >
  457. (LPBYTE) pANSIDevMode->dmFormName ) {
  458. //
  459. // Copy everything between dmDeviceName and dmFormName
  460. //
  461. p1 = (LPBYTE) pANSIDevMode->dmDeviceName +
  462. sizeof(pANSIDevMode->dmDeviceName);
  463. p2 = (LPBYTE) pANSIDevMode->dmFormName;
  464. CopyMemory((LPBYTE) pUnicodeDevMode->dmDeviceName +
  465. sizeof(pUnicodeDevMode->dmDeviceName),
  466. p1,
  467. p2 - p1);
  468. //
  469. // Copy dmFormName which is a string
  470. //
  471. if (pANSIDevMode->dmFormName)
  472. {
  473. AnsiToUnicodeString(pANSIDevMode->dmFormName,
  474. pUnicodeDevMode->dmFormName,
  475. ComputeMaxStrlenA(pANSIDevMode->dmFormName,
  476. sizeof pANSIDevMode->dmFormName));
  477. }
  478. //
  479. // Copy everything after dmFormName
  480. //
  481. p1 = (LPBYTE) pANSIDevMode->dmFormName +
  482. sizeof(pANSIDevMode->dmFormName);
  483. p2 = (LPBYTE) pANSIDevMode + pANSIDevMode->dmSize
  484. + pANSIDevMode->dmDriverExtra;
  485. CopyMemory((LPBYTE) pUnicodeDevMode->dmFormName +
  486. sizeof(pUnicodeDevMode->dmFormName),
  487. p1,
  488. p2 - p1);
  489. pUnicodeDevMode->dmSize = pANSIDevMode->dmSize + sizeof(DEVMODEW)
  490. - sizeof(DEVMODEA);
  491. } else {
  492. //
  493. // Copy everything after dmDeviceName
  494. //
  495. p1 = (LPBYTE) pANSIDevMode->dmDeviceName +
  496. sizeof(pANSIDevMode->dmDeviceName);
  497. p2 = (LPBYTE) pANSIDevMode + pANSIDevMode->dmSize + pANSIDevMode->dmDriverExtra;
  498. CopyMemory((LPBYTE) pUnicodeDevMode->dmDeviceName +
  499. sizeof(pUnicodeDevMode->dmDeviceName),
  500. p1,
  501. p2-p1);
  502. pUnicodeDevMode->dmSize = pANSIDevMode->dmSize
  503. + sizeof(pUnicodeDevMode->dmDeviceName)
  504. - sizeof(pANSIDevMode->dmDeviceName);
  505. }
  506. SPLASSERT(pUnicodeDevMode->dmDriverExtra == pANSIDevMode->dmDriverExtra);
  507. return pUnicodeDevMode;
  508. }
  509. /************************** Function Header ******************************
  510. * CopyAnsiDevModeFromUnicodeDevMode
  511. * Converts the UNICODE version of the DEVMODE to the ANSI version.
  512. *
  513. * RETURNS:
  514. * Nothing.
  515. *
  516. **************************************************************************/
  517. void
  518. CopyAnsiDevModeFromUnicodeDevMode(
  519. LPDEVMODEA pANSIDevMode, /* Filled in by us */
  520. LPDEVMODEW pUnicodeDevMode /* Source of data to fill above */
  521. )
  522. {
  523. LPBYTE p1, p2, pExtra;
  524. WORD dmSize, dmDriverExtra;
  525. //
  526. // NOTE: THE TWO INPUT STRUCTURES MAY BE THE SAME.
  527. //
  528. dmSize = pUnicodeDevMode->dmSize;
  529. dmDriverExtra = pUnicodeDevMode->dmDriverExtra;
  530. pExtra = (LPBYTE) pUnicodeDevMode + pUnicodeDevMode->dmSize;
  531. if (dmSize)
  532. {
  533. //
  534. // Copy dmDeviceName which is a string
  535. //
  536. UnicodeToAnsiString(pUnicodeDevMode->dmDeviceName,
  537. pANSIDevMode->dmDeviceName,
  538. ComputeMaxStrlenW(pUnicodeDevMode->dmDeviceName,
  539. sizeof pANSIDevMode->dmDeviceName));
  540. //
  541. // Does the devmode we got have a dmFormName? (Windows 3.1 had
  542. // DevMode of size 40 and did not have dmFormName)
  543. //
  544. if ( (LPBYTE)pUnicodeDevMode + dmSize >
  545. (LPBYTE) pUnicodeDevMode->dmFormName ) {
  546. //
  547. // Copy everything between dmDeviceName and dmFormName
  548. //
  549. p1 = (LPBYTE) pUnicodeDevMode->dmDeviceName +
  550. sizeof(pUnicodeDevMode->dmDeviceName);
  551. p2 = (LPBYTE) pUnicodeDevMode->dmFormName;
  552. MoveMemory((LPBYTE) pANSIDevMode->dmDeviceName +
  553. sizeof(pANSIDevMode->dmDeviceName),
  554. p1,
  555. p2 - p1);
  556. //
  557. // Copy dmFormName which is a string
  558. //
  559. UnicodeToAnsiString(pUnicodeDevMode->dmFormName,
  560. pANSIDevMode->dmFormName,
  561. ComputeMaxStrlenW(pUnicodeDevMode->dmFormName,
  562. sizeof pANSIDevMode->dmFormName));
  563. //
  564. // Copy everything after dmFormName
  565. //
  566. p1 = (LPBYTE) pUnicodeDevMode->dmFormName +
  567. sizeof(pUnicodeDevMode->dmFormName);
  568. p2 = (LPBYTE) pUnicodeDevMode + dmSize + dmDriverExtra;
  569. MoveMemory((LPBYTE) pANSIDevMode->dmFormName +
  570. sizeof(pANSIDevMode->dmFormName),
  571. p1,
  572. p2 - p1);
  573. pANSIDevMode->dmSize = dmSize + sizeof(DEVMODEA) - sizeof(DEVMODEW);
  574. } else {
  575. //
  576. // Copy everything after dmDeviceName
  577. //
  578. p1 = (LPBYTE) pUnicodeDevMode->dmDeviceName +
  579. sizeof(pUnicodeDevMode->dmDeviceName);
  580. p2 = (LPBYTE) pUnicodeDevMode + dmSize + dmDriverExtra;
  581. MoveMemory((LPBYTE) pANSIDevMode->dmDeviceName +
  582. sizeof(pANSIDevMode->dmDeviceName),
  583. p1,
  584. p2 - p1);
  585. pANSIDevMode->dmSize = dmSize + sizeof(pANSIDevMode->dmDeviceName)
  586. - sizeof(pUnicodeDevMode->dmDeviceName);
  587. }
  588. SPLASSERT(pANSIDevMode->dmDriverExtra == dmDriverExtra);
  589. }
  590. return;
  591. }
  592. BOOL
  593. ConvertAnsiDevModeToUnicodeDevmode(
  594. PDEVMODEA pAnsiDevMode,
  595. PDEVMODEW pUnicodeDevMode,
  596. DWORD dwUnicodeDevModeSize,
  597. PDWORD pcbNeeded
  598. )
  599. {
  600. PDEVMODEW pDevModeW = NULL;
  601. BOOL bRet = FALSE;
  602. if ( !pAnsiDevMode ) {
  603. SetLastError(ERROR_INVALID_PARAMETER);
  604. goto Cleanup;
  605. }
  606. SPLASSERT(BoolFromHResult(SplIsValidDevmodeNoSizeA(pAnsiDevMode)));
  607. pDevModeW = AllocateUnicodeDevMode(pAnsiDevMode);
  608. if ( !pDevModeW ) {
  609. goto Cleanup;
  610. }
  611. *pcbNeeded = pDevModeW->dmSize + pDevModeW->dmDriverExtra;
  612. if ( *pcbNeeded > dwUnicodeDevModeSize ) {
  613. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  614. goto Cleanup;
  615. }
  616. CopyMemory((LPBYTE)pUnicodeDevMode,
  617. (LPBYTE)pDevModeW,
  618. *pcbNeeded);
  619. bRet = TRUE;
  620. Cleanup:
  621. if ( pDevModeW )
  622. LocalFree(pDevModeW);
  623. return bRet;
  624. }
  625. BOOL
  626. ConvertUnicodeDevModeToAnsiDevmode(
  627. PDEVMODEW pUnicodeDevMode,
  628. PDEVMODEA pAnsiDevMode,
  629. DWORD dwAnsiDevModeSize,
  630. PDWORD pcbNeeded
  631. )
  632. {
  633. LPBYTE pDevMode = NULL;
  634. BOOL bRet = FALSE;
  635. DWORD dwSize;
  636. if ( !pUnicodeDevMode ) {
  637. SetLastError(ERROR_INVALID_PARAMETER);
  638. goto Cleanup;
  639. }
  640. dwSize = pUnicodeDevMode->dmSize + pUnicodeDevMode->dmDriverExtra;
  641. pDevMode = LocalAlloc(LPTR, dwSize);
  642. if ( !pDevMode ) {
  643. goto Cleanup;
  644. }
  645. CopyMemory(pDevMode,
  646. (LPBYTE)pUnicodeDevMode,
  647. dwSize);
  648. CopyAnsiDevModeFromUnicodeDevMode((PDEVMODEA) pDevMode,
  649. (PDEVMODEW) pDevMode);
  650. *pcbNeeded = ((PDEVMODEA)pDevMode)->dmSize + ((PDEVMODEA)pDevMode)->dmDriverExtra;
  651. if ( *pcbNeeded > dwAnsiDevModeSize ) {
  652. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  653. goto Cleanup;
  654. }
  655. CopyMemory((LPBYTE)pAnsiDevMode,
  656. pDevMode,
  657. *pcbNeeded);
  658. bRet = TRUE;
  659. Cleanup:
  660. if ( pDevMode )
  661. LocalFree(pDevMode);
  662. return bRet;
  663. }
  664. void
  665. FreeUnicodeStructure(
  666. LPBYTE pUnicodeStructure,
  667. LPDWORD pOffsets
  668. )
  669. {
  670. DWORD i=0;
  671. if ( pUnicodeStructure == NULL ) {
  672. return;
  673. }
  674. if (pOffsets) {
  675. while (pOffsets[i] != -1) {
  676. FreeUnicodeString(*(LPWSTR *)(pUnicodeStructure+pOffsets[i]));
  677. i++;
  678. }
  679. }
  680. LocalFree( pUnicodeStructure );
  681. }
  682. BOOL
  683. EnumPrintersA(
  684. DWORD Flags,
  685. LPSTR Name,
  686. DWORD Level,
  687. LPBYTE pPrinterEnum,
  688. DWORD cbBuf,
  689. LPDWORD pcbNeeded,
  690. LPDWORD pcReturned
  691. )
  692. {
  693. BOOL ReturnValue;
  694. DWORD cbStruct;
  695. DWORD *pOffsets;
  696. LPWSTR pUnicodeName;
  697. switch (Level) {
  698. case STRESSINFOLEVEL:
  699. pOffsets = PrinterInfoStressStrings;
  700. cbStruct = sizeof(PRINTER_INFO_STRESS);
  701. break;
  702. case 4:
  703. pOffsets = PrinterInfo4Strings;
  704. cbStruct = sizeof(PRINTER_INFO_4);
  705. break;
  706. case 1:
  707. pOffsets = PrinterInfo1Strings;
  708. cbStruct = sizeof(PRINTER_INFO_1);
  709. break;
  710. case 2:
  711. pOffsets = PrinterInfo2Strings;
  712. cbStruct = sizeof(PRINTER_INFO_2);
  713. break;
  714. case 5:
  715. pOffsets = PrinterInfo5Strings;
  716. cbStruct = sizeof(PRINTER_INFO_5);
  717. break;
  718. default:
  719. SetLastError(ERROR_INVALID_LEVEL);
  720. return FALSE;
  721. }
  722. pUnicodeName = AllocateUnicodeString(Name);
  723. if (Name && !pUnicodeName)
  724. return FALSE;
  725. ReturnValue = EnumPrintersW(Flags, pUnicodeName, Level, pPrinterEnum,
  726. cbBuf, pcbNeeded, pcReturned);
  727. if (ReturnValue && pPrinterEnum) {
  728. DWORD i=*pcReturned;
  729. while (i--) {
  730. ConvertUnicodeToAnsiStrings(pPrinterEnum, pOffsets);
  731. if ((Level == 2) && pPrinterEnum) {
  732. PRINTER_INFO_2 *pPrinterInfo2 = (PRINTER_INFO_2 *)pPrinterEnum;
  733. if (pPrinterInfo2->pDevMode)
  734. CopyAnsiDevModeFromUnicodeDevMode(
  735. (LPDEVMODEA)pPrinterInfo2->pDevMode,
  736. (LPDEVMODEW)pPrinterInfo2->pDevMode);
  737. }
  738. pPrinterEnum+=cbStruct;
  739. }
  740. }
  741. FreeUnicodeString(pUnicodeName);
  742. return ReturnValue;
  743. }
  744. BOOL
  745. OpenPrinterA(
  746. LPSTR pPrinterName,
  747. LPHANDLE phPrinter,
  748. LPPRINTER_DEFAULTSA pDefault
  749. )
  750. {
  751. BOOL ReturnValue = FALSE;
  752. LPWSTR pUnicodePrinterName = NULL;
  753. PRINTER_DEFAULTSW UnicodeDefaults={NULL, NULL, 0};
  754. pUnicodePrinterName = AllocateUnicodeString(pPrinterName);
  755. if (pPrinterName && !pUnicodePrinterName)
  756. goto Cleanup;
  757. if (pDefault) {
  758. UnicodeDefaults.pDatatype = AllocateUnicodeString(pDefault->pDatatype);
  759. if (pDefault->pDatatype && !UnicodeDefaults.pDatatype)
  760. goto Cleanup;
  761. //
  762. // Milestones etc. 4.5 passes in a bogus devmode in pDefaults.
  763. // Be sure to validate here.
  764. //
  765. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(pDefault->pDevMode))){
  766. UnicodeDefaults.pDevMode = AllocateUnicodeDevMode(
  767. pDefault->pDevMode );
  768. if( !UnicodeDefaults.pDevMode ){
  769. goto Cleanup;
  770. }
  771. }
  772. UnicodeDefaults.DesiredAccess = pDefault->DesiredAccess;
  773. }
  774. ReturnValue = OpenPrinterW(pUnicodePrinterName, phPrinter, &UnicodeDefaults);
  775. if (ReturnValue) {
  776. ((PSPOOL)*phPrinter)->Status |= SPOOL_STATUS_ANSI;
  777. }
  778. Cleanup:
  779. if (UnicodeDefaults.pDevMode)
  780. LocalFree(UnicodeDefaults.pDevMode);
  781. FreeUnicodeString(UnicodeDefaults.pDatatype);
  782. FreeUnicodeString(pUnicodePrinterName);
  783. return ReturnValue;
  784. }
  785. BOOL
  786. ResetPrinterA(
  787. HANDLE hPrinter,
  788. LPPRINTER_DEFAULTSA pDefault
  789. )
  790. {
  791. BOOL ReturnValue = FALSE;
  792. PRINTER_DEFAULTSW UnicodeDefaults={NULL, NULL, 0};
  793. if (pDefault) {
  794. if (pDefault->pDatatype == (LPSTR)-1) {
  795. UnicodeDefaults.pDatatype = (LPWSTR)-1;
  796. } else {
  797. UnicodeDefaults.pDatatype = AllocateUnicodeString(pDefault->pDatatype);
  798. if (pDefault->pDatatype && !UnicodeDefaults.pDatatype)
  799. return FALSE;
  800. }
  801. if (pDefault->pDevMode == (LPDEVMODEA)-1) {
  802. UnicodeDefaults.pDevMode = (LPDEVMODEW)-1;
  803. } else {
  804. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(pDefault->pDevMode))){
  805. UnicodeDefaults.pDevMode = AllocateUnicodeDevMode(
  806. pDefault->pDevMode );
  807. if( !UnicodeDefaults.pDevMode ){
  808. goto Cleanup;
  809. }
  810. }
  811. }
  812. }
  813. ReturnValue = ResetPrinterW(hPrinter, &UnicodeDefaults);
  814. if (UnicodeDefaults.pDevMode &&
  815. (UnicodeDefaults.pDevMode != (LPDEVMODEW)-1)){
  816. LocalFree(UnicodeDefaults.pDevMode);
  817. }
  818. Cleanup:
  819. if (UnicodeDefaults.pDatatype && (UnicodeDefaults.pDatatype != (LPWSTR)-1)) {
  820. FreeUnicodeString(UnicodeDefaults.pDatatype);
  821. }
  822. return ReturnValue;
  823. }
  824. BOOL
  825. SetJobA(
  826. HANDLE hPrinter,
  827. DWORD JobId,
  828. DWORD Level,
  829. LPBYTE pJob,
  830. DWORD Command
  831. )
  832. {
  833. BOOL ReturnValue=FALSE;
  834. LPBYTE pUnicodeStructure=NULL;
  835. LPDEVMODEW pDevModeW = NULL;
  836. DWORD cbStruct;
  837. DWORD *pOffsets;
  838. switch (Level) {
  839. case 0:
  840. break;
  841. case 1:
  842. pOffsets = JobInfo1Strings;
  843. cbStruct = sizeof(JOB_INFO_1);
  844. break;
  845. case 2:
  846. pOffsets = JobInfo2Strings;
  847. cbStruct = sizeof(JOB_INFO_2);
  848. break;
  849. case 3:
  850. return SetJobW( hPrinter, JobId, Level, pJob, Command );
  851. default:
  852. SetLastError(ERROR_INVALID_LEVEL);
  853. return FALSE;
  854. }
  855. if (Level) {
  856. pUnicodeStructure = AllocateUnicodeStructure(pJob, cbStruct, pOffsets);
  857. if (pJob && !pUnicodeStructure)
  858. return FALSE;
  859. }
  860. if ( Level == 2 && pUnicodeStructure && pJob ) {
  861. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(((LPJOB_INFO_2A)pJob)->pDevMode))){
  862. pDevModeW = AllocateUnicodeDevMode(((LPJOB_INFO_2A)pJob)->pDevMode);
  863. if( !pDevModeW ){
  864. ReturnValue = FALSE;
  865. goto Cleanup;
  866. }
  867. ((LPJOB_INFO_2W) pUnicodeStructure)->pDevMode = pDevModeW;
  868. }
  869. }
  870. ReturnValue = SetJobW(hPrinter, JobId, Level, pUnicodeStructure, Command);
  871. if ( pDevModeW ) {
  872. LocalFree(pDevModeW);
  873. }
  874. Cleanup:
  875. FreeUnicodeStructure(pUnicodeStructure, pOffsets);
  876. return ReturnValue;
  877. }
  878. BOOL
  879. GetJobA(
  880. HANDLE hPrinter,
  881. DWORD JobId,
  882. DWORD Level,
  883. LPBYTE pJob,
  884. DWORD cbBuf,
  885. LPDWORD pcbNeeded
  886. )
  887. {
  888. DWORD *pOffsets;
  889. switch (Level) {
  890. case 1:
  891. pOffsets = JobInfo1Strings;
  892. break;
  893. case 2:
  894. pOffsets = JobInfo2Strings;
  895. break;
  896. case 3:
  897. return GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded );
  898. default:
  899. SetLastError(ERROR_INVALID_LEVEL);
  900. return FALSE;
  901. }
  902. if (GetJob(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded)) {
  903. ConvertUnicodeToAnsiStrings(pJob, pOffsets);
  904. //
  905. // Convert the devmode in place for INFO_2.
  906. //
  907. if( Level == 2 ){
  908. PJOB_INFO_2A pJobInfo2 = (PJOB_INFO_2A)pJob;
  909. if( pJobInfo2->pDevMode ){
  910. CopyAnsiDevModeFromUnicodeDevMode(
  911. (LPDEVMODEA)pJobInfo2->pDevMode,
  912. (LPDEVMODEW)pJobInfo2->pDevMode);
  913. }
  914. }
  915. return TRUE;
  916. } else
  917. return FALSE;
  918. }
  919. BOOL
  920. EnumJobsA(
  921. HANDLE hPrinter,
  922. DWORD FirstJob,
  923. DWORD NoJobs,
  924. DWORD Level,
  925. LPBYTE pJob,
  926. DWORD cbBuf,
  927. LPDWORD pcbNeeded,
  928. LPDWORD pcReturned
  929. )
  930. {
  931. DWORD i, cbStruct, *pOffsets;
  932. switch (Level) {
  933. case 1:
  934. pOffsets = JobInfo1Strings;
  935. cbStruct = sizeof(JOB_INFO_1);
  936. break;
  937. case 2:
  938. pOffsets = JobInfo2Strings;
  939. cbStruct = sizeof(JOB_INFO_2);
  940. break;
  941. case 3:
  942. return EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned );
  943. default:
  944. SetLastError(ERROR_INVALID_LEVEL);
  945. return FALSE;
  946. }
  947. if (EnumJobsW(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded,
  948. pcReturned)) {
  949. i=*pcReturned;
  950. while (i--) {
  951. ConvertUnicodeToAnsiStrings(pJob, pOffsets);
  952. //
  953. // Convert the devmode in place for INFO_2.
  954. //
  955. if( Level == 2 ){
  956. PJOB_INFO_2A pJobInfo2 = (PJOB_INFO_2A)pJob;
  957. if( pJobInfo2->pDevMode ){
  958. CopyAnsiDevModeFromUnicodeDevMode(
  959. (LPDEVMODEA)pJobInfo2->pDevMode,
  960. (LPDEVMODEW)pJobInfo2->pDevMode);
  961. }
  962. }
  963. pJob += cbStruct;
  964. }
  965. return TRUE;
  966. } else
  967. return FALSE;
  968. }
  969. HANDLE
  970. AddPrinterA(
  971. LPSTR pName,
  972. DWORD Level,
  973. LPBYTE pPrinter
  974. )
  975. {
  976. HANDLE hPrinter = NULL;
  977. LPBYTE pUnicodeStructure = NULL;
  978. LPDEVMODEW pDevModeW = NULL;
  979. LPWSTR pUnicodeName = NULL;
  980. DWORD cbStruct;
  981. DWORD *pOffsets;
  982. switch (Level) {
  983. case 2:
  984. pOffsets = PrinterInfo2Strings;
  985. cbStruct = sizeof(PRINTER_INFO_2);
  986. break;
  987. default:
  988. SetLastError(ERROR_INVALID_LEVEL);
  989. return NULL;
  990. }
  991. if (!pPrinter) {
  992. SetLastError(ERROR_INVALID_PARAMETER);
  993. return NULL;
  994. }
  995. pUnicodeStructure = AllocateUnicodeStructure(pPrinter, cbStruct, pOffsets);
  996. if (pPrinter && !pUnicodeStructure)
  997. goto Cleanup;
  998. pUnicodeName = AllocateUnicodeString(pName);
  999. if (pName && !pUnicodeName)
  1000. goto Cleanup;
  1001. if ( pUnicodeStructure ) {
  1002. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(((LPPRINTER_INFO_2A)pPrinter)->pDevMode))){
  1003. pDevModeW = AllocateUnicodeDevMode(
  1004. ((LPPRINTER_INFO_2A)pPrinter)->pDevMode);
  1005. if( !pDevModeW ){
  1006. goto Cleanup;
  1007. }
  1008. }
  1009. ((LPPRINTER_INFO_2W)pUnicodeStructure)->pDevMode = pDevModeW;
  1010. hPrinter = AddPrinterW(pUnicodeName, Level, pUnicodeStructure);
  1011. }
  1012. Cleanup:
  1013. FreeUnicodeString( pUnicodeName );
  1014. if ( pDevModeW ) {
  1015. LocalFree(pDevModeW);
  1016. }
  1017. FreeUnicodeStructure( pUnicodeStructure, pOffsets );
  1018. return hPrinter;
  1019. }
  1020. BOOL
  1021. AddPrinterConnectionA(
  1022. LPSTR pName
  1023. )
  1024. {
  1025. BOOL rc;
  1026. LPWSTR pUnicodeName;
  1027. pUnicodeName = AllocateUnicodeString(pName);
  1028. if (pName && !pUnicodeName)
  1029. return FALSE;
  1030. rc = AddPrinterConnectionW(pUnicodeName);
  1031. FreeUnicodeString(pUnicodeName);
  1032. return rc;
  1033. }
  1034. BOOL
  1035. DeletePrinterConnectionA(
  1036. LPSTR pName
  1037. )
  1038. {
  1039. BOOL rc;
  1040. LPWSTR pUnicodeName;
  1041. pUnicodeName = AllocateUnicodeString(pName);
  1042. if (pName && !pUnicodeName)
  1043. return FALSE;
  1044. rc = DeletePrinterConnectionW(pUnicodeName);
  1045. FreeUnicodeString(pUnicodeName);
  1046. return rc;
  1047. }
  1048. BOOL
  1049. SetPrinterA(
  1050. HANDLE hPrinter,
  1051. DWORD Level,
  1052. LPBYTE pPrinter,
  1053. DWORD Command
  1054. )
  1055. {
  1056. LPBYTE pUnicodeStructure; /* Unicode version of input data */
  1057. DWORD cbStruct; /* Size of the output structure */
  1058. DWORD *pOffsets; /* -1 terminated list of addresses */
  1059. DWORD ReturnValue=FALSE;
  1060. //
  1061. // For APP compat. Win9x handled this
  1062. //
  1063. if (eProtectHandle(hPrinter, FALSE))
  1064. {
  1065. return FALSE;
  1066. }
  1067. switch (Level) {
  1068. case 0:
  1069. //
  1070. // This could be 2 cases. STRESSINFOLEVEL, or the real 0 level.
  1071. // If Command is 0 then it is STRESSINFOLEVEL, else real 0 level
  1072. //
  1073. if ( !Command ) {
  1074. pOffsets = PrinterInfoStressStrings;
  1075. cbStruct = sizeof( PRINTER_INFO_STRESS );
  1076. }
  1077. break;
  1078. case 1:
  1079. pOffsets = PrinterInfo1Strings;
  1080. cbStruct = sizeof( PRINTER_INFO_1 );
  1081. break;
  1082. case 2:
  1083. pOffsets = PrinterInfo2Strings;
  1084. cbStruct = sizeof( PRINTER_INFO_2 );
  1085. break;
  1086. case 3:
  1087. pOffsets = PrinterInfo3Strings;
  1088. cbStruct = sizeof( PRINTER_INFO_3 );
  1089. break;
  1090. case 4:
  1091. pOffsets = PrinterInfo4Strings;
  1092. cbStruct = sizeof( PRINTER_INFO_4 );
  1093. break;
  1094. case 5:
  1095. pOffsets = PrinterInfo5Strings;
  1096. cbStruct = sizeof( PRINTER_INFO_5 );
  1097. break;
  1098. case 6:
  1099. break;
  1100. case 7:
  1101. pOffsets = PrinterInfo7Strings;
  1102. cbStruct = sizeof( PRINTER_INFO_7 );
  1103. break;
  1104. case 8:
  1105. pOffsets = PrinterInfo8Strings;
  1106. cbStruct = sizeof( PRINTER_INFO_8 );
  1107. break;
  1108. case 9:
  1109. pOffsets = PrinterInfo9Strings;
  1110. cbStruct = sizeof( PRINTER_INFO_9 );
  1111. break;
  1112. default:
  1113. SetLastError( ERROR_INVALID_LEVEL );
  1114. goto Done;
  1115. }
  1116. //
  1117. // The structure needs to have its CONTENTS converted from
  1118. // ANSI to Unicode. The above switch() statement filled in
  1119. // the two important pieces of information needed to accomplish
  1120. // this goal. First is the size of the structure, second is
  1121. // a list of the offset within the structure to UNICODE
  1122. // string pointers. The AllocateUnicodeStructure() call will
  1123. // allocate a wide version of the structure, copy its contents
  1124. // and convert the strings to Unicode as it goes. That leaves
  1125. // us to deal with any other pieces needing conversion.
  1126. //
  1127. //
  1128. // If Level == 0 and Command != 0 then pPrinter is a DWORD
  1129. //
  1130. if ( Level == 6 || (!Level && Command) ) {
  1131. if ( Level == 6 || Command == PRINTER_CONTROL_SET_STATUS )
  1132. pUnicodeStructure = pPrinter;
  1133. else
  1134. pUnicodeStructure = NULL;
  1135. } else {
  1136. pUnicodeStructure = AllocateUnicodeStructure(pPrinter, cbStruct, pOffsets);
  1137. if (pPrinter && !pUnicodeStructure)
  1138. {
  1139. goto Done;
  1140. }
  1141. }
  1142. #define pPrinterInfo2W ((LPPRINTER_INFO_2W)pUnicodeStructure)
  1143. #define pPrinterInfo2A ((LPPRINTER_INFO_2A)pPrinter)
  1144. //
  1145. // The Level 2 structure has a DEVMODE struct in it: convert now
  1146. //
  1147. if ( Level == 2 &&
  1148. pPrinterInfo2A &&
  1149. pPrinterInfo2A->pDevMode ) {
  1150. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(pPrinterInfo2A->pDevMode))){
  1151. pPrinterInfo2W->pDevMode = AllocateUnicodeDevMode(
  1152. pPrinterInfo2A->pDevMode );
  1153. if( !pPrinterInfo2W->pDevMode)
  1154. {
  1155. FreeUnicodeStructure(pUnicodeStructure, pOffsets);
  1156. goto Done;
  1157. }
  1158. }
  1159. }
  1160. #define pPrinterInfo8W ((LPPRINTER_INFO_8W)pUnicodeStructure)
  1161. #define pPrinterInfo8A ((LPPRINTER_INFO_8A)pPrinter)
  1162. if (( Level == 8 || Level == 9 ) &&
  1163. pPrinterInfo8A &&
  1164. pPrinterInfo8A->pDevMode ) {
  1165. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(pPrinterInfo8A->pDevMode))){
  1166. pPrinterInfo8W->pDevMode = AllocateUnicodeDevMode(
  1167. pPrinterInfo8A->pDevMode );
  1168. if( !pPrinterInfo8W->pDevMode)
  1169. {
  1170. FreeUnicodeStructure(pUnicodeStructure, pOffsets);
  1171. goto Done;
  1172. }
  1173. }
  1174. }
  1175. ReturnValue = SetPrinterW( hPrinter, Level, pUnicodeStructure, Command );
  1176. //
  1177. // Free the DEVMODE we allocated (if we did!), then the
  1178. // the Unicode structure and its contents.
  1179. //
  1180. if (Level == 2 &&
  1181. pPrinterInfo2W &&
  1182. pPrinterInfo2W->pDevMode ) {
  1183. LocalFree( pPrinterInfo2W->pDevMode );
  1184. }
  1185. if ((Level == 8 || Level == 9) &&
  1186. pUnicodeStructure &&
  1187. pPrinterInfo8W->pDevMode ) {
  1188. LocalFree( pPrinterInfo8W->pDevMode );
  1189. }
  1190. //
  1191. // STRESS_INFO and Levels 1-5
  1192. //
  1193. if ( Level != 6 && (Level || !Command) )
  1194. FreeUnicodeStructure( pUnicodeStructure, pOffsets );
  1195. #undef pPrinterInfo2W
  1196. #undef pPrinterInfo2A
  1197. Done:
  1198. vUnprotectHandle(hPrinter);
  1199. return ReturnValue;
  1200. }
  1201. BOOL
  1202. GetPrinterA(
  1203. HANDLE hPrinter,
  1204. DWORD Level,
  1205. LPBYTE pPrinter,
  1206. DWORD cbBuf,
  1207. LPDWORD pcbNeeded
  1208. )
  1209. {
  1210. DWORD *pOffsets;
  1211. switch (Level) {
  1212. case STRESSINFOLEVEL:
  1213. pOffsets = PrinterInfoStressOffsets;
  1214. break;
  1215. case 1:
  1216. pOffsets = PrinterInfo1Strings;
  1217. break;
  1218. case 2:
  1219. pOffsets = PrinterInfo2Strings;
  1220. break;
  1221. case 3:
  1222. pOffsets = PrinterInfo3Strings;
  1223. break;
  1224. case 4:
  1225. pOffsets = PrinterInfo4Strings;
  1226. break;
  1227. case 5:
  1228. pOffsets = PrinterInfo5Strings;
  1229. break;
  1230. case 6:
  1231. pOffsets = PrinterInfo6Strings;
  1232. break;
  1233. case 7:
  1234. pOffsets = PrinterInfo7Strings;
  1235. break;
  1236. case 8:
  1237. pOffsets = PrinterInfo8Strings;
  1238. break;
  1239. case 9:
  1240. pOffsets = PrinterInfo9Strings;
  1241. break;
  1242. default:
  1243. SetLastError(ERROR_INVALID_LEVEL);
  1244. return FALSE;
  1245. }
  1246. if (GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) {
  1247. if (pPrinter) {
  1248. ConvertUnicodeToAnsiStrings(pPrinter, pOffsets);
  1249. if ((Level == 2) && pPrinter) {
  1250. PRINTER_INFO_2 *pPrinterInfo2 = (PRINTER_INFO_2 *)pPrinter;
  1251. if (pPrinterInfo2->pDevMode)
  1252. CopyAnsiDevModeFromUnicodeDevMode(
  1253. (LPDEVMODEA)pPrinterInfo2->pDevMode,
  1254. (LPDEVMODEW)pPrinterInfo2->pDevMode);
  1255. }
  1256. if ((Level == 8 || Level == 9) && pPrinter) {
  1257. PRINTER_INFO_8 *pPrinterInfo8 = (PRINTER_INFO_8 *)pPrinter;
  1258. if (pPrinterInfo8->pDevMode)
  1259. CopyAnsiDevModeFromUnicodeDevMode(
  1260. (LPDEVMODEA)pPrinterInfo8->pDevMode,
  1261. (LPDEVMODEW)pPrinterInfo8->pDevMode);
  1262. }
  1263. }
  1264. return TRUE;
  1265. }
  1266. return FALSE;
  1267. }
  1268. BOOL
  1269. UnicodeToAnsiMultiSz(
  1270. LPWSTR pUnicodeDependentFiles
  1271. )
  1272. {
  1273. LPWSTR pAlignedUnicodeStr = NULL;
  1274. LPWSTR pUnicodeStr;
  1275. DWORD StringLength, rc;
  1276. DWORD Index;
  1277. BOOL bReturn = FALSE;
  1278. //
  1279. // Conversion in place
  1280. //
  1281. if (!(pUnicodeDependentFiles) || !*pUnicodeDependentFiles) {
  1282. bReturn = TRUE;
  1283. } else {
  1284. if ((ULONG_PTR)pUnicodeDependentFiles != (((ULONG_PTR) (pUnicodeDependentFiles) + (sizeof(WCHAR) - 1))&~(sizeof(WCHAR) - 1))) {
  1285. //
  1286. // Calculate the length of the unaligned multisz string
  1287. //
  1288. for (StringLength = 0;
  1289. !( ((LPSTR)pUnicodeDependentFiles)[StringLength] == '\0' &&
  1290. ((LPSTR)pUnicodeDependentFiles)[StringLength + 1] == '\0' &&
  1291. ((LPSTR)pUnicodeDependentFiles)[StringLength + 2] == '\0' &&
  1292. ((LPSTR)pUnicodeDependentFiles)[StringLength + 3] == '\0' );
  1293. StringLength += 2)
  1294. ;
  1295. StringLength /= 2;
  1296. //
  1297. // Include NULL terminator for last string and NULL terminator for MULTI SZ
  1298. //
  1299. StringLength +=2;
  1300. } else {
  1301. //
  1302. // The string is WCHAR aligned.
  1303. //
  1304. pUnicodeStr = pUnicodeDependentFiles;
  1305. while ( *pUnicodeStr ) {
  1306. pUnicodeStr += wcslen(pUnicodeStr) + 1;
  1307. }
  1308. StringLength = (DWORD) (pUnicodeStr - pUnicodeDependentFiles + 1);
  1309. }
  1310. //
  1311. // Since WideCharToMultiByte doesn't do in place conversion,
  1312. // duplicate the pUnicodeDependentFiles regardless if it is aligned or not.
  1313. //
  1314. if (pAlignedUnicodeStr = LocalAlloc(LPTR, StringLength * sizeof(char) * 2)) {
  1315. memcpy( pAlignedUnicodeStr, pUnicodeDependentFiles, StringLength * sizeof(char)* 2);
  1316. rc = WideCharToMultiByte(CP_THREAD_ACP,
  1317. 0,
  1318. pAlignedUnicodeStr,
  1319. StringLength,
  1320. (LPSTR)pUnicodeDependentFiles,
  1321. StringLength * 2,
  1322. NULL, NULL );
  1323. LocalFree( pAlignedUnicodeStr );
  1324. bReturn = rc > 0;
  1325. }
  1326. }
  1327. return bReturn;
  1328. }
  1329. BOOL
  1330. AnsiToUnicodeMultiSz(
  1331. LPSTR pAnsiDependentFiles,
  1332. LPWSTR *pUnicodeDependentFiles
  1333. )
  1334. {
  1335. LPWSTR pUnicodeStr;
  1336. LPSTR pAnsiStr;
  1337. DWORD len, rc;
  1338. if ( ! (pAnsiStr = pAnsiDependentFiles) || !*pAnsiStr ) {
  1339. *pUnicodeDependentFiles = NULL;
  1340. return TRUE;
  1341. }
  1342. while ( *pAnsiStr )
  1343. pAnsiStr += strlen(pAnsiStr) + 1;
  1344. len = (DWORD) (pAnsiStr - pAnsiDependentFiles + 1);
  1345. if ( !(*pUnicodeDependentFiles = LocalAlloc(LPTR, len * sizeof(WCHAR))) ) {
  1346. return FALSE;
  1347. }
  1348. AnsiToUnicodeString(pAnsiDependentFiles, *pUnicodeDependentFiles, len-1);
  1349. return TRUE;
  1350. }
  1351. BOOL
  1352. AddPrinterDriverExA(
  1353. LPSTR pName,
  1354. DWORD Level,
  1355. PBYTE pPrinter,
  1356. DWORD dwFileCopyFlags
  1357. )
  1358. {
  1359. BOOL ReturnValue=FALSE;
  1360. DWORD cbStruct;
  1361. LPWSTR pUnicodeName = NULL;
  1362. LPBYTE pUnicodeStructure = NULL;
  1363. LPDWORD pOffsets;
  1364. switch (Level) {
  1365. case 2:
  1366. pOffsets = DriverInfo2Strings;
  1367. cbStruct = sizeof(DRIVER_INFO_2);
  1368. break;
  1369. case 3:
  1370. pOffsets = DriverInfo3Strings;
  1371. cbStruct = sizeof(DRIVER_INFO_3);
  1372. break;
  1373. case 4:
  1374. pOffsets = DriverInfo4Strings;
  1375. cbStruct = sizeof(DRIVER_INFO_4);
  1376. break;
  1377. case 6:
  1378. pOffsets = DriverInfo6Strings;
  1379. cbStruct = sizeof(DRIVER_INFO_6);
  1380. break;
  1381. default:
  1382. SetLastError(ERROR_INVALID_LEVEL);
  1383. return FALSE;
  1384. }
  1385. if (!pPrinter) {
  1386. SetLastError (ERROR_INVALID_PARAMETER);
  1387. return FALSE;
  1388. }
  1389. pUnicodeStructure = AllocateUnicodeStructure(pPrinter, cbStruct, pOffsets);
  1390. if (pPrinter && !pUnicodeStructure)
  1391. goto Error;
  1392. pUnicodeName = AllocateUnicodeString(pName);
  1393. if (pName && !pUnicodeName)
  1394. goto Error;
  1395. //
  1396. // Handle dependent files which is upto \0\0
  1397. //
  1398. if ( ( Level == 3 || Level == 4 || Level ==6 ) &&
  1399. !AnsiToUnicodeMultiSz(
  1400. (LPSTR) ((PDRIVER_INFO_3A)pPrinter)->pDependentFiles,
  1401. &(((PDRIVER_INFO_3W)pUnicodeStructure)->pDependentFiles)) ) {
  1402. goto Error;
  1403. }
  1404. //
  1405. // Handle pszzPreviousNames which is upto \0\0
  1406. //
  1407. if ( ( Level == 4 || Level == 6 ) &&
  1408. !AnsiToUnicodeMultiSz(
  1409. (LPSTR) ((PDRIVER_INFO_4A)pPrinter)->pszzPreviousNames,
  1410. &(((PDRIVER_INFO_4W)pUnicodeStructure)->pszzPreviousNames)) ) {
  1411. goto Error;
  1412. }
  1413. ReturnValue = AddPrinterDriverExW(pUnicodeName, Level, pUnicodeStructure,dwFileCopyFlags);
  1414. if ( ( Level == 3 || Level == 4 || Level == 6) &&
  1415. ((PDRIVER_INFO_3W)pUnicodeStructure)->pDependentFiles ) {
  1416. LocalFree(((PDRIVER_INFO_3W)pUnicodeStructure)->pDependentFiles);
  1417. }
  1418. if ( (Level == 4 || Level == 6 )&&
  1419. (((PDRIVER_INFO_4)pUnicodeStructure)->pszzPreviousNames) )
  1420. LocalFree(((PDRIVER_INFO_4)pUnicodeStructure)->pszzPreviousNames);
  1421. Error:
  1422. FreeUnicodeStructure( pUnicodeStructure, pOffsets );
  1423. FreeUnicodeString(pUnicodeName);
  1424. return ReturnValue;
  1425. }
  1426. BOOL
  1427. AddPrinterDriverA(
  1428. LPSTR pName,
  1429. DWORD Level,
  1430. PBYTE pPrinter
  1431. )
  1432. {
  1433. return AddPrinterDriverExA(pName, Level, pPrinter, APD_COPY_NEW_FILES);
  1434. }
  1435. BOOL
  1436. EnumPrinterDriversA(
  1437. LPSTR pName,
  1438. LPSTR pEnvironment,
  1439. DWORD Level,
  1440. LPBYTE pDriverInfo,
  1441. DWORD cbBuf,
  1442. LPDWORD pcbNeeded,
  1443. LPDWORD pcReturned
  1444. )
  1445. {
  1446. BOOL ReturnValue=FALSE;
  1447. DWORD cbStruct;
  1448. DWORD *pOffsets;
  1449. LPWSTR pUnicodeName = NULL;
  1450. LPWSTR pUnicodeEnvironment = NULL;
  1451. switch (Level) {
  1452. case 1:
  1453. pOffsets = DriverInfo1Strings;
  1454. cbStruct = sizeof(DRIVER_INFO_1);
  1455. break;
  1456. case 2:
  1457. pOffsets = DriverInfo2Strings;
  1458. cbStruct = sizeof(DRIVER_INFO_2);
  1459. break;
  1460. case 3:
  1461. pOffsets = DriverInfo3Strings;
  1462. cbStruct = sizeof(DRIVER_INFO_3);
  1463. break;
  1464. case 4:
  1465. pOffsets = DriverInfo4Strings;
  1466. cbStruct = sizeof(DRIVER_INFO_4);
  1467. break;
  1468. case 5:
  1469. pOffsets = DriverInfo5Strings;
  1470. cbStruct = sizeof(DRIVER_INFO_5);
  1471. break;
  1472. case 6:
  1473. pOffsets = DriverInfo6Strings;
  1474. cbStruct = sizeof(DRIVER_INFO_6);
  1475. break;
  1476. default:
  1477. SetLastError(ERROR_INVALID_LEVEL);
  1478. return FALSE;
  1479. }
  1480. pUnicodeName = AllocateUnicodeString(pName);
  1481. if (pName && !pUnicodeName)
  1482. goto Cleanup;
  1483. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1484. if (pEnvironment && !pUnicodeEnvironment)
  1485. goto Cleanup;
  1486. if (ReturnValue = EnumPrinterDriversW(pUnicodeName, pUnicodeEnvironment,
  1487. Level, pDriverInfo, cbBuf,
  1488. pcbNeeded, pcReturned)) {
  1489. if (pDriverInfo) {
  1490. DWORD i=*pcReturned;
  1491. while (i--) {
  1492. ConvertUnicodeToAnsiStrings(pDriverInfo, pOffsets);
  1493. if ( ( Level == 3 || Level == 4 || Level == 6) &&
  1494. !UnicodeToAnsiMultiSz(
  1495. ((PDRIVER_INFO_3) pDriverInfo)->pDependentFiles) )
  1496. ReturnValue = FALSE;
  1497. if ( ( Level == 4 || Level == 6 ) &&
  1498. !UnicodeToAnsiMultiSz(
  1499. ((PDRIVER_INFO_4) pDriverInfo)->pszzPreviousNames) )
  1500. ReturnValue = FALSE;
  1501. pDriverInfo+=cbStruct;
  1502. }
  1503. }
  1504. }
  1505. Cleanup:
  1506. FreeUnicodeString(pUnicodeEnvironment);
  1507. FreeUnicodeString(pUnicodeName);
  1508. return ReturnValue;
  1509. }
  1510. BOOL
  1511. GetPrinterDriverA(
  1512. HANDLE hPrinter,
  1513. LPSTR pEnvironment,
  1514. DWORD Level,
  1515. LPBYTE pDriverInfo,
  1516. DWORD cbBuf,
  1517. LPDWORD pcbNeeded
  1518. )
  1519. {
  1520. DWORD *pOffsets;
  1521. LPWSTR pUnicodeEnvironment = NULL;
  1522. BOOL ReturnValue;
  1523. switch (Level) {
  1524. case 1:
  1525. pOffsets = DriverInfo1Strings;
  1526. break;
  1527. case 2:
  1528. pOffsets = DriverInfo2Strings;
  1529. break;
  1530. case 3:
  1531. pOffsets = DriverInfo3Strings;
  1532. break;
  1533. case 4:
  1534. pOffsets = DriverInfo4Strings;
  1535. break;
  1536. case 5:
  1537. pOffsets = DriverInfo5Strings;
  1538. break;
  1539. case 6:
  1540. pOffsets = DriverInfo6Strings;
  1541. break;
  1542. default:
  1543. SetLastError(ERROR_INVALID_LEVEL);
  1544. return FALSE;
  1545. }
  1546. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1547. if (pEnvironment && !pUnicodeEnvironment)
  1548. return FALSE;
  1549. if (ReturnValue = GetPrinterDriverW(hPrinter, pUnicodeEnvironment, Level,
  1550. pDriverInfo, cbBuf, pcbNeeded)) {
  1551. if (pDriverInfo) {
  1552. ConvertUnicodeToAnsiStrings(pDriverInfo, pOffsets);
  1553. if ( ( Level == 3 || Level == 4 || Level == 6) &&
  1554. !UnicodeToAnsiMultiSz(
  1555. ((PDRIVER_INFO_3)pDriverInfo)->pDependentFiles) ) {
  1556. ReturnValue = FALSE;
  1557. }
  1558. if ( ( Level == 4 || Level == 6 ) &&
  1559. !UnicodeToAnsiMultiSz(
  1560. ((PDRIVER_INFO_4)pDriverInfo)->pszzPreviousNames) ) {
  1561. ReturnValue = FALSE;
  1562. }
  1563. }
  1564. }
  1565. //
  1566. // If called to get the size of buffer it will return the size of a W structure and strings
  1567. // rather than the A version. also see enum
  1568. // This cannot cause any harm since we are only allocating more memory than we need.
  1569. //
  1570. FreeUnicodeString(pUnicodeEnvironment);
  1571. return ReturnValue;
  1572. }
  1573. BOOL
  1574. GetPrinterDriverDirectoryA(
  1575. LPSTR pName,
  1576. LPSTR pEnvironment,
  1577. DWORD Level,
  1578. LPBYTE pDriverDirectory,
  1579. DWORD cbBuf,
  1580. LPDWORD pcbNeeded
  1581. )
  1582. {
  1583. DWORD *pOffsets;
  1584. LPWSTR pUnicodeEnvironment = NULL;
  1585. LPWSTR pUnicodeName = NULL;
  1586. LPWSTR pDriverDirectoryW = NULL;
  1587. BOOL ReturnValue = FALSE;
  1588. DWORD Offsets[]={0,(DWORD)-1};
  1589. switch (Level) {
  1590. case 1:
  1591. pOffsets = DriverInfo1Offsets;
  1592. break;
  1593. default:
  1594. SetLastError(ERROR_INVALID_LEVEL);
  1595. return FALSE;
  1596. }
  1597. pUnicodeName = AllocateUnicodeString(pName);
  1598. if (pName && !pUnicodeName)
  1599. goto Cleanup;
  1600. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1601. if (pEnvironment && !pUnicodeEnvironment)
  1602. goto Cleanup;
  1603. if (ReturnValue = GetPrinterDriverDirectoryW(pUnicodeName,
  1604. pUnicodeEnvironment, Level,
  1605. pDriverDirectory,
  1606. cbBuf, pcbNeeded)) {
  1607. if (pDriverDirectory) {
  1608. UnicodeToAnsiString((LPWSTR)pDriverDirectory, pDriverDirectory, NULL_TERMINATED);
  1609. }
  1610. }
  1611. Cleanup:
  1612. FreeUnicodeString(pUnicodeEnvironment);
  1613. FreeUnicodeString(pUnicodeName);
  1614. return ReturnValue;
  1615. }
  1616. BOOL
  1617. DeletePrinterDriverExA(
  1618. LPSTR pName,
  1619. LPSTR pEnvironment,
  1620. LPSTR pDriverName,
  1621. DWORD dwDeleteFlag,
  1622. DWORD dwVersionNum
  1623. )
  1624. {
  1625. LPWSTR pUnicodeName = NULL;
  1626. LPWSTR pUnicodeEnvironment = NULL;
  1627. LPWSTR pUnicodeDriverName = NULL;
  1628. BOOL rc = FALSE;
  1629. pUnicodeName = AllocateUnicodeString(pName);
  1630. if (pName && !pUnicodeName)
  1631. goto Cleanup;
  1632. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1633. if (pEnvironment && !pUnicodeEnvironment)
  1634. goto Cleanup;
  1635. pUnicodeDriverName = AllocateUnicodeString(pDriverName);
  1636. if (pDriverName && !pUnicodeDriverName)
  1637. goto Cleanup;
  1638. rc = DeletePrinterDriverExW(pUnicodeName,
  1639. pUnicodeEnvironment,
  1640. pUnicodeDriverName,
  1641. dwDeleteFlag,
  1642. dwVersionNum);
  1643. Cleanup:
  1644. FreeUnicodeString(pUnicodeName);
  1645. FreeUnicodeString(pUnicodeEnvironment);
  1646. FreeUnicodeString(pUnicodeDriverName);
  1647. return rc;
  1648. }
  1649. BOOL
  1650. DeletePrinterDriverA(
  1651. LPSTR pName,
  1652. LPSTR pEnvironment,
  1653. LPSTR pDriverName
  1654. )
  1655. {
  1656. LPWSTR pUnicodeName = NULL;
  1657. LPWSTR pUnicodeEnvironment = NULL;
  1658. LPWSTR pUnicodeDriverName = NULL;
  1659. BOOL rc = FALSE;
  1660. pUnicodeName = AllocateUnicodeString(pName);
  1661. if (pName && !pUnicodeName)
  1662. goto Cleanup;
  1663. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1664. if (pEnvironment && !pUnicodeEnvironment)
  1665. goto Cleanup;
  1666. pUnicodeDriverName = AllocateUnicodeString(pDriverName);
  1667. if (pDriverName && !pUnicodeDriverName)
  1668. goto Cleanup;
  1669. rc = DeletePrinterDriverW(pUnicodeName,
  1670. pUnicodeEnvironment,
  1671. pUnicodeDriverName);
  1672. Cleanup:
  1673. FreeUnicodeString(pUnicodeName);
  1674. FreeUnicodeString(pUnicodeEnvironment);
  1675. FreeUnicodeString(pUnicodeDriverName);
  1676. return rc;
  1677. }
  1678. BOOL
  1679. AddPerMachineConnectionA(
  1680. LPCSTR pServer,
  1681. LPCSTR pPrinterName,
  1682. LPCSTR pPrintServer,
  1683. LPCSTR pProvider
  1684. )
  1685. {
  1686. LPWSTR pUnicodeServer = NULL;
  1687. LPWSTR pUnicodePrinterName = NULL;
  1688. LPWSTR pUnicodePrintServer = NULL;
  1689. LPWSTR pUnicodeProvider = NULL;
  1690. BOOL rc = FALSE;
  1691. pUnicodeServer = AllocateUnicodeString((LPSTR)pServer);
  1692. if (pServer && !pUnicodeServer)
  1693. goto Cleanup;
  1694. pUnicodePrinterName = AllocateUnicodeString((LPSTR)pPrinterName);
  1695. if (pPrinterName && !pUnicodePrinterName)
  1696. goto Cleanup;
  1697. pUnicodePrintServer = AllocateUnicodeString((LPSTR)pPrintServer);
  1698. if (pPrintServer && !pUnicodePrintServer)
  1699. goto Cleanup;
  1700. pUnicodeProvider = AllocateUnicodeString((LPSTR)pProvider);
  1701. if (pProvider && !pUnicodeProvider)
  1702. goto Cleanup;
  1703. rc = AddPerMachineConnectionW((LPCWSTR) pUnicodeServer,
  1704. (LPCWSTR) pUnicodePrinterName,
  1705. (LPCWSTR) pUnicodePrintServer,
  1706. (LPCWSTR) pUnicodeProvider);
  1707. Cleanup:
  1708. FreeUnicodeString(pUnicodeServer);
  1709. FreeUnicodeString(pUnicodePrinterName);
  1710. FreeUnicodeString(pUnicodePrintServer);
  1711. FreeUnicodeString(pUnicodeProvider);
  1712. return rc;
  1713. }
  1714. BOOL
  1715. DeletePerMachineConnectionA(
  1716. LPCSTR pServer,
  1717. LPCSTR pPrinterName
  1718. )
  1719. {
  1720. LPWSTR pUnicodeServer = NULL;
  1721. LPWSTR pUnicodePrinterName = NULL;
  1722. BOOL rc = FALSE;
  1723. pUnicodeServer = AllocateUnicodeString((LPSTR)pServer);
  1724. if (pServer && !pUnicodeServer)
  1725. goto Cleanup;
  1726. pUnicodePrinterName = AllocateUnicodeString((LPSTR)pPrinterName);
  1727. if (pPrinterName && !pUnicodePrinterName)
  1728. goto Cleanup;
  1729. rc = DeletePerMachineConnectionW((LPCWSTR) pUnicodeServer,
  1730. (LPCWSTR) pUnicodePrinterName);
  1731. Cleanup:
  1732. FreeUnicodeString(pUnicodeServer);
  1733. FreeUnicodeString(pUnicodePrinterName);
  1734. return rc;
  1735. }
  1736. BOOL
  1737. EnumPerMachineConnectionsA(
  1738. LPCSTR pServer,
  1739. LPBYTE pPrinterEnum,
  1740. DWORD cbBuf,
  1741. LPDWORD pcbNeeded,
  1742. LPDWORD pcReturned
  1743. )
  1744. {
  1745. BOOL ReturnValue=FALSE;
  1746. DWORD cbStruct,index;
  1747. DWORD *pOffsets;
  1748. LPWSTR pUnicodeServer = NULL;
  1749. pOffsets = PrinterInfo4Strings;
  1750. cbStruct = sizeof(PRINTER_INFO_4);
  1751. pUnicodeServer = AllocateUnicodeString((LPSTR)pServer);
  1752. if (pServer && !pUnicodeServer)
  1753. goto Cleanup;
  1754. ReturnValue = EnumPerMachineConnectionsW((LPCWSTR) pUnicodeServer,
  1755. pPrinterEnum,
  1756. cbBuf,
  1757. pcbNeeded,
  1758. pcReturned);
  1759. if (ReturnValue && pPrinterEnum) {
  1760. index=*pcReturned;
  1761. while (index--) {
  1762. ConvertUnicodeToAnsiStrings(pPrinterEnum, pOffsets);
  1763. pPrinterEnum+=cbStruct;
  1764. }
  1765. }
  1766. Cleanup:
  1767. FreeUnicodeString(pUnicodeServer);
  1768. return ReturnValue;
  1769. }
  1770. BOOL
  1771. AddPrintProcessorA(
  1772. LPSTR pName,
  1773. LPSTR pEnvironment,
  1774. LPSTR pPathName,
  1775. LPSTR pPrintProcessorName
  1776. )
  1777. {
  1778. BOOL ReturnValue=FALSE;
  1779. LPWSTR pUnicodeName = NULL;
  1780. LPWSTR pUnicodeEnvironment = NULL;
  1781. LPWSTR pUnicodePathName = NULL;
  1782. LPWSTR pUnicodePrintProcessorName = NULL;
  1783. if (!pPathName || !*pPathName) {
  1784. SetLastError(ERROR_INVALID_PARAMETER);
  1785. return FALSE;
  1786. }
  1787. if (!pPrintProcessorName || !*pPrintProcessorName) {
  1788. SetLastError(ERROR_INVALID_PARAMETER);
  1789. return FALSE;
  1790. }
  1791. pUnicodeName = AllocateUnicodeString(pName);
  1792. if (pName && !pUnicodeName)
  1793. goto Cleanup;
  1794. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1795. if (pEnvironment && !pUnicodeEnvironment)
  1796. goto Cleanup;
  1797. pUnicodePathName = AllocateUnicodeString(pPathName);
  1798. if (pPathName && !pUnicodePathName)
  1799. goto Cleanup;
  1800. pUnicodePrintProcessorName = AllocateUnicodeString(pPrintProcessorName);
  1801. if (pPrintProcessorName && !pUnicodePrintProcessorName)
  1802. goto Cleanup;
  1803. if (pUnicodePathName && pUnicodePrintProcessorName) {
  1804. ReturnValue = AddPrintProcessorW(pUnicodeName, pUnicodeEnvironment,
  1805. pUnicodePathName,
  1806. pUnicodePrintProcessorName);
  1807. }
  1808. Cleanup:
  1809. FreeUnicodeString(pUnicodeName);
  1810. FreeUnicodeString(pUnicodeEnvironment);
  1811. FreeUnicodeString(pUnicodePathName);
  1812. FreeUnicodeString(pUnicodePrintProcessorName);
  1813. return ReturnValue;
  1814. }
  1815. BOOL
  1816. EnumPrintProcessorsA(
  1817. LPSTR pName,
  1818. LPSTR pEnvironment,
  1819. DWORD Level,
  1820. LPBYTE pPrintProcessorInfo,
  1821. DWORD cbBuf,
  1822. LPDWORD pcbNeeded,
  1823. LPDWORD pcReturned
  1824. )
  1825. {
  1826. BOOL ReturnValue=FALSE;
  1827. DWORD cbStruct;
  1828. DWORD *pOffsets;
  1829. LPWSTR pUnicodeName = NULL;
  1830. LPWSTR pUnicodeEnvironment = NULL;
  1831. switch (Level) {
  1832. case 1:
  1833. pOffsets = PrintProcessorInfo1Strings;
  1834. cbStruct = sizeof(PRINTPROCESSOR_INFO_1);
  1835. break;
  1836. default:
  1837. SetLastError(ERROR_INVALID_LEVEL);
  1838. return FALSE;
  1839. }
  1840. pUnicodeName = AllocateUnicodeString(pName);
  1841. if (pName && !pUnicodeName)
  1842. goto Cleanup;
  1843. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1844. if (pEnvironment && !pUnicodeEnvironment)
  1845. goto Cleanup;
  1846. if (ReturnValue = EnumPrintProcessorsW(pUnicodeName,
  1847. pUnicodeEnvironment, Level,
  1848. pPrintProcessorInfo, cbBuf,
  1849. pcbNeeded, pcReturned)) {
  1850. if (pPrintProcessorInfo) {
  1851. DWORD i=*pcReturned;
  1852. while (i--) {
  1853. ConvertUnicodeToAnsiStrings(pPrintProcessorInfo, pOffsets);
  1854. pPrintProcessorInfo+=cbStruct;
  1855. }
  1856. }
  1857. }
  1858. Cleanup:
  1859. FreeUnicodeString(pUnicodeName);
  1860. FreeUnicodeString(pUnicodeEnvironment);
  1861. return ReturnValue;
  1862. }
  1863. BOOL
  1864. GetPrintProcessorDirectoryA(
  1865. LPSTR pName,
  1866. LPSTR pEnvironment,
  1867. DWORD Level,
  1868. LPBYTE pPrintProcessorInfo,
  1869. DWORD cbBuf,
  1870. LPDWORD pcbNeeded
  1871. )
  1872. {
  1873. BOOL ReturnValue = FALSE;
  1874. LPWSTR pUnicodeName = NULL;
  1875. LPWSTR pUnicodeEnvironment = NULL;
  1876. pUnicodeName = AllocateUnicodeString(pName);
  1877. if (pName && !pUnicodeName)
  1878. goto Cleanup;
  1879. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  1880. if (pEnvironment && !pUnicodeEnvironment)
  1881. goto Cleanup;
  1882. ReturnValue = GetPrintProcessorDirectoryW(pUnicodeName,
  1883. pUnicodeEnvironment,
  1884. Level,
  1885. pPrintProcessorInfo,
  1886. cbBuf, pcbNeeded);
  1887. if (ReturnValue && pPrintProcessorInfo) {
  1888. UnicodeToAnsiString((LPWSTR)pPrintProcessorInfo,
  1889. (LPSTR)pPrintProcessorInfo,
  1890. NULL_TERMINATED);
  1891. }
  1892. Cleanup:
  1893. FreeUnicodeString(pUnicodeName);
  1894. FreeUnicodeString(pUnicodeEnvironment);
  1895. return ReturnValue;
  1896. }
  1897. BOOL
  1898. EnumPrintProcessorDatatypesA(
  1899. LPSTR pName,
  1900. LPSTR pPrintProcessorName,
  1901. DWORD Level,
  1902. LPBYTE pDatatype,
  1903. DWORD cbBuf,
  1904. LPDWORD pcbNeeded,
  1905. LPDWORD pcReturned
  1906. )
  1907. {
  1908. BOOL ReturnValue=FALSE;
  1909. DWORD cbStruct;
  1910. DWORD *pOffsets;
  1911. LPWSTR pUnicodeName = NULL;
  1912. LPWSTR pUnicodePrintProcessorName = NULL;
  1913. switch (Level) {
  1914. case 1:
  1915. pOffsets = DatatypeInfo1Strings;
  1916. cbStruct = sizeof(DATATYPES_INFO_1);
  1917. break;
  1918. default:
  1919. SetLastError(ERROR_INVALID_LEVEL);
  1920. return FALSE;
  1921. }
  1922. pUnicodeName = AllocateUnicodeString(pName);
  1923. if (pName && !pUnicodeName)
  1924. goto Cleanup;
  1925. pUnicodePrintProcessorName = AllocateUnicodeString(pPrintProcessorName);
  1926. if (pPrintProcessorName && !pUnicodePrintProcessorName)
  1927. goto Cleanup;
  1928. if (ReturnValue = EnumPrintProcessorDatatypesW(pUnicodeName,
  1929. pUnicodePrintProcessorName,
  1930. Level,
  1931. pDatatype,
  1932. cbBuf,
  1933. pcbNeeded,
  1934. pcReturned)) {
  1935. if (pDatatype) {
  1936. DWORD i=*pcReturned;
  1937. while (i--) {
  1938. ConvertUnicodeToAnsiStrings(pDatatype, pOffsets);
  1939. pDatatype += cbStruct;
  1940. }
  1941. }
  1942. }
  1943. Cleanup:
  1944. FreeUnicodeString(pUnicodeName);
  1945. FreeUnicodeString(pUnicodePrintProcessorName);
  1946. return ReturnValue;
  1947. }
  1948. DWORD
  1949. StartDocPrinterA(
  1950. HANDLE hPrinter,
  1951. DWORD Level,
  1952. LPBYTE pDocInfo
  1953. )
  1954. {
  1955. BOOL ReturnValue = FALSE;
  1956. LPBYTE pUnicodeStructure = NULL;
  1957. DWORD cbStruct;
  1958. // level 2 is supported on win95 and not on NT
  1959. switch (Level) {
  1960. case 1:
  1961. cbStruct = sizeof(DOC_INFO_1A);
  1962. break;
  1963. case 3:
  1964. cbStruct = sizeof(DOC_INFO_3A);
  1965. break;
  1966. default:
  1967. SetLastError(ERROR_INVALID_LEVEL);
  1968. goto Cleanup;
  1969. }
  1970. pUnicodeStructure = AllocateUnicodeStructure(pDocInfo, cbStruct, DocInfo1Offsets);
  1971. if (pDocInfo && !pUnicodeStructure)
  1972. goto Cleanup;
  1973. ReturnValue = StartDocPrinterW(hPrinter, Level, pUnicodeStructure);
  1974. Cleanup:
  1975. FreeUnicodeStructure(pUnicodeStructure, DocInfo1Offsets);
  1976. return ReturnValue;
  1977. }
  1978. BOOL
  1979. AddJobA(
  1980. HANDLE hPrinter,
  1981. DWORD Level,
  1982. LPBYTE pData,
  1983. DWORD cbBuf,
  1984. LPDWORD pcbNeeded
  1985. )
  1986. {
  1987. BOOL ReturnValue;
  1988. if( Level == 2 || Level == 3 ){
  1989. SetLastError( ERROR_INVALID_LEVEL );
  1990. return FALSE;
  1991. }
  1992. if (ReturnValue = AddJobW(hPrinter, Level, pData,
  1993. cbBuf, pcbNeeded))
  1994. ConvertUnicodeToAnsiStrings(pData, AddJobStrings);
  1995. return ReturnValue;
  1996. }
  1997. DWORD
  1998. GetPrinterDataA(
  1999. HANDLE hPrinter,
  2000. LPSTR pValueName,
  2001. LPDWORD pType,
  2002. LPBYTE pData,
  2003. DWORD nSize,
  2004. LPDWORD pcbNeeded
  2005. )
  2006. {
  2007. DWORD ReturnValue = ERROR_SUCCESS;
  2008. DWORD ReturnType = 0;
  2009. LPWSTR pUnicodeValueName = NULL;
  2010. pUnicodeValueName = AllocateUnicodeString(pValueName);
  2011. //
  2012. // pUnicodeValueName will be NULL if the caller passed NULL for pValueName. The
  2013. // invalid situation is when pValueName is non NULL and pUnicodeValueName is NULL
  2014. //
  2015. if (pUnicodeValueName || !pValueName)
  2016. {
  2017. if (!pType)
  2018. {
  2019. pType = (PDWORD)&ReturnType;
  2020. }
  2021. if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSION))
  2022. {
  2023. //
  2024. // The caller wants OSVersion
  2025. //
  2026. OSVERSIONINFOW osw = {0};
  2027. ReturnValue = GetPrinterDataW(hPrinter,
  2028. pUnicodeValueName,
  2029. pType,
  2030. (PBYTE)&osw,
  2031. nSize >= sizeof(OSVERSIONINFOA) ? sizeof(osw) : nSize,
  2032. pcbNeeded);
  2033. if (ReturnValue == ERROR_SUCCESS && pData)
  2034. {
  2035. OSVERSIONWRAP wrap = {0};
  2036. wrap.bOsVersionEx = FALSE;
  2037. wrap.Unicode.pOsVersion = &osw;
  2038. wrap.Ansi.pOsVersion = (OSVERSIONINFOA *)pData;
  2039. ReturnValue = CopyOsVersionUnicodeToAnsi(wrap);
  2040. }
  2041. //
  2042. // Set correct number of bytes required/returned
  2043. //
  2044. if (pcbNeeded)
  2045. {
  2046. *pcbNeeded = sizeof(OSVERSIONINFOA);
  2047. }
  2048. }
  2049. else if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSIONEX))
  2050. {
  2051. //
  2052. // The caller wants OSVersionEx
  2053. //
  2054. OSVERSIONINFOEXW osexw = {0};
  2055. ReturnValue = GetPrinterDataW(hPrinter,
  2056. pUnicodeValueName,
  2057. pType,
  2058. (PBYTE)&osexw,
  2059. nSize >= sizeof(OSVERSIONINFOEXA) ? sizeof(osexw) : nSize,
  2060. pcbNeeded);
  2061. if (ReturnValue == ERROR_SUCCESS && pData)
  2062. {
  2063. OSVERSIONWRAP wrap = {0};
  2064. wrap.bOsVersionEx = TRUE;
  2065. wrap.Unicode.pOsVersionEx = &osexw;
  2066. wrap.Ansi.pOsVersionEx = (OSVERSIONINFOEXA *)pData;
  2067. ReturnValue = CopyOsVersionUnicodeToAnsi(wrap);
  2068. }
  2069. //
  2070. // Set correct number of bytes required/returned
  2071. //
  2072. if (pcbNeeded)
  2073. {
  2074. *pcbNeeded = sizeof(OSVERSIONINFOEXA);
  2075. }
  2076. }
  2077. else
  2078. {
  2079. ReturnValue = GetPrinterDataW(hPrinter, pUnicodeValueName, pType, pData, nSize, pcbNeeded);
  2080. //
  2081. // Special case string values
  2082. //
  2083. if ((ReturnValue == ERROR_MORE_DATA || ReturnValue == ERROR_SUCCESS) &&
  2084. (*pType == REG_MULTI_SZ || *pType == REG_SZ || *pType == REG_EXPAND_SZ))
  2085. {
  2086. if (ReturnValue==ERROR_SUCCESS)
  2087. {
  2088. //
  2089. // The buffer passed in by the caller was large enough. We only need to
  2090. // convert from UNICODE to ANSI. It can happen that a UNICODE char will
  2091. // be represented on 3 ansi chars, so we cannot assume that if a buffer
  2092. // is large enough for a unicode string, it can also accomodate the converted
  2093. // ansi string.
  2094. //
  2095. ReturnValue = UnicodeToAnsi(NULL,
  2096. 0,
  2097. pData,
  2098. *pcbNeeded,
  2099. pcbNeeded);
  2100. }
  2101. else
  2102. {
  2103. BYTE *pBuf = NULL;
  2104. if (pBuf = LocalAlloc(LPTR, *pcbNeeded))
  2105. {
  2106. if ((ReturnValue = GetPrinterDataW(hPrinter,
  2107. pUnicodeValueName,
  2108. pType,
  2109. pBuf,
  2110. *pcbNeeded,
  2111. pcbNeeded)) == ERROR_SUCCESS)
  2112. {
  2113. ReturnValue = UnicodeToAnsi(pBuf,
  2114. *pcbNeeded / sizeof(WCHAR),
  2115. pData,
  2116. nSize,
  2117. pcbNeeded);
  2118. }
  2119. LocalFree(pBuf);
  2120. }
  2121. else
  2122. {
  2123. ReturnValue = GetLastError();
  2124. }
  2125. }
  2126. }
  2127. }
  2128. }
  2129. else
  2130. {
  2131. //
  2132. // pUnicodeValueName is NULL and pValueName is NOT NULL, so AllocateUnicodeString failed
  2133. // AllocateUnicodeString sets the LastError correctly
  2134. //
  2135. ReturnValue = GetLastError();
  2136. }
  2137. FreeUnicodeString(pUnicodeValueName);
  2138. return ReturnValue;
  2139. }
  2140. DWORD
  2141. GetPrinterDataExA(
  2142. HANDLE hPrinter,
  2143. LPCSTR pKeyName,
  2144. LPCSTR pValueName,
  2145. LPDWORD pType,
  2146. LPBYTE pData,
  2147. DWORD nSize,
  2148. LPDWORD pcbNeeded
  2149. )
  2150. {
  2151. DWORD ReturnValue = ERROR_SUCCESS;
  2152. DWORD ReturnType = 0;
  2153. LPWSTR pUnicodeValueName = NULL;
  2154. LPWSTR pUnicodeKeyName = NULL;
  2155. pUnicodeValueName = AllocateUnicodeString((LPSTR) pValueName);
  2156. if (pValueName && !pUnicodeValueName)
  2157. goto Cleanup;
  2158. pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName);
  2159. if (pKeyName && !pUnicodeKeyName)
  2160. goto Cleanup;
  2161. if (!pType) {
  2162. pType = (PDWORD) &ReturnType;
  2163. }
  2164. if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSION))
  2165. {
  2166. //
  2167. // The caller wants OSVersion
  2168. //
  2169. OSVERSIONINFOW osw = {0};
  2170. ReturnValue = GetPrinterDataExW(hPrinter,
  2171. (LPCWSTR)pUnicodeKeyName,
  2172. (LPCWSTR)pUnicodeValueName,
  2173. pType,
  2174. (PBYTE)&osw,
  2175. nSize >= sizeof(OSVERSIONINFOA) ? sizeof(osw) : nSize,
  2176. pcbNeeded);
  2177. if (ReturnValue == ERROR_SUCCESS && pData)
  2178. {
  2179. OSVERSIONWRAP wrap = {0};
  2180. wrap.bOsVersionEx = FALSE;
  2181. wrap.Unicode.pOsVersion = &osw;
  2182. wrap.Ansi.pOsVersion = (OSVERSIONINFOA *)pData;
  2183. ReturnValue = CopyOsVersionUnicodeToAnsi(wrap);
  2184. }
  2185. //
  2186. // Set correct number of bytes required/returned
  2187. //
  2188. if (pcbNeeded)
  2189. {
  2190. *pcbNeeded = sizeof(OSVERSIONINFOA);
  2191. }
  2192. }
  2193. else if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSIONEX))
  2194. {
  2195. //
  2196. // The caller wants OSVersionEx
  2197. //
  2198. OSVERSIONINFOEXW osexw = {0};
  2199. ReturnValue = GetPrinterDataExW(hPrinter,
  2200. (LPCWSTR)pUnicodeKeyName,
  2201. (LPCWSTR)pUnicodeValueName,
  2202. pType,
  2203. (PBYTE)&osexw,
  2204. nSize >= sizeof(OSVERSIONINFOEXA) ? sizeof(osexw) : nSize,
  2205. pcbNeeded);
  2206. if (ReturnValue == ERROR_SUCCESS && pData)
  2207. {
  2208. OSVERSIONWRAP wrap = {0};
  2209. wrap.bOsVersionEx = TRUE;
  2210. wrap.Unicode.pOsVersionEx = &osexw;
  2211. wrap.Ansi.pOsVersionEx = (OSVERSIONINFOEXA *)pData;
  2212. ReturnValue = CopyOsVersionUnicodeToAnsi(wrap);
  2213. }
  2214. //
  2215. // Set correct number of bytes required/returned
  2216. //
  2217. if (pcbNeeded)
  2218. {
  2219. *pcbNeeded = sizeof(OSVERSIONINFOEXA);
  2220. }
  2221. }
  2222. else
  2223. {
  2224. ReturnValue = GetPrinterDataExW(hPrinter,
  2225. (LPCWSTR)pUnicodeKeyName,
  2226. (LPCWSTR)pUnicodeValueName,
  2227. pType,
  2228. pData,
  2229. nSize,
  2230. pcbNeeded);
  2231. //
  2232. // Special case string values
  2233. //
  2234. if ((ReturnValue == ERROR_MORE_DATA || ReturnValue == ERROR_SUCCESS) &&
  2235. (*pType == REG_MULTI_SZ || *pType == REG_SZ || *pType == REG_EXPAND_SZ))
  2236. {
  2237. if (ReturnValue==ERROR_SUCCESS)
  2238. {
  2239. //
  2240. // The buffer passed in by the caller was large enough. We only need to
  2241. // convert from UNICODE to ANSI. It can happen that a UNICODE char will
  2242. // be represented on 3 ansi chars, so we cannot assume that if a buffer
  2243. // is large enough for a unicode string, it can also accomodate the converted
  2244. // ansi string.
  2245. //
  2246. ReturnValue = UnicodeToAnsi(NULL,
  2247. 0,
  2248. pData,
  2249. *pcbNeeded,
  2250. pcbNeeded);
  2251. }
  2252. else
  2253. {
  2254. BYTE *pBuf = NULL;
  2255. if (pBuf = LocalAlloc(LPTR, *pcbNeeded))
  2256. {
  2257. if ((ReturnValue = GetPrinterDataExW(hPrinter,
  2258. (LPCWSTR)pUnicodeKeyName,
  2259. (LPCWSTR)pUnicodeValueName,
  2260. pType,
  2261. pBuf,
  2262. *pcbNeeded,
  2263. pcbNeeded)) == ERROR_SUCCESS)
  2264. {
  2265. ReturnValue = UnicodeToAnsi(pBuf,
  2266. *pcbNeeded / sizeof(WCHAR),
  2267. pData,
  2268. nSize,
  2269. pcbNeeded);
  2270. }
  2271. LocalFree(pBuf);
  2272. }
  2273. else
  2274. {
  2275. ReturnValue = GetLastError();
  2276. }
  2277. }
  2278. }
  2279. }
  2280. Cleanup:
  2281. FreeUnicodeString(pUnicodeKeyName);
  2282. FreeUnicodeString(pUnicodeValueName);
  2283. return ReturnValue;
  2284. }
  2285. DWORD
  2286. EnumPrinterDataA(
  2287. HANDLE hPrinter,
  2288. DWORD dwIndex, // index of value to query
  2289. LPSTR pValueName, // address of buffer for value string
  2290. DWORD cbValueName, // size of pValueName
  2291. LPDWORD pcbValueName, // address for size of value buffer
  2292. LPDWORD pType, // address of buffer for type code
  2293. LPBYTE pData, // address of buffer for value data
  2294. DWORD cbData, // size of pData
  2295. LPDWORD pcbData // address for size of data buffer
  2296. )
  2297. {
  2298. DWORD ReturnValue = 0;
  2299. DWORD i;
  2300. ReturnValue = EnumPrinterDataW(hPrinter,
  2301. dwIndex,
  2302. (LPWSTR) pValueName,
  2303. cbValueName,
  2304. pcbValueName,
  2305. pType,
  2306. pData,
  2307. cbData,
  2308. pcbData);
  2309. if (ReturnValue == ERROR_SUCCESS && (cbValueName || cbData))
  2310. {
  2311. if (pData && pType &&
  2312. (*pType==REG_SZ ||
  2313. *pType==REG_MULTI_SZ ||
  2314. *pType==REG_EXPAND_SZ))
  2315. {
  2316. //
  2317. // For this API we will require a buffer size that can accomodate UNICODE strings
  2318. // We do not want UnicodeToAnsi to update the number of bytes needed to store
  2319. // the string converted to ansi.
  2320. //
  2321. UnicodeToAnsi(NULL, 0, pData, *pcbData, NULL);
  2322. }
  2323. UnicodeToAnsiString((LPWSTR) pValueName, (LPSTR) pValueName, NULL_TERMINATED);
  2324. }
  2325. return ReturnValue;
  2326. }
  2327. DWORD
  2328. EnumPrinterDataExA(
  2329. HANDLE hPrinter,
  2330. LPCSTR pKeyName,
  2331. LPBYTE pEnumValues,
  2332. DWORD cbEnumValues,
  2333. LPDWORD pcbEnumValues,
  2334. LPDWORD pnEnumValues
  2335. )
  2336. {
  2337. DWORD ReturnValue = 0;
  2338. DWORD i;
  2339. PPRINTER_ENUM_VALUES pEnumValue;
  2340. LPWSTR pUnicodeKeyName = NULL;
  2341. pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName);
  2342. if (pKeyName && !pUnicodeKeyName)
  2343. goto Cleanup;
  2344. ReturnValue = EnumPrinterDataExW(hPrinter,
  2345. (LPCWSTR) pUnicodeKeyName,
  2346. pEnumValues,
  2347. cbEnumValues,
  2348. pcbEnumValues,
  2349. pnEnumValues);
  2350. if (ReturnValue == ERROR_SUCCESS) {
  2351. pEnumValue = (PPRINTER_ENUM_VALUES) pEnumValues;
  2352. for(i = 0 ; i < *pnEnumValues ; ++i, ++pEnumValue) {
  2353. if (pEnumValue->cbValueName) {
  2354. UnicodeToAnsiString((LPWSTR) pEnumValue->pValueName,
  2355. (LPSTR) pEnumValue->pValueName,
  2356. NULL_TERMINATED);
  2357. }
  2358. if (pEnumValue->pData &&
  2359. (pEnumValue->dwType == REG_SZ ||
  2360. pEnumValue->dwType == REG_MULTI_SZ ||
  2361. pEnumValue->dwType == REG_EXPAND_SZ)) {
  2362. //
  2363. // For this API we will require a buffer size that can accomodate UNICODE strings
  2364. // We do not want UnicodeToAnsi to update the number of bytes needed to store
  2365. // the string converted to ansi.
  2366. //
  2367. UnicodeToAnsi(NULL,
  2368. 0,
  2369. pEnumValue->pData,
  2370. pEnumValue->cbData,
  2371. NULL);
  2372. }
  2373. }
  2374. }
  2375. Cleanup:
  2376. FreeUnicodeString(pUnicodeKeyName);
  2377. return ReturnValue;
  2378. }
  2379. DWORD
  2380. EnumPrinterKeyA(
  2381. HANDLE hPrinter,
  2382. LPCSTR pKeyName,
  2383. LPSTR pSubkey, // address of buffer for value string
  2384. DWORD cbSubkey, // size of pValueName
  2385. LPDWORD pcbSubkey // address for size of value buffer
  2386. )
  2387. {
  2388. DWORD ReturnValue = 0;
  2389. LPWSTR pUnicodeKeyName = NULL;
  2390. pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName);
  2391. if (pKeyName && !pUnicodeKeyName)
  2392. goto Cleanup;
  2393. ReturnValue = EnumPrinterKeyW( hPrinter,
  2394. (LPCWSTR) pUnicodeKeyName,
  2395. (LPWSTR) pSubkey,
  2396. cbSubkey,
  2397. pcbSubkey);
  2398. if (ReturnValue == ERROR_SUCCESS && cbSubkey)
  2399. {
  2400. ReturnValue = UnicodeToAnsi(NULL,
  2401. 0,
  2402. pSubkey,
  2403. *pcbSubkey,
  2404. pcbSubkey);
  2405. }
  2406. else if (ReturnValue == ERROR_MORE_DATA)
  2407. {
  2408. BYTE *pBuf = NULL;
  2409. if (pBuf = LocalAlloc(LPTR, *pcbSubkey))
  2410. {
  2411. if ((ReturnValue = EnumPrinterKeyW(hPrinter,
  2412. (LPCWSTR)pUnicodeKeyName,
  2413. (LPWSTR)pBuf,
  2414. *pcbSubkey,
  2415. pcbSubkey)) == ERROR_SUCCESS)
  2416. {
  2417. ReturnValue = UnicodeToAnsi(pBuf,
  2418. *pcbSubkey / sizeof(WCHAR),
  2419. pSubkey,
  2420. cbSubkey,
  2421. pcbSubkey);
  2422. }
  2423. LocalFree(pBuf);
  2424. }
  2425. else
  2426. {
  2427. ReturnValue = GetLastError();
  2428. }
  2429. }
  2430. Cleanup:
  2431. FreeUnicodeString(pUnicodeKeyName);
  2432. return ReturnValue;
  2433. }
  2434. DWORD
  2435. DeletePrinterDataA(
  2436. HANDLE hPrinter,
  2437. LPSTR pValueName
  2438. )
  2439. {
  2440. DWORD ReturnValue = 0;
  2441. LPWSTR pUnicodeValueName = NULL;
  2442. pUnicodeValueName = AllocateUnicodeString(pValueName);
  2443. if (pValueName && !pUnicodeValueName)
  2444. goto Cleanup;
  2445. ReturnValue = DeletePrinterDataW(hPrinter, (LPWSTR) pUnicodeValueName);
  2446. Cleanup:
  2447. FreeUnicodeString(pUnicodeValueName);
  2448. return ReturnValue;
  2449. }
  2450. DWORD
  2451. DeletePrinterDataExA(
  2452. HANDLE hPrinter,
  2453. LPCSTR pKeyName,
  2454. LPCSTR pValueName
  2455. )
  2456. {
  2457. DWORD ReturnValue = 0;
  2458. LPWSTR pUnicodeKeyName = NULL;
  2459. LPWSTR pUnicodeValueName = NULL;
  2460. pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName);
  2461. if (pKeyName && !pUnicodeKeyName)
  2462. goto Cleanup;
  2463. pUnicodeValueName = AllocateUnicodeString((LPSTR) pValueName);
  2464. if (pValueName && !pUnicodeValueName)
  2465. goto Cleanup;
  2466. ReturnValue = DeletePrinterDataExW(hPrinter, (LPCWSTR) pUnicodeKeyName, (LPCWSTR) pUnicodeValueName);
  2467. Cleanup:
  2468. FreeUnicodeString(pUnicodeKeyName);
  2469. FreeUnicodeString(pUnicodeValueName);
  2470. return ReturnValue;
  2471. }
  2472. DWORD
  2473. DeletePrinterKeyA(
  2474. HANDLE hPrinter,
  2475. LPCSTR pKeyName
  2476. )
  2477. {
  2478. DWORD ReturnValue = 0;
  2479. LPWSTR pUnicodeKeyName = NULL;
  2480. pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName);
  2481. if (pKeyName && !pUnicodeKeyName)
  2482. goto Cleanup;
  2483. ReturnValue = DeletePrinterKeyW(hPrinter, (LPCWSTR) pUnicodeKeyName);
  2484. Cleanup:
  2485. FreeUnicodeString(pUnicodeKeyName);
  2486. return ReturnValue;
  2487. }
  2488. DWORD
  2489. SetPrinterDataA(
  2490. HANDLE hPrinter,
  2491. LPSTR pValueName,
  2492. DWORD Type,
  2493. LPBYTE pData,
  2494. DWORD cbData
  2495. )
  2496. {
  2497. DWORD ReturnValue = 0;
  2498. LPWSTR pUnicodeValueName = NULL;
  2499. LPWSTR pUnicodeData = NULL;
  2500. DWORD cbDataString;
  2501. DWORD i;
  2502. pUnicodeValueName = AllocateUnicodeString(pValueName);
  2503. if (pValueName && !pUnicodeValueName)
  2504. goto Cleanup;
  2505. if (Type == REG_SZ || Type == REG_EXPAND_SZ || Type == REG_MULTI_SZ)
  2506. {
  2507. //
  2508. // No matter if reg_sz or multi_sz, we want to mimic the registry APIs
  2509. // in behavior. This means we will not check strings for null termination.
  2510. // We will set as many bytes as specified by cbData
  2511. //
  2512. pUnicodeData = AllocateUnicodeStringWithSize(pData, cbData);
  2513. if (pUnicodeData)
  2514. {
  2515. cbData *= sizeof(WCHAR);
  2516. ReturnValue = SetPrinterDataW(hPrinter, pUnicodeValueName, Type, (LPBYTE) pUnicodeData, cbData);
  2517. FreeUnicodeString(pUnicodeData);
  2518. }
  2519. else
  2520. {
  2521. ReturnValue = ERROR_INVALID_PARAMETER;
  2522. }
  2523. }
  2524. else
  2525. {
  2526. ReturnValue = SetPrinterDataW(hPrinter, pUnicodeValueName, Type, pData, cbData);
  2527. }
  2528. Cleanup:
  2529. FreeUnicodeString(pUnicodeValueName);
  2530. return ReturnValue;
  2531. }
  2532. DWORD
  2533. SetPrinterDataExA(
  2534. HANDLE hPrinter,
  2535. LPCSTR pKeyName,
  2536. LPCSTR pValueName,
  2537. DWORD Type,
  2538. LPBYTE pData,
  2539. DWORD cbData
  2540. )
  2541. {
  2542. DWORD ReturnValue = 0;
  2543. LPWSTR pUnicodeKeyName = NULL;
  2544. LPWSTR pUnicodeValueName = NULL;
  2545. LPWSTR pUnicodeData = NULL;
  2546. DWORD cbDataString;
  2547. DWORD i;
  2548. pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName);
  2549. if (pKeyName && !pUnicodeKeyName)
  2550. goto Cleanup;
  2551. pUnicodeValueName = AllocateUnicodeString((LPSTR) pValueName);
  2552. if (pValueName && !pUnicodeValueName)
  2553. goto Cleanup;
  2554. if (Type == REG_SZ || Type == REG_EXPAND_SZ || Type == REG_MULTI_SZ)
  2555. {
  2556. //
  2557. // No matter if reg_sz or multi_sz, we want to mimic the registry APIs
  2558. // in behavior. This means we will not check strings for null termination.
  2559. // We will set as many bytes as specified by cbData
  2560. //
  2561. pUnicodeData = AllocateUnicodeStringWithSize(pData, cbData);
  2562. if (pUnicodeData)
  2563. {
  2564. cbData *= sizeof(WCHAR);
  2565. ReturnValue = SetPrinterDataExW(hPrinter,
  2566. (LPCWSTR) pUnicodeKeyName,
  2567. (LPCWSTR) pUnicodeValueName,
  2568. Type,
  2569. (LPBYTE) pUnicodeData,
  2570. cbData);
  2571. FreeUnicodeString(pUnicodeData);
  2572. }
  2573. else
  2574. {
  2575. ReturnValue = ERROR_INVALID_PARAMETER;
  2576. }
  2577. }
  2578. else
  2579. {
  2580. ReturnValue = SetPrinterDataExW(hPrinter,
  2581. (LPCWSTR) pUnicodeKeyName,
  2582. (LPCWSTR) pUnicodeValueName,
  2583. Type,
  2584. pData,
  2585. cbData);
  2586. }
  2587. Cleanup:
  2588. FreeUnicodeString(pUnicodeValueName);
  2589. FreeUnicodeString(pUnicodeKeyName);
  2590. return ReturnValue;
  2591. }
  2592. /**************************** Function Header *******************************
  2593. * DocumentPropertiesA
  2594. * The ANSI version of the DocumentProperties function. Basically
  2595. * converts the input parameters to UNICODE versions and calls
  2596. * the DocumentPropertiesW function.
  2597. *
  2598. * CAVEATS: PRESUMES THAT IF pDevModeOutput IS SUPPLIED, IT HAS THE SIZE
  2599. * OF THE UNICODE VERSION. THIS WILL USUALLY HAPPEN IF THE CALLER
  2600. * FIRST CALLS TO FIND THE SIZE REQUIRED>
  2601. *
  2602. * RETURNS:
  2603. * Somesort of LONG.
  2604. *
  2605. ****************************************************************************/
  2606. LONG
  2607. DocumentPropertiesA(
  2608. HWND hWnd,
  2609. HANDLE hPrinter,
  2610. LPSTR pDeviceName,
  2611. PDEVMODEA pDevModeOutput,
  2612. PDEVMODEA pDevModeInput,
  2613. DWORD fMode
  2614. )
  2615. {
  2616. LPWSTR pUnicodeDeviceName = NULL;
  2617. LPDEVMODEW pUnicodeDevModeInput = NULL;
  2618. LPDEVMODEW pUnicodeDevModeOutput = NULL;
  2619. LONG ReturnValue = -1;
  2620. pUnicodeDeviceName = AllocateUnicodeString(pDeviceName);
  2621. if (pDeviceName && !pUnicodeDeviceName)
  2622. goto Cleanup;
  2623. ReturnValue = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName,
  2624. NULL, NULL, 0);
  2625. if (ReturnValue > 0) {
  2626. if (fMode) {
  2627. if (pUnicodeDevModeOutput = LocalAlloc(LMEM_FIXED, ReturnValue)) {
  2628. //
  2629. // Only convert the input buffer if one is specified
  2630. // and fMode indicates it's valid. WinNT 3.51 used
  2631. // pDevModeInput regardless of DM_IN_BUFFER, but this
  2632. // broke Borland Delphi for win95 + Corel Flow for win95.
  2633. //
  2634. if( pDevModeInput && ( fMode & DM_IN_BUFFER )){
  2635. //
  2636. // If the devmode is invalid, then don't pass one in.
  2637. // This fixes MS Imager32 (which passes dmSize == 0) and
  2638. // Milestones etc. 4.5.
  2639. //
  2640. // Note: this assumes that pDevModeOutput is still the
  2641. // correct size!
  2642. //
  2643. if( !BoolFromHResult(SplIsValidDevmodeNoSizeA(pDevModeInput))){
  2644. fMode &= ~DM_IN_BUFFER;
  2645. } else {
  2646. pUnicodeDevModeInput = AllocateUnicodeDevMode(
  2647. pDevModeInput );
  2648. if( !pUnicodeDevModeInput ){
  2649. ReturnValue = -1;
  2650. goto Cleanup;
  2651. }
  2652. }
  2653. }
  2654. ReturnValue = DocumentPropertiesW(hWnd, hPrinter,
  2655. pUnicodeDeviceName,
  2656. pUnicodeDevModeOutput,
  2657. pUnicodeDevModeInput, fMode );
  2658. //
  2659. // The printer driver has filled in the DEVMODEW
  2660. // structure - if one was passed in. Now convert it
  2661. // back to a DEVMODEA structure.
  2662. //
  2663. if (pDevModeOutput && (ReturnValue == IDOK)) {
  2664. CopyAnsiDevModeFromUnicodeDevMode(pDevModeOutput,
  2665. pUnicodeDevModeOutput);
  2666. }
  2667. } else
  2668. ReturnValue = -1;
  2669. } else
  2670. ReturnValue-=sizeof(DEVMODEW)-sizeof(DEVMODEA);
  2671. }
  2672. Cleanup:
  2673. if (pUnicodeDevModeInput)
  2674. LocalFree(pUnicodeDevModeInput);
  2675. if (pUnicodeDevModeOutput)
  2676. LocalFree(pUnicodeDevModeOutput);
  2677. FreeUnicodeString(pUnicodeDeviceName);
  2678. return ReturnValue;
  2679. }
  2680. BOOL
  2681. WriteCurDevModeToRegistry(
  2682. LPWSTR pPrinterName,
  2683. LPDEVMODEW pDevMode
  2684. )
  2685. {
  2686. DWORD Status;
  2687. HKEY hDevMode;
  2688. SPLASSERT(pDevMode);
  2689. Status = RegCreateKeyEx(HKEY_CURRENT_USER,
  2690. szCurDevMode,
  2691. 0,
  2692. NULL,
  2693. 0,
  2694. KEY_WRITE,
  2695. NULL,
  2696. &hDevMode,
  2697. NULL);
  2698. if ( Status == ERROR_SUCCESS ) {
  2699. Status = RegSetValueExW(hDevMode,
  2700. pPrinterName,
  2701. 0,
  2702. REG_BINARY,
  2703. (LPBYTE)pDevMode,
  2704. pDevMode->dmSize + pDevMode->dmDriverExtra);
  2705. RegCloseKey(hDevMode);
  2706. }
  2707. return Status == ERROR_SUCCESS;
  2708. }
  2709. BOOL
  2710. DeleteCurDevModeFromRegistry(
  2711. PWSTR pPrinterName
  2712. )
  2713. {
  2714. DWORD Status;
  2715. HKEY hDevModeKey;
  2716. Status = RegCreateKeyEx(HKEY_CURRENT_USER,
  2717. szCurDevMode,
  2718. 0,
  2719. NULL,
  2720. 0,
  2721. KEY_WRITE,
  2722. NULL,
  2723. &hDevModeKey,
  2724. NULL);
  2725. if ( Status == ERROR_SUCCESS ) {
  2726. Status = RegDeleteValue(hDevModeKey, pPrinterName);
  2727. RegCloseKey(hDevModeKey);
  2728. }
  2729. return Status == ERROR_SUCCESS;
  2730. }
  2731. LPDEVMODEW
  2732. AllocateCurDevMode(
  2733. HANDLE hPrinter,
  2734. LPWSTR pDeviceName,
  2735. LONG cbDevMode
  2736. )
  2737. {
  2738. LPDEVMODEW pRegDevMode = NULL;
  2739. LPDEVMODEW pRealDevMode = NULL;
  2740. LPDEVMODEW pRetDevMode = NULL;
  2741. BOOL bUpdateReg = FALSE;
  2742. HANDLE hKeyDevMode = INVALID_HANDLE_VALUE;
  2743. DWORD dwStatus, dwType;
  2744. LONG lDocStatus;
  2745. //
  2746. // This code now checks to see that the DEVMODE in the registry matches that of
  2747. // the driver. If it does not, then 1. The driver has been migrated. 2. The user has been
  2748. // using an incompatible driver. In this case, the per user DEVMODE settings are overwritten
  2749. // with those obtained from the driver.
  2750. //
  2751. dwStatus = RegCreateKeyEx( HKEY_CURRENT_USER,
  2752. szCurDevMode,
  2753. 0,
  2754. NULL,
  2755. 0,
  2756. KEY_READ,
  2757. NULL,
  2758. &hKeyDevMode,
  2759. NULL);
  2760. if( dwStatus != ERROR_SUCCESS )
  2761. goto Cleanup;
  2762. pRegDevMode = (PDEVMODEW)LocalAlloc(LMEM_FIXED, cbDevMode);
  2763. pRealDevMode = (PDEVMODEW)LocalAlloc(LMEM_FIXED, cbDevMode);
  2764. //
  2765. // This cbDevMode is obtained via a call to DocumentPropertiesW, thus it is
  2766. // correct (unless race condition).
  2767. //
  2768. if( pRegDevMode == NULL || pRealDevMode == NULL)
  2769. goto Cleanup;
  2770. lDocStatus = DocumentPropertiesW( NULL,
  2771. hPrinter,
  2772. pDeviceName,
  2773. pRealDevMode,
  2774. NULL,
  2775. DM_COPY );
  2776. dwStatus = RegQueryValueExW(hKeyDevMode,
  2777. pDeviceName,
  2778. 0,
  2779. &dwType,
  2780. (LPBYTE)pRegDevMode,
  2781. &cbDevMode);
  2782. bUpdateReg = (dwStatus != ERROR_SUCCESS || dwType != REG_BINARY)
  2783. && lDocStatus == IDOK;
  2784. if (dwStatus == ERROR_SUCCESS && lDocStatus == IDOK && !bUpdateReg) {
  2785. if (BoolFromHResult(SplIsValidDevmodeNoSizeW(pRegDevMode)))
  2786. {
  2787. //
  2788. // Check to see that our DEVMODE structures are compatible
  2789. //
  2790. bUpdateReg = pRealDevMode->dmSize != pRegDevMode->dmSize ||
  2791. pRealDevMode->dmDriverExtra != pRegDevMode->dmDriverExtra ||
  2792. pRealDevMode->dmSpecVersion != pRegDevMode->dmSpecVersion ||
  2793. pRealDevMode->dmDriverVersion != pRegDevMode->dmDriverVersion;
  2794. if (!bUpdateReg)
  2795. pRetDevMode = pRegDevMode;
  2796. }
  2797. }
  2798. if (bUpdateReg) {
  2799. //
  2800. // The Registry is out of date, The read from the Document properties must have
  2801. // succeded
  2802. //
  2803. if (!WriteCurDevModeToRegistry(pDeviceName, pRealDevMode) )
  2804. goto Cleanup;
  2805. else
  2806. pRetDevMode = pRealDevMode;
  2807. }
  2808. Cleanup:
  2809. if (pRegDevMode != pRetDevMode && pRegDevMode != NULL)
  2810. LocalFree(pRegDevMode);
  2811. if (pRealDevMode != pRetDevMode && pRealDevMode != NULL)
  2812. LocalFree(pRealDevMode);
  2813. if (hKeyDevMode != INVALID_HANDLE_VALUE)
  2814. RegCloseKey( hKeyDevMode );
  2815. return pRetDevMode;
  2816. }
  2817. VOID
  2818. MergeDevMode(
  2819. LPDEVMODEW pDMOut,
  2820. LPDEVMODEW pDMIn
  2821. )
  2822. {
  2823. //
  2824. // Simply check each bit in the dmFields entry. If set, then copy
  2825. // the input data to the output data.
  2826. //
  2827. if ( pDMIn->dmFields & DM_ORIENTATION ) {
  2828. pDMOut->dmOrientation = pDMIn->dmOrientation;
  2829. pDMOut->dmFields |= DM_ORIENTATION;
  2830. }
  2831. if( (pDMIn->dmFields & (DM_FORMNAME | DM_PAPERSIZE)) ||
  2832. (pDMIn->dmFields & (DM_PAPERLENGTH | DM_PAPERWIDTH)) ==
  2833. (DM_PAPERLENGTH | DM_PAPERWIDTH) )
  2834. {
  2835. //
  2836. // Value user fields, so use them. And delete ALL ours!
  2837. //
  2838. pDMOut->dmFields &= ~(DM_FORMNAME | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH);
  2839. if( pDMIn->dmFields & DM_PAPERSIZE )
  2840. {
  2841. pDMOut->dmPaperSize = pDMIn->dmPaperSize;
  2842. pDMOut->dmFields |= DM_PAPERSIZE;
  2843. }
  2844. if( pDMIn->dmFields & DM_PAPERLENGTH )
  2845. {
  2846. pDMOut->dmPaperLength = pDMIn->dmPaperLength;
  2847. pDMOut->dmFields |= DM_PAPERLENGTH;
  2848. }
  2849. if( pDMIn->dmFields & DM_PAPERWIDTH )
  2850. {
  2851. pDMOut->dmPaperWidth = pDMIn->dmPaperWidth;
  2852. pDMOut->dmFields |= DM_PAPERWIDTH;
  2853. }
  2854. if( pDMIn->dmFields & DM_FORMNAME )
  2855. {
  2856. CopyMemory( pDMOut->dmFormName, pDMIn->dmFormName,
  2857. sizeof( pDMOut->dmFormName ) );
  2858. pDMOut->dmFields |= DM_FORMNAME;
  2859. }
  2860. }
  2861. if( pDMIn->dmFields & DM_SCALE ) {
  2862. pDMOut->dmScale = pDMIn->dmScale;
  2863. pDMOut->dmFields |= DM_SCALE;
  2864. }
  2865. if ( pDMIn->dmFields & DM_COPIES ) {
  2866. pDMOut->dmCopies = pDMIn->dmCopies;
  2867. pDMOut->dmFields |= DM_COPIES;
  2868. }
  2869. if ( pDMIn->dmFields & DM_DEFAULTSOURCE ) {
  2870. pDMOut->dmDefaultSource = pDMIn->dmDefaultSource;
  2871. pDMOut->dmFields |= DM_DEFAULTSOURCE;
  2872. }
  2873. if ( pDMIn->dmFields & DM_PRINTQUALITY ) {
  2874. pDMOut->dmPrintQuality = pDMIn->dmPrintQuality;
  2875. pDMOut->dmFields |= DM_PRINTQUALITY;
  2876. }
  2877. if ( pDMIn->dmFields & DM_COLOR ) {
  2878. pDMOut->dmColor = pDMIn->dmColor;
  2879. pDMOut->dmFields |= DM_COLOR;
  2880. }
  2881. if ( pDMIn->dmFields & DM_DUPLEX ) {
  2882. pDMOut->dmDuplex = pDMIn->dmDuplex;
  2883. pDMOut->dmFields |= DM_DUPLEX;
  2884. }
  2885. if ( pDMIn->dmFields & DM_YRESOLUTION ) {
  2886. //
  2887. // Note that DM_YRESOLUTION implies there is data in dmPrintQuality.
  2888. // This latter field is used to specify the desired X resolution,
  2889. // which is only required for dot matrix printers.
  2890. //
  2891. pDMOut->dmYResolution = pDMIn->dmYResolution;
  2892. pDMOut->dmPrintQuality = pDMIn->dmPrintQuality;
  2893. pDMOut->dmFields |= DM_YRESOLUTION;
  2894. }
  2895. if ( pDMIn->dmFields & DM_TTOPTION ) {
  2896. pDMOut->dmTTOption = pDMIn->dmTTOption;
  2897. pDMOut->dmFields |= DM_TTOPTION;
  2898. }
  2899. if ( pDMIn->dmFields & DM_COLLATE ) {
  2900. pDMOut->dmCollate = pDMIn->dmCollate;
  2901. pDMOut->dmFields |= DM_COLLATE;
  2902. }
  2903. if ( pDMIn->dmFields & DM_ICMMETHOD ) {
  2904. pDMOut->dmICMMethod = pDMIn->dmICMMethod;
  2905. pDMOut->dmFields |= DM_ICMMETHOD;
  2906. }
  2907. if ( pDMIn->dmFields & DM_ICMINTENT ) {
  2908. pDMOut->dmICMIntent = pDMIn->dmICMIntent;
  2909. pDMOut->dmFields |= DM_ICMINTENT;
  2910. }
  2911. if ( pDMIn->dmFields & DM_MEDIATYPE ) {
  2912. pDMOut->dmMediaType = pDMIn->dmMediaType;
  2913. pDMOut->dmFields |= DM_MEDIATYPE;
  2914. }
  2915. if ( pDMIn->dmFields & DM_DITHERTYPE ) {
  2916. pDMOut->dmDitherType = pDMIn->dmDitherType;
  2917. pDMOut->dmFields |= DM_DITHERTYPE;
  2918. }
  2919. }
  2920. LONG
  2921. ExtDeviceMode(
  2922. HWND hWnd,
  2923. HANDLE hInst,
  2924. LPDEVMODEA pDevModeOutput,
  2925. LPSTR pDeviceName,
  2926. LPSTR pPort,
  2927. LPDEVMODEA pDevModeInput,
  2928. LPSTR pProfile,
  2929. DWORD fMode
  2930. )
  2931. {
  2932. HANDLE hPrinter = NULL;
  2933. LONG cbDevMode;
  2934. DWORD NewfMode;
  2935. LPDEVMODEW pNewDevModeIn = NULL;
  2936. LPDEVMODEW pNewDevModeOut = NULL, pTempDevMode = NULL;
  2937. LONG ReturnValue = -1;
  2938. PRINTER_DEFAULTSW PrinterDefaults={NULL, NULL, PRINTER_READ};
  2939. LPWSTR pUnicodeDeviceName;
  2940. LPWSTR pUnicodePort;
  2941. pUnicodeDeviceName = AllocateUnicodeString(pDeviceName);
  2942. if (pDeviceName && !pUnicodeDeviceName)
  2943. return ReturnValue;
  2944. pUnicodePort = AllocateUnicodeString(pPort);
  2945. if (pPort && !pUnicodePort) {
  2946. FreeUnicodeString(pUnicodeDeviceName);
  2947. return ReturnValue;
  2948. }
  2949. if (OpenPrinterW(pUnicodeDeviceName, &hPrinter, &PrinterDefaults)) {
  2950. cbDevMode = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName,
  2951. NULL, NULL, 0);
  2952. if (!fMode || cbDevMode <= 0) {
  2953. ClosePrinter(hPrinter);
  2954. FreeUnicodeString(pUnicodeDeviceName);
  2955. FreeUnicodeString(pUnicodePort);
  2956. if (!fMode)
  2957. cbDevMode -= sizeof(DEVMODEW) - sizeof(DEVMODEA);
  2958. return cbDevMode;
  2959. }
  2960. pNewDevModeOut = (PDEVMODEW)LocalAlloc( LMEM_FIXED, cbDevMode );
  2961. if( !pNewDevModeOut ){
  2962. ClosePrinter(hPrinter);
  2963. FreeUnicodeString(pUnicodeDeviceName);
  2964. FreeUnicodeString(pUnicodePort);
  2965. return -1;
  2966. }
  2967. //
  2968. // If our flags specify an input DevMode, and we have
  2969. // an input devmode, use it.
  2970. //
  2971. if(( fMode & DM_IN_BUFFER ) && pDevModeInput ){
  2972. //
  2973. // App may specify one or two fields in dmFields and expect us
  2974. // to merge it with the global 16-bit devmode
  2975. //
  2976. pNewDevModeIn = AllocateCurDevMode(hPrinter,
  2977. pUnicodeDeviceName,
  2978. cbDevMode);
  2979. pTempDevMode = AllocateUnicodeDevMode(pDevModeInput);
  2980. //
  2981. // correct any bogus field settings for the papersize stuff
  2982. //
  2983. ValidatePaperFields(pUnicodeDeviceName,
  2984. pUnicodePort,
  2985. pTempDevMode);
  2986. if ( !pNewDevModeIn || !pTempDevMode ) {
  2987. if ( pNewDevModeIn )
  2988. LocalFree(pNewDevModeIn);
  2989. if ( pTempDevMode )
  2990. LocalFree(pTempDevMode);
  2991. ClosePrinter(hPrinter);
  2992. FreeUnicodeString(pUnicodeDeviceName);
  2993. FreeUnicodeString(pUnicodePort);
  2994. return -1;
  2995. }
  2996. //
  2997. // Some apps will just set the public fields they want to be changed
  2998. // from global devmode, so we need to merge input devmode with global
  2999. // devmode
  3000. //
  3001. MergeDevMode(pNewDevModeIn, pTempDevMode);
  3002. //
  3003. // Copy input devmode's private section if present else send the
  3004. // the private section from global devmode
  3005. //
  3006. if ( pTempDevMode->dmDriverExtra &&
  3007. pTempDevMode->dmDriverExtra == pNewDevModeIn->dmDriverExtra ) {
  3008. CopyMemory((LPBYTE)pNewDevModeIn + pNewDevModeIn->dmSize,
  3009. (LPBYTE)pTempDevMode + pTempDevMode->dmSize,
  3010. pTempDevMode->dmDriverExtra);
  3011. }
  3012. LocalFree(pTempDevMode);
  3013. pTempDevMode = NULL;
  3014. } else {
  3015. //
  3016. // Get the win16 global devmode.
  3017. //
  3018. pNewDevModeIn = AllocateCurDevMode( hPrinter,
  3019. pUnicodeDeviceName,
  3020. cbDevMode );
  3021. if (!pNewDevModeIn) {
  3022. ClosePrinter(hPrinter);
  3023. FreeUnicodeString(pUnicodeDeviceName);
  3024. FreeUnicodeString(pUnicodePort);
  3025. return -1;
  3026. }
  3027. fMode |= DM_IN_BUFFER;
  3028. }
  3029. NewfMode = fMode;
  3030. //
  3031. // If DM_UPDATE is set, turn on DM_COPY so that we can update
  3032. // the win16 devmode.
  3033. //
  3034. if (fMode & DM_UPDATE)
  3035. NewfMode |= DM_COPY;
  3036. ReturnValue = DocumentPropertiesW(hWnd,
  3037. hPrinter,
  3038. pUnicodeDeviceName,
  3039. pNewDevModeOut,
  3040. pNewDevModeIn,
  3041. NewfMode);
  3042. if ( ReturnValue == IDOK &&
  3043. (fMode & DM_UPDATE) ) {
  3044. if ( WriteCurDevModeToRegistry(pUnicodeDeviceName,
  3045. pNewDevModeOut) ) {
  3046. SendNotifyMessageW(HWND_BROADCAST,
  3047. WM_DEVMODECHANGE,
  3048. 0,
  3049. (LPARAM)pUnicodeDeviceName);
  3050. } else {
  3051. ReturnValue = -1;
  3052. }
  3053. }
  3054. if (pNewDevModeIn)
  3055. LocalFree(pNewDevModeIn);
  3056. if ((ReturnValue == IDOK) && (fMode & DM_COPY) && pDevModeOutput)
  3057. CopyAnsiDevModeFromUnicodeDevMode(pDevModeOutput, pNewDevModeOut);
  3058. if (pNewDevModeOut)
  3059. LocalFree(pNewDevModeOut);
  3060. ClosePrinter(hPrinter);
  3061. }
  3062. FreeUnicodeString(pUnicodeDeviceName);
  3063. FreeUnicodeString(pUnicodePort);
  3064. return ReturnValue;
  3065. }
  3066. void
  3067. DeviceMode(
  3068. HWND hWnd,
  3069. HANDLE hModule,
  3070. LPSTR pDevice,
  3071. LPSTR pPort
  3072. )
  3073. {
  3074. HANDLE hPrinter, hDevMode;
  3075. DWORD cbDevMode;
  3076. LPDEVMODEW pNewDevMode, pDevMode=NULL;
  3077. PRINTER_DEFAULTSW PrinterDefaults={NULL, NULL, PRINTER_READ};
  3078. DWORD Status, Type, cb;
  3079. LPWSTR pUnicodeDevice;
  3080. pUnicodeDevice = AllocateUnicodeString(pDevice);
  3081. if (pDevice && !pUnicodeDevice)
  3082. return;
  3083. if (OpenPrinterW(pUnicodeDevice, &hPrinter, &PrinterDefaults)) {
  3084. Status = RegCreateKeyExW(HKEY_CURRENT_USER, szCurDevMode,
  3085. 0, NULL, 0, KEY_WRITE | KEY_READ,
  3086. NULL, &hDevMode, NULL);
  3087. if (Status == ERROR_SUCCESS) {
  3088. Status = RegQueryValueExW(hDevMode, pUnicodeDevice, 0, &Type,
  3089. NULL, &cb);
  3090. if (Status == ERROR_SUCCESS) {
  3091. pDevMode = LocalAlloc(LMEM_FIXED, cb);
  3092. if (pDevMode) {
  3093. Status = RegQueryValueExW(hDevMode, pUnicodeDevice, 0,
  3094. &Type, (LPBYTE)pDevMode, &cb);
  3095. if (Status != ERROR_SUCCESS || BoolFromHResult(SplIsValidDevmodeNoSizeW(pDevMode))) {
  3096. LocalFree(pDevMode);
  3097. pDevMode = NULL;
  3098. }
  3099. } else {
  3100. goto Cleanup;
  3101. }
  3102. }
  3103. cbDevMode = DocumentPropertiesW(hWnd, hPrinter,
  3104. pUnicodeDevice, NULL,
  3105. pDevMode, 0);
  3106. if (cbDevMode > 0) {
  3107. if (pNewDevMode = (PDEVMODEW)LocalAlloc(LMEM_FIXED,
  3108. cbDevMode)) {
  3109. if (DocumentPropertiesW(hWnd,
  3110. hPrinter, pUnicodeDevice,
  3111. pNewDevMode,
  3112. pDevMode,
  3113. DM_COPY | DM_PROMPT | DM_MODIFY)
  3114. == IDOK) {
  3115. Status = RegSetValueExW(hDevMode,
  3116. pUnicodeDevice, 0,
  3117. REG_BINARY,
  3118. (LPBYTE)pNewDevMode,
  3119. pNewDevMode->dmSize +
  3120. pNewDevMode->dmDriverExtra);
  3121. //
  3122. // Everything succeeded if Status == ERROR_SUCCESS.
  3123. //
  3124. }
  3125. LocalFree(pNewDevMode);
  3126. }
  3127. }
  3128. if (pDevMode)
  3129. LocalFree(pDevMode);
  3130. RegCloseKey(hDevMode);
  3131. }
  3132. ClosePrinter(hPrinter);
  3133. }
  3134. Cleanup:
  3135. FreeUnicodeString(pUnicodeDevice);
  3136. return;
  3137. }
  3138. LONG
  3139. AdvancedDocumentPropertiesA(
  3140. HWND hWnd,
  3141. HANDLE hPrinter,
  3142. LPSTR pDeviceName,
  3143. PDEVMODEA pDevModeOutput,
  3144. PDEVMODEA pDevModeInput
  3145. )
  3146. {
  3147. LONG ReturnValue = FALSE;
  3148. LPWSTR pUnicodeDeviceName = NULL;
  3149. LPDEVMODEW pUnicodeDevModeInput = NULL;
  3150. LPDEVMODEW pUnicodeDevModeOutput = NULL;
  3151. LONG cbOutput = 0;
  3152. pUnicodeDeviceName = AllocateUnicodeString(pDeviceName);
  3153. if (pDeviceName && !pUnicodeDeviceName)
  3154. goto Cleanup;
  3155. if( BoolFromHResult(SplIsValidDevmodeNoSizeA(pDevModeInput))){
  3156. pUnicodeDevModeInput = AllocateUnicodeDevMode(pDevModeInput);
  3157. if( !pUnicodeDevModeInput ){
  3158. goto Cleanup;
  3159. }
  3160. //
  3161. // The output DevMode must be at least as big as the input
  3162. // DevMode.
  3163. //
  3164. cbOutput = pDevModeInput->dmSize +
  3165. pDevModeInput->dmDriverExtra +
  3166. sizeof(DEVMODEW) - sizeof(DEVMODEA);
  3167. }
  3168. if( pDevModeOutput ){
  3169. if( !cbOutput ){
  3170. //
  3171. // We don't know the output size of the devmode, so make
  3172. // call DocumentPropertiesW to find out.
  3173. //
  3174. cbOutput = DocumentPropertiesW( hWnd,
  3175. hPrinter,
  3176. pUnicodeDeviceName,
  3177. NULL,
  3178. NULL,
  3179. 0 );
  3180. if( cbOutput <= 0 ){
  3181. goto Cleanup;
  3182. }
  3183. }
  3184. pUnicodeDevModeOutput = (PDEVMODEW)LocalAlloc( LPTR, cbOutput );
  3185. if( !pUnicodeDevModeOutput ){
  3186. goto Cleanup;
  3187. }
  3188. }
  3189. ReturnValue = AdvancedDocumentPropertiesW(hWnd, hPrinter,
  3190. pUnicodeDeviceName,
  3191. pUnicodeDevModeOutput,
  3192. pUnicodeDevModeInput );
  3193. if( pDevModeOutput && (ReturnValue > 0) ){
  3194. CopyAnsiDevModeFromUnicodeDevMode(pDevModeOutput,
  3195. pUnicodeDevModeOutput);
  3196. }
  3197. if ( !pDevModeOutput && ReturnValue > 0 )
  3198. ReturnValue -= sizeof(DEVMODEW) - sizeof(DEVMODEA);
  3199. Cleanup:
  3200. if (pUnicodeDevModeOutput)
  3201. LocalFree(pUnicodeDevModeOutput);
  3202. if (pUnicodeDevModeInput)
  3203. LocalFree(pUnicodeDevModeInput);
  3204. FreeUnicodeString(pUnicodeDeviceName);
  3205. return ReturnValue;
  3206. }
  3207. LONG
  3208. AdvancedSetupDialog(
  3209. HWND hWnd,
  3210. HANDLE hInst,
  3211. LPDEVMODEA pDevModeInput,
  3212. LPDEVMODEA pDevModeOutput
  3213. )
  3214. {
  3215. HANDLE hPrinter;
  3216. LONG ReturnValue = -1;
  3217. if (OpenPrinterA(pDevModeInput->dmDeviceName, &hPrinter, NULL)) {
  3218. ReturnValue = AdvancedDocumentPropertiesA(hWnd, hPrinter,
  3219. pDevModeInput->dmDeviceName,
  3220. pDevModeOutput,
  3221. pDevModeInput);
  3222. ClosePrinter(hPrinter);
  3223. }
  3224. return ReturnValue;
  3225. }
  3226. BOOL
  3227. AddFormA(
  3228. HANDLE hPrinter,
  3229. DWORD Level,
  3230. LPBYTE pForm
  3231. )
  3232. {
  3233. BOOL ReturnValue;
  3234. LPBYTE pUnicodeForm;
  3235. pUnicodeForm = AllocateUnicodeStructure(pForm, sizeof(FORM_INFO_1A), FormInfo1Strings);
  3236. if (pForm && !pUnicodeForm)
  3237. return FALSE;
  3238. ReturnValue = AddFormW(hPrinter, Level, pUnicodeForm);
  3239. FreeUnicodeStructure(pUnicodeForm, FormInfo1Offsets);
  3240. return ReturnValue;
  3241. }
  3242. BOOL
  3243. DeleteFormA(
  3244. HANDLE hPrinter,
  3245. LPSTR pFormName
  3246. )
  3247. {
  3248. BOOL ReturnValue;
  3249. LPWSTR pUnicodeFormName;
  3250. pUnicodeFormName = AllocateUnicodeString(pFormName);
  3251. if (pFormName && !pUnicodeFormName)
  3252. return FALSE;
  3253. ReturnValue = DeleteFormW(hPrinter, pUnicodeFormName);
  3254. FreeUnicodeString(pUnicodeFormName);
  3255. return ReturnValue;
  3256. }
  3257. BOOL
  3258. GetFormA(
  3259. HANDLE hPrinter,
  3260. LPSTR pFormName,
  3261. DWORD Level,
  3262. LPBYTE pForm,
  3263. DWORD cbBuf,
  3264. LPDWORD pcbNeeded
  3265. )
  3266. {
  3267. BOOL ReturnValue;
  3268. DWORD *pOffsets;
  3269. LPWSTR pUnicodeFormName;
  3270. switch (Level) {
  3271. case 1:
  3272. pOffsets = FormInfo1Strings;
  3273. break;
  3274. default:
  3275. SetLastError(ERROR_INVALID_LEVEL);
  3276. return FALSE;
  3277. }
  3278. pUnicodeFormName = AllocateUnicodeString(pFormName);
  3279. if (pFormName && !pUnicodeFormName)
  3280. return FALSE;
  3281. ReturnValue = GetFormW(hPrinter, pUnicodeFormName, Level, pForm,
  3282. cbBuf, pcbNeeded);
  3283. if (ReturnValue && pForm)
  3284. ConvertUnicodeToAnsiStrings(pForm, pOffsets);
  3285. FreeUnicodeString(pUnicodeFormName);
  3286. return ReturnValue;
  3287. }
  3288. BOOL
  3289. SetFormA(
  3290. HANDLE hPrinter,
  3291. LPSTR pFormName,
  3292. DWORD Level,
  3293. LPBYTE pForm
  3294. )
  3295. {
  3296. BOOL ReturnValue = FALSE;
  3297. LPWSTR pUnicodeFormName = NULL;
  3298. LPBYTE pUnicodeForm = NULL;
  3299. pUnicodeFormName = AllocateUnicodeString(pFormName);
  3300. if (pFormName && !pUnicodeFormName)
  3301. goto Cleanup;
  3302. pUnicodeForm = AllocateUnicodeStructure(pForm, sizeof(FORM_INFO_1A), FormInfo1Strings);
  3303. if (pForm && !pUnicodeForm)
  3304. goto Cleanup;
  3305. ReturnValue = SetFormW(hPrinter, pUnicodeFormName, Level, pUnicodeForm);
  3306. Cleanup:
  3307. FreeUnicodeString(pUnicodeFormName);
  3308. FreeUnicodeStructure(pUnicodeForm, FormInfo1Offsets);
  3309. return ReturnValue;
  3310. }
  3311. BOOL
  3312. EnumFormsA(
  3313. HANDLE hPrinter,
  3314. DWORD Level,
  3315. LPBYTE pForm,
  3316. DWORD cbBuf,
  3317. LPDWORD pcbNeeded,
  3318. LPDWORD pcReturned
  3319. )
  3320. {
  3321. BOOL ReturnValue;
  3322. DWORD cbStruct;
  3323. DWORD *pOffsets;
  3324. switch (Level) {
  3325. case 1:
  3326. pOffsets = FormInfo1Strings;
  3327. cbStruct = sizeof(FORM_INFO_1);
  3328. break;
  3329. default:
  3330. SetLastError(ERROR_INVALID_LEVEL);
  3331. return FALSE;
  3332. }
  3333. ReturnValue = EnumFormsW(hPrinter, Level, pForm, cbBuf,
  3334. pcbNeeded, pcReturned);
  3335. if (ReturnValue && pForm) {
  3336. DWORD i=*pcReturned;
  3337. while (i--) {
  3338. ConvertUnicodeToAnsiStrings(pForm, pOffsets);
  3339. pForm+=cbStruct;
  3340. }
  3341. }
  3342. return ReturnValue;
  3343. }
  3344. BOOL
  3345. EnumPortsA(
  3346. LPSTR pName,
  3347. DWORD Level,
  3348. LPBYTE pPort,
  3349. DWORD cbBuf,
  3350. LPDWORD pcbNeeded,
  3351. LPDWORD pcReturned
  3352. )
  3353. {
  3354. BOOL ReturnValue = FALSE;
  3355. DWORD cbStruct;
  3356. DWORD *pOffsets;
  3357. LPWSTR pUnicodeName = NULL;
  3358. switch (Level) {
  3359. case 1:
  3360. pOffsets = PortInfo1Strings;
  3361. cbStruct = sizeof(PORT_INFO_1);
  3362. break;
  3363. case 2:
  3364. pOffsets = PortInfo2Strings;
  3365. cbStruct = sizeof(PORT_INFO_2);
  3366. break;
  3367. default:
  3368. SetLastError(ERROR_INVALID_LEVEL);
  3369. return FALSE;
  3370. }
  3371. pUnicodeName = AllocateUnicodeString(pName);
  3372. if (pName && !pUnicodeName)
  3373. goto Cleanup;
  3374. ReturnValue = EnumPortsW(pUnicodeName, Level, pPort, cbBuf,
  3375. pcbNeeded, pcReturned);
  3376. if (ReturnValue && pPort) {
  3377. DWORD i=*pcReturned;
  3378. while (i--) {
  3379. ConvertUnicodeToAnsiStrings(pPort, pOffsets);
  3380. pPort+=cbStruct;
  3381. }
  3382. }
  3383. Cleanup:
  3384. FreeUnicodeString(pUnicodeName);
  3385. return ReturnValue;
  3386. }
  3387. BOOL
  3388. EnumMonitorsA(
  3389. LPSTR pName,
  3390. DWORD Level,
  3391. LPBYTE pMonitor,
  3392. DWORD cbBuf,
  3393. LPDWORD pcbNeeded,
  3394. LPDWORD pcReturned
  3395. )
  3396. {
  3397. BOOL ReturnValue = FALSE;
  3398. DWORD cbStruct;
  3399. DWORD *pOffsets;
  3400. LPWSTR pUnicodeName = NULL;
  3401. switch (Level) {
  3402. case 1:
  3403. pOffsets = MonitorInfo1Strings;
  3404. cbStruct = sizeof(MONITOR_INFO_1);
  3405. break;
  3406. case 2:
  3407. pOffsets = MonitorInfo2Strings;
  3408. cbStruct = sizeof(MONITOR_INFO_2);
  3409. break;
  3410. default:
  3411. SetLastError(ERROR_INVALID_LEVEL);
  3412. return FALSE;
  3413. }
  3414. pUnicodeName = AllocateUnicodeString(pName);
  3415. if (pName && !pUnicodeName)
  3416. goto Cleanup;
  3417. ReturnValue = EnumMonitorsW(pUnicodeName, Level, pMonitor, cbBuf,
  3418. pcbNeeded, pcReturned);
  3419. if (ReturnValue && pMonitor) {
  3420. DWORD i=*pcReturned;
  3421. while (i--) {
  3422. ConvertUnicodeToAnsiStrings(pMonitor, pOffsets);
  3423. pMonitor+=cbStruct;
  3424. }
  3425. }
  3426. Cleanup:
  3427. FreeUnicodeString(pUnicodeName);
  3428. return ReturnValue;
  3429. }
  3430. BOOL
  3431. AddPortA(
  3432. LPSTR pName,
  3433. HWND hWnd,
  3434. LPSTR pMonitorName
  3435. )
  3436. {
  3437. LPWSTR pUnicodeName = NULL;
  3438. LPWSTR pUnicodeMonitorName = NULL;
  3439. DWORD ReturnValue = FALSE;
  3440. pUnicodeName = AllocateUnicodeString(pName);
  3441. if (pName && !pUnicodeName)
  3442. goto Cleanup;
  3443. pUnicodeMonitorName = AllocateUnicodeString(pMonitorName);
  3444. if (pMonitorName && !pUnicodeMonitorName)
  3445. goto Cleanup;
  3446. ReturnValue = AddPortW( pUnicodeName, hWnd, pUnicodeMonitorName );
  3447. Cleanup:
  3448. FreeUnicodeString(pUnicodeName);
  3449. FreeUnicodeString(pUnicodeMonitorName);
  3450. return ReturnValue;
  3451. }
  3452. BOOL
  3453. ConfigurePortA(
  3454. LPSTR pName,
  3455. HWND hWnd,
  3456. LPSTR pPortName
  3457. )
  3458. {
  3459. LPWSTR pUnicodeName = NULL;
  3460. LPWSTR pUnicodePortName = NULL;
  3461. DWORD ReturnValue = FALSE;
  3462. pUnicodeName = AllocateUnicodeString(pName);
  3463. if (pName && !pUnicodeName)
  3464. goto Cleanup;
  3465. pUnicodePortName = AllocateUnicodeString(pPortName);
  3466. if (pPortName && !pUnicodePortName)
  3467. goto Cleanup;
  3468. ReturnValue = ConfigurePortW( pUnicodeName, hWnd, pUnicodePortName );
  3469. Cleanup:
  3470. FreeUnicodeString(pUnicodeName);
  3471. FreeUnicodeString(pUnicodePortName);
  3472. return ReturnValue;
  3473. }
  3474. BOOL
  3475. DeletePortA(
  3476. LPSTR pName,
  3477. HWND hWnd,
  3478. LPSTR pPortName
  3479. )
  3480. {
  3481. LPWSTR pUnicodeName = NULL;
  3482. LPWSTR pUnicodePortName = NULL;
  3483. DWORD ReturnValue = FALSE;
  3484. pUnicodeName = AllocateUnicodeString(pName);
  3485. if (pName && !pUnicodeName)
  3486. goto Cleanup;
  3487. pUnicodePortName = AllocateUnicodeString(pPortName);
  3488. if (pPortName && !pUnicodePortName)
  3489. goto Cleanup;
  3490. ReturnValue = DeletePortW( pUnicodeName, hWnd, pUnicodePortName );
  3491. Cleanup:
  3492. FreeUnicodeString(pUnicodeName);
  3493. FreeUnicodeString(pUnicodePortName);
  3494. return ReturnValue;
  3495. }
  3496. DWORD
  3497. PrinterMessageBoxA(
  3498. HANDLE hPrinter,
  3499. DWORD Error,
  3500. HWND hWnd,
  3501. LPSTR pText,
  3502. LPSTR pCaption,
  3503. DWORD dwType
  3504. )
  3505. {
  3506. DWORD ReturnValue=FALSE;
  3507. LPWSTR pTextW = NULL;
  3508. LPWSTR pCaptionW = NULL;
  3509. pTextW = AllocateUnicodeString(pText);
  3510. if (pText && !pTextW)
  3511. goto Cleanup;
  3512. pCaptionW = AllocateUnicodeString(pCaption);
  3513. if (pCaption && !pCaptionW)
  3514. goto Cleanup;
  3515. ReturnValue = PrinterMessageBoxW(hPrinter, Error, hWnd, pTextW,
  3516. pCaptionW, dwType);
  3517. Cleanup:
  3518. FreeUnicodeString(pTextW);
  3519. FreeUnicodeString(pCaptionW);
  3520. return ReturnValue;
  3521. }
  3522. int
  3523. DeviceCapabilitiesA(
  3524. LPCSTR pDevice,
  3525. LPCSTR pPort,
  3526. WORD fwCapability,
  3527. LPSTR pOutput,
  3528. CONST DEVMODEA *pDevMode
  3529. )
  3530. {
  3531. LPWSTR pDeviceW = NULL;
  3532. LPWSTR pPortW = NULL;
  3533. LPWSTR pOutputW = NULL;
  3534. LPWSTR pKeepW = NULL;
  3535. LPDEVMODEW pDevModeW = NULL;
  3536. DWORD c, Size;
  3537. int cb = 0;
  3538. int rc = GDI_ERROR;
  3539. pDeviceW = AllocateUnicodeString((LPSTR)pDevice);
  3540. if (pDevice && !pDeviceW)
  3541. goto Cleanup;
  3542. pPortW = AllocateUnicodeString((LPSTR)pPort);
  3543. if (pPort && !pPortW)
  3544. goto Cleanup;
  3545. if( BoolFromHResult(SplIsValidDevmodeNoSizeA((LPDEVMODEA)pDevMode))){
  3546. pDevModeW = AllocateUnicodeDevMode((LPDEVMODEA)pDevMode);
  3547. if( !pDevModeW ){
  3548. goto Cleanup;
  3549. }
  3550. }
  3551. switch (fwCapability) {
  3552. //
  3553. // These will require Unicode to Ansi conversion
  3554. //
  3555. case DC_BINNAMES:
  3556. case DC_FILEDEPENDENCIES:
  3557. case DC_PAPERNAMES:
  3558. case DC_PERSONALITY:
  3559. case DC_MEDIAREADY:
  3560. case DC_MEDIATYPENAMES:
  3561. if (pOutput) {
  3562. cb = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability,
  3563. NULL, pDevModeW);
  3564. if (cb >= 0) {
  3565. switch (fwCapability) {
  3566. case DC_BINNAMES:
  3567. cb *= 48;
  3568. break;
  3569. case DC_PERSONALITY:
  3570. cb *= 64;
  3571. break;
  3572. case DC_FILEDEPENDENCIES:
  3573. case DC_PAPERNAMES:
  3574. case DC_MEDIAREADY:
  3575. case DC_MEDIATYPENAMES:
  3576. cb *= 128;
  3577. break;
  3578. }
  3579. pOutputW = pKeepW = LocalAlloc(LPTR, cb);
  3580. if (pKeepW) {
  3581. c = rc = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability,
  3582. pOutputW, pDevModeW);
  3583. switch (fwCapability) {
  3584. case DC_BINNAMES:
  3585. Size = 24;
  3586. break;
  3587. case DC_PERSONALITY:
  3588. Size = 32;
  3589. break;
  3590. case DC_FILEDEPENDENCIES:
  3591. case DC_PAPERNAMES:
  3592. case DC_MEDIAREADY:
  3593. case DC_MEDIATYPENAMES:
  3594. Size = 64;
  3595. break;
  3596. }
  3597. for (; c; c--) {
  3598. UnicodeToAnsiString(pOutputW, pOutput, NULL_TERMINATED);
  3599. pOutputW += Size;
  3600. pOutput += Size;
  3601. }
  3602. LocalFree(pKeepW);
  3603. }
  3604. }
  3605. } else {
  3606. rc = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability,
  3607. NULL, pDevModeW);
  3608. }
  3609. break;
  3610. default:
  3611. rc = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability, (LPWSTR)pOutput, pDevModeW);
  3612. //
  3613. // If the call to find size of public portion of devmode and
  3614. // it was succesful adjust the size for UNICODE->ANSI conversion
  3615. //
  3616. if ( fwCapability == DC_SIZE && rc > 0 ) {
  3617. rc -= sizeof(DEVMODEW) - sizeof(DEVMODEA);
  3618. }
  3619. }
  3620. Cleanup:
  3621. FreeUnicodeString(pDeviceW);
  3622. FreeUnicodeString(pPortW);
  3623. if (pDevModeW)
  3624. LocalFree(pDevModeW);
  3625. return rc;
  3626. }
  3627. BOOL
  3628. AddMonitorA(
  3629. LPSTR pName,
  3630. DWORD Level,
  3631. LPBYTE pMonitorInfo
  3632. )
  3633. {
  3634. BOOL ReturnValue=FALSE;
  3635. DWORD cbStruct;
  3636. LPWSTR pUnicodeName = NULL;
  3637. LPBYTE pUnicodeStructure = NULL;
  3638. LPDWORD pOffsets;
  3639. switch (Level) {
  3640. case 2:
  3641. pOffsets = MonitorInfo2Strings;
  3642. cbStruct = sizeof(MONITOR_INFO_2);
  3643. break;
  3644. default:
  3645. SetLastError(ERROR_INVALID_LEVEL);
  3646. return FALSE;
  3647. }
  3648. pUnicodeStructure = AllocateUnicodeStructure(pMonitorInfo, cbStruct, pOffsets);
  3649. if (pMonitorInfo && !pUnicodeStructure)
  3650. goto Cleanup;
  3651. pUnicodeName = AllocateUnicodeString(pName);
  3652. if (pName && !pUnicodeName)
  3653. goto Cleanup;
  3654. if (pUnicodeStructure) {
  3655. ReturnValue = AddMonitorW(pUnicodeName, Level, pUnicodeStructure);
  3656. }
  3657. Cleanup:
  3658. FreeUnicodeStructure(pUnicodeStructure, pOffsets);
  3659. FreeUnicodeString(pUnicodeName);
  3660. return ReturnValue;
  3661. }
  3662. BOOL
  3663. DeleteMonitorA(
  3664. LPSTR pName,
  3665. LPSTR pEnvironment,
  3666. LPSTR pMonitorName
  3667. )
  3668. {
  3669. LPWSTR pUnicodeName = NULL;
  3670. LPWSTR pUnicodeEnvironment = NULL;
  3671. LPWSTR pUnicodeMonitorName = NULL;
  3672. BOOL rc = FALSE;
  3673. pUnicodeName = AllocateUnicodeString(pName);
  3674. if (pName && !pUnicodeName)
  3675. goto Cleanup;
  3676. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  3677. if (pEnvironment && !pUnicodeEnvironment)
  3678. goto Cleanup;
  3679. pUnicodeMonitorName = AllocateUnicodeString(pMonitorName);
  3680. if (pMonitorName && !pUnicodeMonitorName)
  3681. goto Cleanup;
  3682. rc = DeleteMonitorW(pUnicodeName,
  3683. pUnicodeEnvironment,
  3684. pUnicodeMonitorName);
  3685. Cleanup:
  3686. FreeUnicodeString(pUnicodeName);
  3687. FreeUnicodeString(pUnicodeEnvironment);
  3688. FreeUnicodeString(pUnicodeMonitorName);
  3689. return rc;
  3690. }
  3691. BOOL
  3692. DeletePrintProcessorA(
  3693. LPSTR pName,
  3694. LPSTR pEnvironment,
  3695. LPSTR pPrintProcessorName
  3696. )
  3697. {
  3698. LPWSTR pUnicodeName = NULL;
  3699. LPWSTR pUnicodeEnvironment = NULL;
  3700. LPWSTR pUnicodePrintProcessorName = NULL;
  3701. BOOL rc = FALSE;
  3702. if (!pPrintProcessorName || !*pPrintProcessorName) {
  3703. SetLastError(ERROR_INVALID_PARAMETER);
  3704. return FALSE;
  3705. }
  3706. pUnicodeName = AllocateUnicodeString(pName);
  3707. if (pName && !pUnicodeName)
  3708. goto Cleanup;
  3709. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  3710. if (pEnvironment && !pUnicodeEnvironment)
  3711. goto Cleanup;
  3712. pUnicodePrintProcessorName = AllocateUnicodeString(pPrintProcessorName);
  3713. if (pPrintProcessorName && !pUnicodePrintProcessorName)
  3714. goto Cleanup;
  3715. rc = DeletePrintProcessorW(pUnicodeName,
  3716. pUnicodeEnvironment,
  3717. pUnicodePrintProcessorName);
  3718. Cleanup:
  3719. FreeUnicodeString(pUnicodeName);
  3720. FreeUnicodeString(pUnicodeEnvironment);
  3721. FreeUnicodeString(pUnicodePrintProcessorName);
  3722. return rc;
  3723. }
  3724. BOOL
  3725. AddPrintProvidorA(
  3726. LPSTR pName,
  3727. DWORD Level,
  3728. LPBYTE pProvidorInfo
  3729. )
  3730. {
  3731. BOOL ReturnValue=FALSE;
  3732. DWORD cbStruct;
  3733. LPWSTR pUnicodeName = NULL;
  3734. LPBYTE pUnicodeStructure = NULL;
  3735. LPDWORD pOffsets;
  3736. if (!pProvidorInfo)
  3737. {
  3738. SetLastError(ERROR_INVALID_PARAMETER);
  3739. return FALSE;
  3740. }
  3741. switch (Level) {
  3742. case 1:
  3743. pOffsets = ProvidorInfo1Strings;
  3744. cbStruct = sizeof(PROVIDOR_INFO_1);
  3745. break;
  3746. case 2:
  3747. pOffsets = ProvidorInfo2Strings;
  3748. cbStruct = sizeof(PROVIDOR_INFO_2);
  3749. break;
  3750. default:
  3751. SetLastError(ERROR_INVALID_LEVEL);
  3752. return FALSE;
  3753. }
  3754. pUnicodeStructure = AllocateUnicodeStructure(pProvidorInfo, cbStruct, pOffsets);
  3755. if (!pProvidorInfo || !pUnicodeStructure)
  3756. goto CleanUp;
  3757. pUnicodeName = AllocateUnicodeString(pName);
  3758. if (pName && !pUnicodeName)
  3759. goto CleanUp;
  3760. if ((Level == 2) &&
  3761. !AnsiToUnicodeMultiSz((LPSTR) ((PPROVIDOR_INFO_2A) pProvidorInfo)->pOrder,
  3762. &(((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder))) {
  3763. goto CleanUp;
  3764. }
  3765. if (pUnicodeStructure) {
  3766. ReturnValue = AddPrintProvidorW(pUnicodeName, Level,
  3767. pUnicodeStructure);
  3768. }
  3769. if ((Level == 2) &&
  3770. ((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder) {
  3771. LocalFree(((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder);
  3772. ((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder = NULL;
  3773. }
  3774. CleanUp:
  3775. FreeUnicodeStructure(pUnicodeStructure, pOffsets);
  3776. FreeUnicodeString(pUnicodeName);
  3777. return ReturnValue;
  3778. }
  3779. BOOL
  3780. DeletePrintProvidorA(
  3781. LPSTR pName,
  3782. LPSTR pEnvironment,
  3783. LPSTR pPrintProvidorName
  3784. )
  3785. {
  3786. LPWSTR pUnicodeName = NULL;
  3787. LPWSTR pUnicodeEnvironment = NULL;
  3788. LPWSTR pUnicodePrintProvidorName = NULL;
  3789. BOOL rc = FALSE;
  3790. pUnicodeName = AllocateUnicodeString(pName);
  3791. if (pName && !pUnicodeName)
  3792. goto Cleanup;
  3793. pUnicodeEnvironment = AllocateUnicodeString(pEnvironment);
  3794. if (pEnvironment && !pUnicodeEnvironment)
  3795. goto Cleanup;
  3796. pUnicodePrintProvidorName = AllocateUnicodeString(pPrintProvidorName);
  3797. if (pPrintProvidorName && !pUnicodePrintProvidorName)
  3798. goto Cleanup;
  3799. rc = DeletePrintProvidorW(pUnicodeName,
  3800. pUnicodeEnvironment,
  3801. pUnicodePrintProvidorName);
  3802. Cleanup:
  3803. FreeUnicodeString(pUnicodeName);
  3804. FreeUnicodeString(pUnicodeEnvironment);
  3805. FreeUnicodeString(pUnicodePrintProvidorName);
  3806. return rc;
  3807. }
  3808. BOOL
  3809. AddPortExA(
  3810. IN LPSTR pName, OPTIONAL
  3811. IN DWORD Level,
  3812. IN LPBYTE pBuffer,
  3813. IN LPSTR pMonitorName
  3814. )
  3815. {
  3816. PPORT_INFO_1A pPortInfo1;
  3817. PPORT_INFO_FFA pPortInfoFF;
  3818. LPWSTR pNameW = NULL;
  3819. LPWSTR pMonitorNameW = NULL;
  3820. LPWSTR pPortNameW = NULL;
  3821. PORT_INFO_1W PortInfo1;
  3822. PORT_INFO_FFW PortInfoFF;
  3823. DWORD LastError = ERROR_SUCCESS;
  3824. BOOL bReturnValue = FALSE;
  3825. //
  3826. // Initialize variables that will be freed in error cases.
  3827. //
  3828. pNameW = AllocateUnicodeString( pName);
  3829. if (pName && !pNameW) {
  3830. LastError = GetLastError();
  3831. goto Done;
  3832. }
  3833. pPortNameW = NULL;
  3834. pMonitorNameW = AllocateUnicodeString( pMonitorName);
  3835. if (pMonitorName && !pMonitorNameW) {
  3836. LastError = GetLastError();
  3837. goto Done;
  3838. }
  3839. if( !pBuffer || !pMonitorName ){
  3840. LastError = ERROR_INVALID_PARAMETER;
  3841. goto Done;
  3842. }
  3843. //
  3844. // Catch out of memory conditions.
  3845. //
  3846. if( !pMonitorNameW || ( pName && !pNameW )){
  3847. LastError = GetLastError();
  3848. goto Done;
  3849. }
  3850. switch( Level ){
  3851. case (DWORD)-1:
  3852. pPortInfoFF = (PPORT_INFO_FFA)pBuffer;
  3853. if( !pPortInfoFF->pName || !pPortInfoFF->pName[0] ){
  3854. LastError = ERROR_INVALID_PARAMETER;
  3855. goto Done;
  3856. }
  3857. pPortNameW = PortInfoFF.pName = AllocateUnicodeString( pPortInfoFF->pName);
  3858. if( !pPortNameW ){
  3859. LastError = GetLastError();
  3860. goto Done;
  3861. }
  3862. PortInfoFF.cbMonitorData = pPortInfoFF->cbMonitorData;
  3863. PortInfoFF.pMonitorData = pPortInfoFF->pMonitorData;
  3864. bReturnValue = AddPortExW( pNameW,
  3865. Level,
  3866. (LPBYTE)&PortInfoFF,
  3867. pMonitorNameW );
  3868. if( !bReturnValue ){
  3869. LastError = GetLastError();
  3870. }
  3871. break;
  3872. case 1:
  3873. pPortInfo1 = (PPORT_INFO_1A)pBuffer;
  3874. if( !pPortInfo1->pName || !pPortInfo1->pName[0] ){
  3875. LastError = ERROR_INVALID_PARAMETER;
  3876. goto Done;
  3877. }
  3878. pPortNameW = PortInfo1.pName = AllocateUnicodeString( pPortInfo1->pName);
  3879. if( !pPortNameW ){
  3880. LastError = GetLastError();
  3881. goto Done;
  3882. }
  3883. bReturnValue = AddPortExW( pNameW,
  3884. Level,
  3885. (LPBYTE)&PortInfo1,
  3886. pMonitorNameW );
  3887. if( !bReturnValue ){
  3888. LastError = GetLastError();
  3889. }
  3890. break;
  3891. default:
  3892. LastError = ERROR_INVALID_LEVEL;
  3893. break;
  3894. }
  3895. Done:
  3896. FreeUnicodeString( pNameW );
  3897. FreeUnicodeString( pPortNameW );
  3898. FreeUnicodeString( pMonitorNameW );
  3899. if( !bReturnValue ){
  3900. SetLastError( LastError );
  3901. return FALSE;
  3902. }
  3903. return TRUE;
  3904. }
  3905. LPSTR
  3906. StartDocDlgA(
  3907. HANDLE hPrinter,
  3908. DOCINFOA *pDocInfo
  3909. )
  3910. {
  3911. DOCINFOW DocInfoW;
  3912. LPSTR lpszAnsiOutput = NULL;
  3913. LPSTR lpszAnsiString = NULL;
  3914. LPWSTR lpszUnicodeString = NULL;
  3915. DWORD dwLen = 0;
  3916. if (!pDocInfo) {
  3917. DBGMSG(DBG_WARNING, ("StartDocDlgA: Null pDocInfo passed in\n"));
  3918. return NULL;
  3919. }
  3920. memset(&DocInfoW, 0, sizeof(DOCINFOW));
  3921. if (pDocInfo->lpszDocName) {
  3922. DocInfoW.lpszDocName = (LPCWSTR)AllocateUnicodeString ((LPSTR)pDocInfo->lpszDocName);
  3923. if (pDocInfo->lpszDocName && !DocInfoW.lpszDocName)
  3924. return NULL;
  3925. }
  3926. if (pDocInfo->lpszOutput) {
  3927. DocInfoW.lpszOutput = (LPCWSTR)AllocateUnicodeString((LPSTR)pDocInfo->lpszOutput);
  3928. if (pDocInfo->lpszOutput && !DocInfoW.lpszOutput) {
  3929. FreeUnicodeString((LPWSTR) DocInfoW.lpszDocName);
  3930. return NULL;
  3931. }
  3932. }
  3933. lpszUnicodeString = StartDocDlgW(hPrinter, &DocInfoW);
  3934. if (lpszUnicodeString == (LPWSTR)-1) {
  3935. lpszAnsiString = (LPSTR)-1;
  3936. } else if (lpszUnicodeString == (LPWSTR)-2) {
  3937. lpszAnsiString = (LPSTR)-2;
  3938. } else if (lpszUnicodeString){
  3939. dwLen = wcslen(lpszUnicodeString);
  3940. if (lpszAnsiString = LocalAlloc(LPTR, dwLen+1)){
  3941. UnicodeToAnsiString(lpszUnicodeString, lpszAnsiString, dwLen);
  3942. LocalFree(lpszUnicodeString);
  3943. } else {
  3944. DBGMSG(DBG_WARNING, ("StartDocDlgA: LocalAlloc failed returning NULL\n"));
  3945. }
  3946. }
  3947. if (DocInfoW.lpszDocName ) {
  3948. FreeUnicodeString((LPWSTR)DocInfoW.lpszDocName);
  3949. }
  3950. if (DocInfoW.lpszOutput) {
  3951. //
  3952. // we might have changed the DocInfoW.lpszOutput as well
  3953. // for pooled printing; so reconstruct pDocInfo->lpszOutput
  3954. //
  3955. dwLen = wcslen(DocInfoW.lpszOutput);
  3956. UnicodeToAnsiString((LPWSTR)DocInfoW.lpszOutput, (LPSTR)pDocInfo->lpszOutput, dwLen);
  3957. FreeUnicodeString((LPWSTR)DocInfoW.lpszOutput);
  3958. }
  3959. return lpszAnsiString;
  3960. }
  3961. BOOL
  3962. SetPortA(
  3963. LPSTR pszName,
  3964. LPSTR pszPortName,
  3965. DWORD dwLevel,
  3966. LPBYTE pPorts
  3967. )
  3968. {
  3969. LPBYTE pUnicodeStructure = NULL;
  3970. DWORD cbStruct;
  3971. PDWORD pOffsets = NULL;
  3972. LPWSTR pszUnicodeName = NULL;
  3973. LPWSTR pszUnicodePortName = NULL;
  3974. BOOL bRet = FALSE;
  3975. switch (dwLevel) {
  3976. case 3:
  3977. pOffsets = PortInfo3Offsets;
  3978. cbStruct = sizeof(PORT_INFO_3);
  3979. break;
  3980. default:
  3981. SetLastError( ERROR_INVALID_LEVEL );
  3982. return FALSE;
  3983. }
  3984. pszUnicodeName = AllocateUnicodeString(pszName);
  3985. if (pszName && !pszUnicodeName)
  3986. goto Cleanup;
  3987. pszUnicodePortName = AllocateUnicodeString(pszPortName);
  3988. if (pszPortName && !pszUnicodePortName)
  3989. goto Cleanup;
  3990. pUnicodeStructure = AllocateUnicodeStructure(pPorts, cbStruct, pOffsets);
  3991. if (pPorts && !pUnicodeStructure)
  3992. goto Cleanup;
  3993. bRet = SetPortW(pszUnicodeName, pszUnicodePortName, dwLevel, pUnicodeStructure);
  3994. Cleanup:
  3995. FreeUnicodeStructure(pUnicodeStructure, pOffsets);
  3996. FreeUnicodeString(pszUnicodePortName);
  3997. FreeUnicodeString(pszUnicodeName);
  3998. return bRet;
  3999. }
  4000. /*++
  4001. Routine Name:
  4002. IsValidDevmodeA
  4003. Description:
  4004. Check to see whether the devmode passed is valid.
  4005. Arguments:
  4006. pDevmode - The devmode
  4007. DevmodeSize - The size of the buffer.
  4008. Return Value:
  4009. TRUE if succeeded.
  4010. --*/
  4011. BOOL
  4012. IsValidDevmodeA(
  4013. IN PDEVMODEA pDevmode,
  4014. IN size_t DevmodeSize
  4015. )
  4016. {
  4017. return BoolFromHResult(SplIsValidDevmodeA(pDevmode, DevmodeSize));
  4018. }
  4019. /********************************************************************
  4020. Ansi version entry points for the default printer api set.
  4021. ********************************************************************/
  4022. BOOL
  4023. GetDefaultPrinterA(
  4024. IN LPSTR pszBuffer,
  4025. IN LPDWORD pcchBuffer
  4026. )
  4027. {
  4028. BOOL bRetval = TRUE;
  4029. LPWSTR pszUnicodeBuffer = NULL;
  4030. LPDWORD pcchUnicodeBuffer = pcchBuffer;
  4031. if( pszBuffer && pcchBuffer && *pcchBuffer )
  4032. {
  4033. pszUnicodeBuffer = LocalAlloc( LMEM_FIXED, *pcchBuffer * sizeof( WCHAR ) );
  4034. bRetval = pszUnicodeBuffer ? TRUE : FALSE;
  4035. }
  4036. if( bRetval )
  4037. {
  4038. bRetval = GetDefaultPrinterW( pszUnicodeBuffer, pcchUnicodeBuffer );
  4039. if( bRetval && pszUnicodeBuffer )
  4040. {
  4041. bRetval = UnicodeToAnsiString( pszUnicodeBuffer, pszBuffer, 0 ) > 0;
  4042. }
  4043. }
  4044. if( pszUnicodeBuffer )
  4045. {
  4046. LocalFree( pszUnicodeBuffer );
  4047. }
  4048. return bRetval;
  4049. }
  4050. BOOL
  4051. SetDefaultPrinterA(
  4052. IN LPCSTR pszPrinter
  4053. )
  4054. {
  4055. BOOL bRetval = TRUE;
  4056. LPWSTR pszUnicode = NULL;
  4057. if( pszPrinter )
  4058. {
  4059. pszUnicode = AllocateUnicodeString( (PSTR) pszPrinter );
  4060. bRetval = pszUnicode ? TRUE : FALSE;
  4061. }
  4062. if( bRetval )
  4063. {
  4064. bRetval = SetDefaultPrinterW( pszUnicode );
  4065. }
  4066. if( pszUnicode )
  4067. {
  4068. FreeUnicodeString( pszUnicode );
  4069. }
  4070. return bRetval;
  4071. }
  4072. BOOL
  4073. PublishPrinterA(
  4074. HWND hwnd,
  4075. PCSTR pszUNCName,
  4076. PCSTR pszDN,
  4077. PCSTR pszCN,
  4078. PSTR *ppszDN,
  4079. DWORD dwAction
  4080. )
  4081. {
  4082. PWSTR pszUnicodeUNCName = NULL;
  4083. PWSTR pszUnicodeDN = NULL;
  4084. PWSTR pszUnicodeCN = NULL;
  4085. BOOL bRet = FALSE;
  4086. pszUnicodeUNCName = AllocateUnicodeString((PSTR) pszUNCName);
  4087. if (pszUNCName && !pszUnicodeUNCName)
  4088. goto error;
  4089. pszUnicodeDN = AllocateUnicodeString((PSTR) pszDN);
  4090. if (pszDN && !pszUnicodeDN)
  4091. goto error;
  4092. pszUnicodeCN = AllocateUnicodeString((PSTR) pszCN);
  4093. if (pszCN && !pszUnicodeCN)
  4094. goto error;
  4095. bRet = PublishPrinterW( hwnd,
  4096. pszUnicodeUNCName,
  4097. pszUnicodeDN,
  4098. pszUnicodeCN,
  4099. (PWSTR *) ppszDN,
  4100. dwAction);
  4101. if (ppszDN && *ppszDN) {
  4102. if (!UnicodeToAnsiString((PWSTR) *ppszDN, *ppszDN, NULL_TERMINATED))
  4103. bRet = FALSE;
  4104. }
  4105. error:
  4106. FreeUnicodeString(pszUnicodeUNCName);
  4107. FreeUnicodeString(pszUnicodeDN);
  4108. FreeUnicodeString(pszUnicodeCN);
  4109. return bRet;
  4110. }
  4111. VOID
  4112. ValidatePaperFields(
  4113. LPCWSTR pUnicodeDeviceName,
  4114. LPCWSTR pUnicodePort,
  4115. LPDEVMODEW pDevModeIn
  4116. )
  4117. {
  4118. POINTS ptMinSize, ptMaxSize;
  4119. if(!pUnicodeDeviceName ||
  4120. !pUnicodeDeviceName[0] ||
  4121. !pUnicodePort ||
  4122. !pUnicodePort[0] ||
  4123. !pDevModeIn) {
  4124. return;
  4125. }
  4126. //
  4127. // this logic was swiped from the MergeDevMode() code for the Win3.1 UNIDRV
  4128. //
  4129. // According to UNIDRV, dmPaperSize must be set to DMPAPER_USER if custom
  4130. // paper sizes are going to be taken seriously.
  4131. //
  4132. if((pDevModeIn->dmPaperSize == DMPAPER_USER) &&
  4133. (pDevModeIn->dmFields & DM_PAPERWIDTH) &&
  4134. (pDevModeIn->dmFields & DM_PAPERLENGTH)) {
  4135. pDevModeIn->dmFields |= (DM_PAPERLENGTH | DM_PAPERLENGTH);
  4136. //
  4137. // Get the minimum size this printer supports
  4138. //
  4139. if(DeviceCapabilitiesW(pUnicodeDeviceName,
  4140. pUnicodePort,
  4141. DC_MINEXTENT,
  4142. (PWSTR) &ptMinSize,
  4143. NULL) == -1) {
  4144. //
  4145. // No changes.
  4146. //
  4147. return;
  4148. }
  4149. if(DeviceCapabilitiesW(pUnicodeDeviceName,
  4150. pUnicodePort,
  4151. DC_MAXEXTENT,
  4152. (PWSTR) &ptMaxSize,
  4153. NULL) == -1) {
  4154. //
  4155. // No changes.
  4156. //
  4157. return;
  4158. }
  4159. //
  4160. // Force the custom paper size to fit the machine's capabilities
  4161. //
  4162. if(pDevModeIn->dmPaperWidth < ptMinSize.x)
  4163. pDevModeIn->dmPaperWidth = ptMinSize.x;
  4164. else if(pDevModeIn->dmPaperWidth > ptMaxSize.x)
  4165. pDevModeIn->dmPaperWidth = ptMaxSize.x;
  4166. if(pDevModeIn->dmPaperLength < ptMinSize.y)
  4167. pDevModeIn->dmPaperLength = ptMinSize.y;
  4168. else if(pDevModeIn->dmPaperLength > ptMaxSize.y)
  4169. pDevModeIn->dmPaperLength = ptMaxSize.y;
  4170. }
  4171. //
  4172. // Else if they don't have it right, turn these guys off so they don't
  4173. // get merged into the default devmode later.
  4174. //
  4175. else {
  4176. pDevModeIn->dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH);
  4177. pDevModeIn->dmPaperWidth = 0;
  4178. pDevModeIn->dmPaperLength = 0;
  4179. }
  4180. }
  4181. DWORD
  4182. UnicodeToAnsi(
  4183. IN LPBYTE pUnicode,
  4184. IN DWORD cchUnicode,
  4185. IN OUT LPBYTE pData,
  4186. IN DWORD cbData,
  4187. IN OUT DWORD *pcbCopied OPTIONAL
  4188. )
  4189. /*++
  4190. Routine Name:
  4191. UnicodeToAnsi
  4192. Routine Description:
  4193. Converts the content of a buffer from unicode to ansi. There is no assumption about
  4194. NULL terminator. If pUnicode is not NULL, then it must be WCHAR aligned and cchUnicode
  4195. indicates the number of WCHARs in the buffer that will be converted to ansi. If pUnicode
  4196. is NULL, then the function converts in place the contents of pData from Unicode to Ansi.
  4197. Arguments:
  4198. pUnicode - buffer aligned to WCHAR that contains a unicode string
  4199. cchUnicode - number of WCHARs in pUnicode buffer
  4200. pData - buffer that will hold the converted string
  4201. cbData - sizeo in bytes of the buffer pDa
  4202. pcbCopied - number of bytes copied to pData or needed to accomodate the converted string
  4203. Return Value:
  4204. None.
  4205. --*/
  4206. {
  4207. DWORD cReturn = cbData;
  4208. DWORD cbCopied = 0;
  4209. DWORD Error = ERROR_INVALID_PARAMETER;
  4210. //
  4211. // If the size of both input buffer is 0, then we do not do anything and return success.
  4212. // Otherwise, the caller must give us either valid pData or a valid pUnicode that is
  4213. // WCHAR aligned
  4214. //
  4215. if (!cbData && !cchUnicode)
  4216. {
  4217. Error = ERROR_SUCCESS;
  4218. }
  4219. else if (pData || pUnicode && !((ULONG_PTR)pUnicode % sizeof(WCHAR)))
  4220. {
  4221. LPWSTR pAligned = (LPWSTR)pUnicode;
  4222. Error = ERROR_SUCCESS;
  4223. if (!pAligned)
  4224. {
  4225. //
  4226. // We convert contents of pData from unicode to ansi
  4227. //
  4228. if (pAligned = LocalAlloc(LPTR, cbData))
  4229. {
  4230. memcpy(pAligned, pData, cbData);
  4231. cchUnicode = cbData / sizeof(WCHAR);
  4232. }
  4233. else
  4234. {
  4235. Error = GetLastError();
  4236. }
  4237. }
  4238. //
  4239. // Convert data to ansi or find out how many bytes are
  4240. // necessary to accomodate the string
  4241. //
  4242. if (Error == ERROR_SUCCESS)
  4243. {
  4244. cbCopied = WideCharToMultiByte(CP_THREAD_ACP,
  4245. 0,
  4246. pAligned,
  4247. cchUnicode,
  4248. pData,
  4249. cbData,
  4250. NULL,
  4251. NULL);
  4252. //
  4253. // WideCharToMultiByte tells us how many bytes we need
  4254. //
  4255. if (!cbCopied)
  4256. {
  4257. Error = ERROR_MORE_DATA;
  4258. cbCopied = WideCharToMultiByte(CP_THREAD_ACP,
  4259. 0,
  4260. pAligned,
  4261. cchUnicode,
  4262. pData,
  4263. 0,
  4264. NULL,
  4265. NULL);
  4266. }
  4267. else if (!cbData)
  4268. {
  4269. Error = ERROR_MORE_DATA;
  4270. }
  4271. if (pAligned != (LPWSTR)pUnicode)
  4272. {
  4273. LocalFree(pAligned);
  4274. }
  4275. }
  4276. }
  4277. if (pcbCopied)
  4278. {
  4279. *pcbCopied = cbCopied;
  4280. }
  4281. return Error;
  4282. }