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

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