[WINSPOOL] GetPrinterDriverA(): Refactor failure handling (#2832)
[reactos.git] / win32ss / printing / base / winspool / printers.c
1 /*
2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions related to Printers and printing
5 * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
6 */
7
8 #include "precomp.h"
9 #include <marshalling/printers.h>
10 #include <marshalling/printerdrivers.h>
11 #include <strsafe.h>
12
13 // Local Constants
14
15 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
16 Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */
17 static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
18 static const WCHAR wszDeviceValue[] = L"Device";
19
20 static DWORD
21 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
22 {
23 DWORD cbNeeded;
24 DWORD dwErrorCode;
25 PJOB_INFO_1W pJobInfo1 = NULL;
26
27 // Create the spool file.
28 pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
29 if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
30 {
31 dwErrorCode = GetLastError();
32 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
33 goto Cleanup;
34 }
35
36 // Get the size of the job information.
37 GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
38 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
39 {
40 dwErrorCode = GetLastError();
41 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
42 goto Cleanup;
43 }
44
45 // Allocate enough memory for the returned job information.
46 pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
47 if (!pJobInfo1)
48 {
49 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
50 ERR("HeapAlloc failed!\n");
51 goto Cleanup;
52 }
53
54 // Get the job information.
55 if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
56 {
57 dwErrorCode = GetLastError();
58 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
59 goto Cleanup;
60 }
61
62 // Add our document information.
63 if (pDocInfo1->pDatatype)
64 pJobInfo1->pDatatype = pDocInfo1->pDatatype;
65
66 pJobInfo1->pDocument = pDocInfo1->pDocName;
67
68 // Set the new job information.
69 if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
70 {
71 dwErrorCode = GetLastError();
72 ERR("SetJobW failed with error %lu!\n", dwErrorCode);
73 goto Cleanup;
74 }
75
76 // We were successful!
77 pHandle->dwJobID = pAddJobInfo1->JobId;
78 dwErrorCode = ERROR_SUCCESS;
79
80 Cleanup:
81 if (pJobInfo1)
82 HeapFree(hProcessHeap, 0, pJobInfo1);
83
84 return dwErrorCode;
85 }
86
87 static DWORD
88 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
89 {
90 DWORD dwErrorCode;
91 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
92
93 DocInfoContainer.Level = 1;
94 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
95
96 RpcTryExcept
97 {
98 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
99 }
100 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
101 {
102 dwErrorCode = RpcExceptionCode();
103 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
104 }
105 RpcEndExcept;
106
107 return dwErrorCode;
108 }
109
110 BOOL WINAPI
111 AbortPrinter(HANDLE hPrinter)
112 {
113 TRACE("AbortPrinter(%p)\n", hPrinter);
114 UNIMPLEMENTED;
115 return FALSE;
116 }
117
118 HANDLE WINAPI
119 AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
120 {
121 TRACE("AddPrinterA(%s, %lu, %p)\n", pName, Level, pPrinter);
122 UNIMPLEMENTED;
123 return NULL;
124 }
125
126 HANDLE WINAPI
127 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
128 {
129 TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
130 UNIMPLEMENTED;
131 return NULL;
132 }
133
134 BOOL WINAPI
135 ClosePrinter(HANDLE hPrinter)
136 {
137 DWORD dwErrorCode;
138 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
139
140 TRACE("ClosePrinter(%p)\n", hPrinter);
141
142 // Sanity checks.
143 if (!pHandle)
144 {
145 dwErrorCode = ERROR_INVALID_HANDLE;
146 goto Cleanup;
147 }
148
149 // Do the RPC call.
150 RpcTryExcept
151 {
152 dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter);
153 }
154 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
155 {
156 dwErrorCode = RpcExceptionCode();
157 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
158 }
159 RpcEndExcept;
160
161 // Close any open file handle.
162 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
163 CloseHandle(pHandle->hSPLFile);
164
165 // Free the memory for the handle.
166 HeapFree(hProcessHeap, 0, pHandle);
167
168 Cleanup:
169 SetLastError(dwErrorCode);
170 return (dwErrorCode == ERROR_SUCCESS);
171 }
172
173 BOOL WINAPI
174 DeletePrinter(HANDLE hPrinter)
175 {
176 TRACE("DeletePrinter(%p)\n", hPrinter);
177 UNIMPLEMENTED;
178 return FALSE;
179 }
180
181 DWORD WINAPI
182 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
183 {
184 TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
185 UNIMPLEMENTED;
186 return 0;
187 }
188
189 DWORD WINAPI
190 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
191 {
192 TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
193 UNIMPLEMENTED;
194 return 0;
195 }
196
197 INT WINAPI
198 DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut)
199 {
200 TRACE("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut);
201 UNIMPLEMENTED;
202 return DOCUMENTEVENT_UNSUPPORTED;
203 }
204
205 LONG WINAPI
206 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
207 {
208 PWSTR pwszDeviceName = NULL;
209 PDEVMODEW pdmwInput = NULL;
210 PDEVMODEW pdmwOutput = NULL;
211 BOOL bReturnValue = -1;
212 DWORD cch;
213
214 TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
215
216 if (pDeviceName)
217 {
218 // Convert pName to a Unicode string pwszDeviceName.
219 cch = strlen(pDeviceName);
220
221 pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
222 if (!pwszDeviceName)
223 {
224 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
225 ERR("HeapAlloc failed!\n");
226 goto Cleanup;
227 }
228
229 MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1);
230 }
231
232 if (pDevModeInput)
233 {
234 // Create working buffer for input to DocumentPropertiesW.
235 pdmwInput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW));
236 if (!pdmwInput)
237 {
238 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
239 ERR("HeapAlloc failed!\n");
240 goto Cleanup;
241 }
242 RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, pdmwInput);
243 }
244
245 if (pDevModeOutput)
246 {
247 // Create working buffer for output from DocumentPropertiesW.
248 pdmwOutput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW));
249 if (!pdmwOutput)
250 {
251 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
252 ERR("HeapAlloc failed!\n");
253 goto Cleanup;
254 }
255 }
256
257 bReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode);
258 TRACE("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue);
259
260 if (pwszDeviceName)
261 {
262 HeapFree(hProcessHeap, 0, pwszDeviceName);
263 }
264
265 if (bReturnValue < 0)
266 {
267 TRACE("DocumentPropertiesW failed!\n");
268 goto Cleanup;
269 }
270
271 if (pdmwOutput)
272 {
273 RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput);
274 }
275
276 Cleanup:
277 if(pwszDeviceName)
278 HeapFree(hProcessHeap, 0, pwszDeviceName);
279
280 if (pdmwInput)
281 HeapFree(hProcessHeap, 0, pdmwInput);
282
283 if (pdmwOutput)
284 HeapFree(hProcessHeap, 0, pdmwOutput);
285
286 return bReturnValue;
287 }
288
289 static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
290 {
291 PRINTER_INFO_9W *pi9 = NULL;
292 DWORD needed = 0;
293 BOOL res;
294
295 res = GetPrinterW(hprn, 9, NULL, 0, &needed);
296 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
297 {
298 pi9 = HeapAlloc(hProcessHeap, 0, needed);
299 res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed);
300 }
301
302 if (res)
303 return pi9;
304
305 ERR("GetPrinterW failed with %u\n", GetLastError());
306 HeapFree(hProcessHeap, 0, pi9);
307 return NULL;
308 }
309
310 LONG WINAPI
311 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
312 {
313 HANDLE hUseHandle = NULL;
314 PRINTER_INFO_9W *pi9 = NULL;
315 LONG Result = -1, Length;
316
317 TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
318 if (hPrinter)
319 {
320 hUseHandle = hPrinter;
321 }
322 else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
323 {
324 ERR("No handle, and no usable printer name passed in\n");
325 return -1;
326 }
327
328 pi9 = get_devmodeW(hUseHandle);
329
330 if (pi9)
331 {
332 Length = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
333 // See wineps.drv PSDRV_ExtDeviceMode
334 if (fMode)
335 {
336 Result = 1; /* IDOK */
337
338 if (fMode & DM_IN_BUFFER)
339 {
340 FIXME("Merge pDevModeInput with pi9, write back to driver!\n");
341 // See wineps.drv PSDRV_MergeDevmodes
342 }
343
344 if (fMode & DM_IN_PROMPT)
345 {
346 FIXME("Show property sheet!\n");
347 Result = 2; /* IDCANCEL */
348 }
349
350 if (fMode & (DM_OUT_BUFFER | DM_OUT_DEFAULT))
351 {
352 if (pDevModeOutput)
353 {
354 memcpy(pDevModeOutput, pi9->pDevMode, pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra);
355 }
356 else
357 {
358 ERR("No pDevModeOutput\n");
359 Result = -1;
360 }
361 }
362 }
363 else
364 {
365 Result = Length;
366 }
367
368 HeapFree(hProcessHeap, 0, pi9);
369 }
370
371 if (hUseHandle && !hPrinter)
372 ClosePrinter(hUseHandle);
373 return Result;
374 }
375
376 BOOL WINAPI
377 EndDocPrinter(HANDLE hPrinter)
378 {
379 DWORD dwErrorCode;
380 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
381
382 TRACE("EndDocPrinter(%p)\n", hPrinter);
383
384 // Sanity checks.
385 if (!pHandle)
386 {
387 dwErrorCode = ERROR_INVALID_HANDLE;
388 goto Cleanup;
389 }
390
391 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
392 {
393 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
394 RpcTryExcept
395 {
396 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
397 }
398 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
399 {
400 dwErrorCode = RpcExceptionCode();
401 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
402 }
403 RpcEndExcept;
404
405 // Close the spool file handle.
406 CloseHandle(pHandle->hSPLFile);
407 }
408 else
409 {
410 // In all other cases, just call _RpcEndDocPrinter.
411 RpcTryExcept
412 {
413 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
414 }
415 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
416 {
417 dwErrorCode = RpcExceptionCode();
418 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
419 }
420 RpcEndExcept;
421 }
422
423 // A new document can now be started again.
424 pHandle->bStartedDoc = FALSE;
425
426 Cleanup:
427 SetLastError(dwErrorCode);
428 return (dwErrorCode == ERROR_SUCCESS);
429 }
430
431 BOOL WINAPI
432 EndPagePrinter(HANDLE hPrinter)
433 {
434 DWORD dwErrorCode;
435 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
436
437 TRACE("EndPagePrinter(%p)\n", hPrinter);
438
439 // Sanity checks.
440 if (!pHandle)
441 {
442 dwErrorCode = ERROR_INVALID_HANDLE;
443 goto Cleanup;
444 }
445
446 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
447 {
448 // For spooled jobs, we don't need to do anything.
449 dwErrorCode = ERROR_SUCCESS;
450 }
451 else
452 {
453 // In all other cases, just call _RpcEndPagePrinter.
454 RpcTryExcept
455 {
456 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
457 }
458 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
459 {
460 dwErrorCode = RpcExceptionCode();
461 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
462 }
463 RpcEndExcept;
464 }
465
466 Cleanup:
467 SetLastError(dwErrorCode);
468 return (dwErrorCode == ERROR_SUCCESS);
469 }
470
471 BOOL WINAPI
472 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
473 {
474 DWORD dwErrorCode;
475 DWORD cch;
476 PWSTR pwszName = NULL;
477 PSTR pszPrinterName = NULL;
478 PSTR pszServerName = NULL;
479 PSTR pszDescription = NULL;
480 PSTR pszName = NULL;
481 PSTR pszComment = NULL;
482 PSTR pszShareName = NULL;
483 PSTR pszPortName = NULL;
484 PSTR pszDriverName = NULL;
485 PSTR pszLocation = NULL;
486 PSTR pszSepFile = NULL;
487 PSTR pszPrintProcessor = NULL;
488 PSTR pszDatatype = NULL;
489 PSTR pszParameters = NULL;
490 DWORD i;
491 PPRINTER_INFO_1W ppi1w = NULL;
492 PPRINTER_INFO_1A ppi1a = NULL;
493 PPRINTER_INFO_2W ppi2w = NULL;
494 PPRINTER_INFO_2A ppi2a = NULL;
495 PPRINTER_INFO_4W ppi4w = NULL;
496 PPRINTER_INFO_4A ppi4a = NULL;
497 PPRINTER_INFO_5W ppi5w = NULL;
498 PPRINTER_INFO_5A ppi5a = NULL;
499
500 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
501
502 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
503 if (Level != 1 && Level != 2 && Level != 4 && Level != 5)
504 {
505 dwErrorCode = ERROR_INVALID_LEVEL;
506 ERR("Invalid Level!\n");
507 goto Cleanup;
508 }
509
510 if (Name)
511 {
512 // Convert pName to a Unicode string pwszName.
513 cch = strlen(Name);
514
515 pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
516 if (!pwszName)
517 {
518 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
519 ERR("HeapAlloc failed!\n");
520 goto Cleanup;
521 }
522
523 MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1);
524 }
525
526 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
527 if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned))
528 {
529 dwErrorCode = GetLastError();
530 goto Cleanup;
531 }
532
533 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
534 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
535 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
536
537 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
538 ppi1w = (PPRINTER_INFO_1W)pPrinterEnum;
539 ppi2w = (PPRINTER_INFO_2W)pPrinterEnum;
540 ppi4w = (PPRINTER_INFO_4W)pPrinterEnum;
541 ppi5w = (PPRINTER_INFO_5W)pPrinterEnum;
542 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
543 ppi1a = (PPRINTER_INFO_1A)pPrinterEnum;
544 ppi2a = (PPRINTER_INFO_2A)pPrinterEnum;
545 ppi4a = (PPRINTER_INFO_4A)pPrinterEnum;
546 ppi5a = (PPRINTER_INFO_5A)pPrinterEnum;
547
548 for (i = 0; i < *pcReturned; i++)
549 {
550 switch (Level)
551 {
552 case 1:
553 {
554 if (ppi1w[i].pDescription)
555 {
556 // Convert Unicode pDescription to a ANSI string pszDescription.
557 cch = wcslen(ppi1w[i].pDescription);
558
559 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
560 if (!pszDescription)
561 {
562 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
563 ERR("HeapAlloc failed!\n");
564 goto Cleanup;
565 }
566
567 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL);
568 StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription);
569
570 HeapFree(hProcessHeap, 0, pszDescription);
571 }
572
573 if (ppi1w[i].pName)
574 {
575 // Convert Unicode pName to a ANSI string pszName.
576 cch = wcslen(ppi1w[i].pName);
577
578 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
579 if (!pszName)
580 {
581 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
582 ERR("HeapAlloc failed!\n");
583 goto Cleanup;
584 }
585
586 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL);
587 StringCchCopyA(ppi1a[i].pName, cch + 1, pszName);
588
589 HeapFree(hProcessHeap, 0, pszName);
590 }
591
592 if (ppi1w[i].pComment)
593 {
594 // Convert Unicode pComment to a ANSI string pszComment.
595 cch = wcslen(ppi1w[i].pComment);
596
597 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
598 if (!pszComment)
599 {
600 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
601 ERR("HeapAlloc failed!\n");
602 goto Cleanup;
603 }
604
605 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
606 StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment);
607
608 HeapFree(hProcessHeap, 0, pszComment);
609 }
610 break;
611 }
612
613
614 case 2:
615 {
616 if (ppi2w[i].pServerName)
617 {
618 // Convert Unicode pServerName to a ANSI string pszServerName.
619 cch = wcslen(ppi2w[i].pServerName);
620
621 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
622 if (!pszServerName)
623 {
624 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
625 ERR("HeapAlloc failed!\n");
626 goto Cleanup;
627 }
628
629 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
630 StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName);
631
632 HeapFree(hProcessHeap, 0, pszServerName);
633 }
634
635 if (ppi2w[i].pPrinterName)
636 {
637 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
638 cch = wcslen(ppi2w[i].pPrinterName);
639
640 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
641 if (!pszPrinterName)
642 {
643 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
644 ERR("HeapAlloc failed!\n");
645 goto Cleanup;
646 }
647
648 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
649 StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName);
650
651 HeapFree(hProcessHeap, 0, pszPrinterName);
652 }
653
654 if (ppi2w[i].pShareName)
655 {
656 // Convert Unicode pShareName to a ANSI string pszShareName.
657 cch = wcslen(ppi2w[i].pShareName);
658
659 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
660 if (!pszShareName)
661 {
662 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
663 ERR("HeapAlloc failed!\n");
664 goto Cleanup;
665 }
666
667 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL);
668 StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName);
669
670 HeapFree(hProcessHeap, 0, pszShareName);
671 }
672
673 if (ppi2w[i].pPortName)
674 {
675 // Convert Unicode pPortName to a ANSI string pszPortName.
676 cch = wcslen(ppi2w[i].pPortName);
677
678 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
679 if (!pszPortName)
680 {
681 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
682 ERR("HeapAlloc failed!\n");
683 goto Cleanup;
684 }
685
686 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
687 StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName);
688
689 HeapFree(hProcessHeap, 0, pszPortName);
690 }
691
692 if (ppi2w[i].pDriverName)
693 {
694 // Convert Unicode pDriverName to a ANSI string pszDriverName.
695 cch = wcslen(ppi2w[i].pDriverName);
696
697 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
698 if (!pszDriverName)
699 {
700 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
701 ERR("HeapAlloc failed!\n");
702 goto Cleanup;
703 }
704
705 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
706 StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName);
707
708 HeapFree(hProcessHeap, 0, pszDriverName);
709 }
710
711 if (ppi2w[i].pComment)
712 {
713 // Convert Unicode pComment to a ANSI string pszComment.
714 cch = wcslen(ppi2w[i].pComment);
715
716 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
717 if (!pszComment)
718 {
719 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
720 ERR("HeapAlloc failed!\n");
721 goto Cleanup;
722 }
723
724 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
725 StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment);
726
727 HeapFree(hProcessHeap, 0, pszComment);
728 }
729
730 if (ppi2w[i].pLocation)
731 {
732 // Convert Unicode pLocation to a ANSI string pszLocation.
733 cch = wcslen(ppi2w[i].pLocation);
734
735 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
736 if (!pszLocation)
737 {
738 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
739 ERR("HeapAlloc failed!\n");
740 goto Cleanup;
741 }
742
743 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL);
744 StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation);
745
746 HeapFree(hProcessHeap, 0, pszLocation);
747 }
748
749
750 if (ppi2w[i].pSepFile)
751 {
752 // Convert Unicode pSepFile to a ANSI string pszSepFile.
753 cch = wcslen(ppi2w[i].pSepFile);
754
755 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
756 if (!pszSepFile)
757 {
758 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
759 ERR("HeapAlloc failed!\n");
760 goto Cleanup;
761 }
762
763 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
764 StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile);
765
766 HeapFree(hProcessHeap, 0, pszSepFile);
767 }
768
769 if (ppi2w[i].pPrintProcessor)
770 {
771 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
772 cch = wcslen(ppi2w[i].pPrintProcessor);
773
774 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
775 if (!pszPrintProcessor)
776 {
777 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
778 ERR("HeapAlloc failed!\n");
779 goto Cleanup;
780 }
781
782 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
783 StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor);
784
785 HeapFree(hProcessHeap, 0, pszPrintProcessor);
786 }
787
788
789 if (ppi2w[i].pDatatype)
790 {
791 // Convert Unicode pDatatype to a ANSI string pszDatatype.
792 cch = wcslen(ppi2w[i].pDatatype);
793
794 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
795 if (!pszDatatype)
796 {
797 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
798 ERR("HeapAlloc failed!\n");
799 goto Cleanup;
800 }
801
802 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
803 StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype);
804
805 HeapFree(hProcessHeap, 0, pszDatatype);
806 }
807
808 if (ppi2w[i].pParameters)
809 {
810 // Convert Unicode pParameters to a ANSI string pszParameters.
811 cch = wcslen(ppi2w[i].pParameters);
812
813 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
814 if (!pszParameters)
815 {
816 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
817 ERR("HeapAlloc failed!\n");
818 goto Cleanup;
819 }
820
821 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL);
822 StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters);
823
824 HeapFree(hProcessHeap, 0, pszParameters);
825 }
826 break;
827
828 }
829
830 case 4:
831 {
832 if (ppi4w[i].pPrinterName)
833 {
834 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
835 cch = wcslen(ppi4w[i].pPrinterName);
836
837 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
838 if (!pszPrinterName)
839 {
840 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
841 ERR("HeapAlloc failed!\n");
842 goto Cleanup;
843 }
844
845 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
846 StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName);
847
848 HeapFree(hProcessHeap, 0, pszPrinterName);
849 }
850
851 if (ppi4w[i].pServerName)
852 {
853 // Convert Unicode pServerName to a ANSI string pszServerName.
854 cch = wcslen(ppi4w[i].pServerName);
855
856 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
857 if (!pszServerName)
858 {
859 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
860 ERR("HeapAlloc failed!\n");
861 goto Cleanup;
862 }
863
864 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
865 StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName);
866
867 HeapFree(hProcessHeap, 0, pszServerName);
868 }
869 break;
870 }
871
872 case 5:
873 {
874 if (ppi5w[i].pPrinterName)
875 {
876 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
877 cch = wcslen(ppi5w[i].pPrinterName);
878
879 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
880 if (!pszPrinterName)
881 {
882 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
883 ERR("HeapAlloc failed!\n");
884 goto Cleanup;
885 }
886
887 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
888 StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName);
889
890 HeapFree(hProcessHeap, 0, pszPrinterName);
891 }
892
893 if (ppi5w[i].pPortName)
894 {
895 // Convert Unicode pPortName to a ANSI string pszPortName.
896 cch = wcslen(ppi5w[i].pPortName);
897
898 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
899 if (!pszPortName)
900 {
901 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
902 ERR("HeapAlloc failed!\n");
903 goto Cleanup;
904 }
905
906 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
907 StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName);
908
909 HeapFree(hProcessHeap, 0, pszPortName);
910 }
911 break;
912 }
913
914 } // switch
915 } // for
916
917 dwErrorCode = ERROR_SUCCESS;
918
919 Cleanup:
920 if (pwszName)
921 {
922 HeapFree(hProcessHeap, 0, pwszName);
923 }
924
925 SetLastError(dwErrorCode);
926 return (dwErrorCode == ERROR_SUCCESS);
927 }
928
929 BOOL WINAPI
930 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
931 {
932 DWORD dwErrorCode;
933
934 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
935
936 // Dismiss invalid levels already at this point.
937 if (Level == 3 || Level > 5)
938 {
939 dwErrorCode = ERROR_INVALID_LEVEL;
940 goto Cleanup;
941 }
942
943 if (cbBuf && pPrinterEnum)
944 ZeroMemory(pPrinterEnum, cbBuf);
945
946 // Do the RPC call
947 RpcTryExcept
948 {
949 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
950 }
951 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
952 {
953 dwErrorCode = RpcExceptionCode();
954 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
955 }
956 RpcEndExcept;
957
958 if (dwErrorCode == ERROR_SUCCESS)
959 {
960 // Replace relative offset addresses in the output by absolute pointers.
961 ASSERT(Level <= 9);
962 MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
963 }
964
965 Cleanup:
966 SetLastError(dwErrorCode);
967 return (dwErrorCode == ERROR_SUCCESS);
968 }
969
970 BOOL WINAPI
971 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
972 {
973 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
974 UNIMPLEMENTED;
975 return FALSE;
976 }
977
978 BOOL WINAPI
979 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
980 {
981 DWORD dwErrorCode;
982 PWSTR pwszBuffer = NULL;
983
984 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
985
986 // Sanity check.
987 if (!pcchBuffer)
988 {
989 dwErrorCode = ERROR_INVALID_PARAMETER;
990 goto Cleanup;
991 }
992
993 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
994 if (pszBuffer && *pcchBuffer)
995 {
996 pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
997 if (!pwszBuffer)
998 {
999 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1000 ERR("HeapAlloc failed!\n");
1001 goto Cleanup;
1002 }
1003 }
1004
1005 if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
1006 {
1007 dwErrorCode = GetLastError();
1008 goto Cleanup;
1009 }
1010
1011 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
1012 WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
1013
1014 dwErrorCode = ERROR_SUCCESS;
1015
1016 Cleanup:
1017 if (pwszBuffer)
1018 HeapFree(hProcessHeap, 0, pwszBuffer);
1019
1020 SetLastError(dwErrorCode);
1021 return (dwErrorCode == ERROR_SUCCESS);
1022 }
1023
1024 BOOL WINAPI
1025 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
1026 {
1027 DWORD cbNeeded;
1028 DWORD cchInputBuffer;
1029 DWORD dwErrorCode;
1030 HKEY hWindowsKey = NULL;
1031 PWSTR pwszDevice = NULL;
1032 PWSTR pwszComma;
1033
1034 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
1035
1036 // Sanity check.
1037 if (!pcchBuffer)
1038 {
1039 dwErrorCode = ERROR_INVALID_PARAMETER;
1040 goto Cleanup;
1041 }
1042
1043 cchInputBuffer = *pcchBuffer;
1044
1045 // Open the registry key where the default printer for the current user is stored.
1046 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
1047 if (dwErrorCode != ERROR_SUCCESS)
1048 {
1049 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
1050 goto Cleanup;
1051 }
1052
1053 // Determine the size of the required buffer.
1054 dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
1055 if (dwErrorCode != ERROR_SUCCESS)
1056 {
1057 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
1058 goto Cleanup;
1059 }
1060
1061 // Allocate it.
1062 pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
1063 if (!pwszDevice)
1064 {
1065 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1066 ERR("HeapAlloc failed!\n");
1067 goto Cleanup;
1068 }
1069
1070 // Now get the actual value.
1071 dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
1072 if (dwErrorCode != ERROR_SUCCESS)
1073 {
1074 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
1075 goto Cleanup;
1076 }
1077
1078 // We get a string "<Printer Name>,winspool,<Port>:".
1079 // Extract the printer name from it.
1080 pwszComma = wcschr(pwszDevice, L',');
1081 if (!pwszComma)
1082 {
1083 ERR("Found no or invalid default printer: %S!\n", pwszDevice);
1084 dwErrorCode = ERROR_INVALID_NAME;
1085 goto Cleanup;
1086 }
1087
1088 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
1089 *pcchBuffer = pwszComma - pwszDevice + 1;
1090
1091 // Check if the supplied buffer is large enough.
1092 if (cchInputBuffer < *pcchBuffer)
1093 {
1094 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
1095 goto Cleanup;
1096 }
1097
1098 // Copy the default printer.
1099 *pwszComma = 0;
1100 CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
1101
1102 dwErrorCode = ERROR_SUCCESS;
1103
1104 Cleanup:
1105 if (hWindowsKey)
1106 RegCloseKey(hWindowsKey);
1107
1108 if (pwszDevice)
1109 HeapFree(hProcessHeap, 0, pwszDevice);
1110
1111 SetLastError(dwErrorCode);
1112 return (dwErrorCode == ERROR_SUCCESS);
1113 }
1114
1115 BOOL WINAPI
1116 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
1117 {
1118 DWORD dwErrorCode;
1119 PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter;
1120 PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter;
1121 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
1122 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
1123 PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter;
1124 PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter;
1125 PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter;
1126 PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter;
1127 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
1128 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
1129 DWORD cch;
1130
1131 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
1132
1133 // Check for invalid levels here for early error return. Should be 1-9.
1134 if (Level < 1 || Level > 9)
1135 {
1136 dwErrorCode = ERROR_INVALID_LEVEL;
1137 ERR("Invalid Level!\n");
1138 goto Cleanup;
1139 }
1140
1141 if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded))
1142 {
1143 dwErrorCode = GetLastError();
1144 goto Cleanup;
1145 }
1146
1147 switch (Level)
1148 {
1149 case 1:
1150 {
1151 if (ppi1w->pDescription)
1152 {
1153 PSTR pszDescription;
1154
1155 // Convert Unicode pDescription to a ANSI string pszDescription.
1156 cch = wcslen(ppi1w->pDescription);
1157
1158 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1159 if (!pszDescription)
1160 {
1161 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1162 ERR("HeapAlloc failed!\n");
1163 goto Cleanup;
1164 }
1165
1166 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL);
1167 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription);
1168
1169 HeapFree(hProcessHeap, 0, pszDescription);
1170 }
1171
1172 if (ppi1w->pName)
1173 {
1174 PSTR pszName;
1175
1176 // Convert Unicode pName to a ANSI string pszName.
1177 cch = wcslen(ppi1w->pName);
1178
1179 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1180 if (!pszName)
1181 {
1182 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1183 ERR("HeapAlloc failed!\n");
1184 goto Cleanup;
1185 }
1186
1187 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL);
1188 StringCchCopyA(ppi1a->pName, cch + 1, pszName);
1189
1190 HeapFree(hProcessHeap, 0, pszName);
1191 }
1192
1193 if (ppi1w->pComment)
1194 {
1195 PSTR pszComment;
1196
1197 // Convert Unicode pComment to a ANSI string pszComment.
1198 cch = wcslen(ppi1w->pComment);
1199
1200 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1201 if (!pszComment)
1202 {
1203 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1204 ERR("HeapAlloc failed!\n");
1205 goto Cleanup;
1206 }
1207
1208 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL);
1209 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment);
1210
1211 HeapFree(hProcessHeap, 0, pszComment);
1212 }
1213 break;
1214 }
1215
1216 case 2:
1217 {
1218 if (ppi2w->pServerName)
1219 {
1220 PSTR pszServerName;
1221
1222 // Convert Unicode pServerName to a ANSI string pszServerName.
1223 cch = wcslen(ppi2w->pServerName);
1224
1225 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1226 if (!pszServerName)
1227 {
1228 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1229 ERR("HeapAlloc failed!\n");
1230 goto Cleanup;
1231 }
1232
1233 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1234 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName);
1235
1236 HeapFree(hProcessHeap, 0, pszServerName);
1237 }
1238
1239 if (ppi2w->pPrinterName)
1240 {
1241 PSTR pszPrinterName;
1242
1243 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1244 cch = wcslen(ppi2w->pPrinterName);
1245
1246 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1247 if (!pszPrinterName)
1248 {
1249 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1250 ERR("HeapAlloc failed!\n");
1251 goto Cleanup;
1252 }
1253
1254 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1255 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName);
1256
1257 HeapFree(hProcessHeap, 0, pszPrinterName);
1258 }
1259
1260 if (ppi2w->pShareName)
1261 {
1262 PSTR pszShareName;
1263
1264 // Convert Unicode pShareName to a ANSI string pszShareName.
1265 cch = wcslen(ppi2w->pShareName);
1266
1267 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1268 if (!pszShareName)
1269 {
1270 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1271 ERR("HeapAlloc failed!\n");
1272 goto Cleanup;
1273 }
1274
1275 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL);
1276 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName);
1277
1278 HeapFree(hProcessHeap, 0, pszShareName);
1279 }
1280
1281 if (ppi2w->pPortName)
1282 {
1283 PSTR pszPortName;
1284
1285 // Convert Unicode pPortName to a ANSI string pszPortName.
1286 cch = wcslen(ppi2w->pPortName);
1287
1288 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1289 if (!pszPortName)
1290 {
1291 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1292 ERR("HeapAlloc failed!\n");
1293 goto Cleanup;
1294 }
1295
1296 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1297 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName);
1298
1299 HeapFree(hProcessHeap, 0, pszPortName);
1300 }
1301
1302 if (ppi2w->pDriverName)
1303 {
1304 PSTR pszDriverName;
1305
1306 // Convert Unicode pDriverName to a ANSI string pszDriverName.
1307 cch = wcslen(ppi2w->pDriverName);
1308
1309 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1310 if (!pszDriverName)
1311 {
1312 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1313 ERR("HeapAlloc failed!\n");
1314 goto Cleanup;
1315 }
1316
1317 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
1318 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName);
1319
1320 HeapFree(hProcessHeap, 0, pszDriverName);
1321 }
1322
1323 if (ppi2w->pComment)
1324 {
1325 PSTR pszComment;
1326
1327 // Convert Unicode pComment to a ANSI string pszComment.
1328 cch = wcslen(ppi2w->pComment);
1329
1330 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1331 if (!pszComment)
1332 {
1333 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1334 ERR("HeapAlloc failed!\n");
1335 goto Cleanup;
1336 }
1337
1338 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL);
1339 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment);
1340
1341 HeapFree(hProcessHeap, 0, pszComment);
1342 }
1343
1344 if (ppi2w->pLocation)
1345 {
1346 PSTR pszLocation;
1347
1348 // Convert Unicode pLocation to a ANSI string pszLocation.
1349 cch = wcslen(ppi2w->pLocation);
1350
1351 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1352 if (!pszLocation)
1353 {
1354 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1355 ERR("HeapAlloc failed!\n");
1356 goto Cleanup;
1357 }
1358
1359 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL);
1360 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation);
1361
1362 HeapFree(hProcessHeap, 0, pszLocation);
1363 }
1364
1365 if (ppi2w->pSepFile)
1366 {
1367 PSTR pszSepFile;
1368
1369 // Convert Unicode pSepFile to a ANSI string pszSepFile.
1370 cch = wcslen(ppi2w->pSepFile);
1371
1372 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1373 if (!pszSepFile)
1374 {
1375 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1376 ERR("HeapAlloc failed!\n");
1377 goto Cleanup;
1378 }
1379
1380 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
1381 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile);
1382
1383 HeapFree(hProcessHeap, 0, pszSepFile);
1384 }
1385
1386 if (ppi2w->pPrintProcessor)
1387 {
1388 PSTR pszPrintProcessor;
1389
1390 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1391 cch = wcslen(ppi2w->pPrintProcessor);
1392
1393 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1394 if (!pszPrintProcessor)
1395 {
1396 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1397 ERR("HeapAlloc failed!\n");
1398 goto Cleanup;
1399 }
1400
1401 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
1402 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor);
1403
1404 HeapFree(hProcessHeap, 0, pszPrintProcessor);
1405 }
1406
1407 if (ppi2w->pDatatype)
1408 {
1409 PSTR pszDatatype;
1410
1411 // Convert Unicode pDatatype to a ANSI string pszDatatype.
1412 cch = wcslen(ppi2w->pDatatype);
1413
1414 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1415 if (!pszDatatype)
1416 {
1417 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1418 ERR("HeapAlloc failed!\n");
1419 goto Cleanup;
1420 }
1421
1422 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
1423 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype);
1424
1425 HeapFree(hProcessHeap, 0, pszDatatype);
1426 }
1427
1428 if (ppi2w->pParameters)
1429 {
1430 PSTR pszParameters;
1431
1432 // Convert Unicode pParameters to a ANSI string pszParameters.
1433 cch = wcslen(ppi2w->pParameters);
1434
1435 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1436 if (!pszParameters)
1437 {
1438 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1439 ERR("HeapAlloc failed!\n");
1440 goto Cleanup;
1441 }
1442
1443 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL);
1444 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters);
1445
1446 HeapFree(hProcessHeap, 0, pszParameters);
1447 }
1448 break;
1449 }
1450
1451 case 4:
1452 {
1453 if (ppi4w->pPrinterName)
1454 {
1455 PSTR pszPrinterName;
1456
1457 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1458 cch = wcslen(ppi4w->pPrinterName);
1459
1460 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1461 if (!pszPrinterName)
1462 {
1463 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1464 ERR("HeapAlloc failed!\n");
1465 goto Cleanup;
1466 }
1467
1468 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1469 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName);
1470
1471 HeapFree(hProcessHeap, 0, pszPrinterName);
1472 }
1473
1474 if (ppi4w->pServerName)
1475 {
1476 PSTR pszServerName;
1477
1478 // Convert Unicode pServerName to a ANSI string pszServerName.
1479 cch = wcslen(ppi4w->pServerName);
1480
1481 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1482 if (!pszServerName)
1483 {
1484 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1485 ERR("HeapAlloc failed!\n");
1486 goto Cleanup;
1487 }
1488
1489 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1490 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName);
1491
1492 HeapFree(hProcessHeap, 0, pszServerName);
1493 }
1494 break;
1495 }
1496
1497 case 5:
1498 {
1499 if (ppi5w->pPrinterName)
1500 {
1501 PSTR pszPrinterName;
1502
1503 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1504 cch = wcslen(ppi5w->pPrinterName);
1505
1506 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1507 if (!pszPrinterName)
1508 {
1509 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1510 ERR("HeapAlloc failed!\n");
1511 goto Cleanup;
1512 }
1513
1514 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1515 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName);
1516
1517 HeapFree(hProcessHeap, 0, pszPrinterName);
1518 }
1519
1520 if (ppi5w->pPortName)
1521 {
1522 PSTR pszPortName;
1523
1524 // Convert Unicode pPortName to a ANSI string pszPortName.
1525 cch = wcslen(ppi5w->pPortName);
1526
1527 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1528 if (!pszPortName)
1529 {
1530 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1531 ERR("HeapAlloc failed!\n");
1532 goto Cleanup;
1533 }
1534
1535 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1536 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName);
1537
1538 HeapFree(hProcessHeap, 0, pszPortName);
1539 }
1540 break;
1541 }
1542
1543 case 7:
1544 {
1545 if (ppi7w->pszObjectGUID)
1546 {
1547 PSTR pszaObjectGUID;
1548
1549 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
1550 cch = wcslen(ppi7w->pszObjectGUID);
1551
1552 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1553 if (!pszaObjectGUID)
1554 {
1555 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1556 ERR("HeapAlloc failed!\n");
1557 goto Cleanup;
1558 }
1559
1560 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL);
1561 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID);
1562
1563 HeapFree(hProcessHeap, 0, pszaObjectGUID);
1564 }
1565 break;
1566 }
1567 } // switch
1568
1569 dwErrorCode = ERROR_SUCCESS;
1570
1571 Cleanup:
1572 SetLastError(dwErrorCode);
1573 return (dwErrorCode == ERROR_SUCCESS);
1574 }
1575
1576 BOOL WINAPI
1577 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
1578 {
1579 DWORD dwErrorCode;
1580 /*
1581 * We are mapping multiple different pointers to the same pDriverInfo pointer here so that
1582 * we can use the same incoming pointer for different Levels
1583 */
1584 PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo;
1585 PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo;
1586 PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo;
1587 PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo;
1588 PDRIVER_INFO_5W pdi5w = (PDRIVER_INFO_5W)pDriverInfo;
1589 PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo;
1590
1591 DWORD cch;
1592 PWSTR pwszEnvironment = NULL;
1593
1594 TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1595
1596 // Check for invalid levels here for early error return. Should be 1-6.
1597 if (Level < 1 || Level > 6)
1598 {
1599 dwErrorCode = ERROR_INVALID_LEVEL;
1600 ERR("Invalid Level!\n");
1601 goto Cleanup;
1602 }
1603
1604 if (pEnvironment)
1605 {
1606 // Convert pEnvironment to a Unicode string pwszEnvironment.
1607 cch = strlen(pEnvironment);
1608
1609 pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
1610 if (!pwszEnvironment)
1611 {
1612 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1613 ERR("HeapAlloc failed!\n");
1614 goto Cleanup;
1615 }
1616
1617 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1);
1618 }
1619
1620 if (!GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded))
1621 {
1622 dwErrorCode = GetLastError();
1623 goto Cleanup;
1624 }
1625
1626 // Do Unicode to ANSI conversions for strings based on Level
1627 switch (Level)
1628 {
1629 case 1:
1630 {
1631 dwErrorCode = UnicodeToAnsiInPlace(pdi1w->pName);
1632 if (dwErrorCode != ERROR_SUCCESS)
1633 {
1634 goto Cleanup;
1635 }
1636
1637 break;
1638 }
1639
1640 case 2:
1641 {
1642 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pName);
1643 if (dwErrorCode != ERROR_SUCCESS)
1644 {
1645 goto Cleanup;
1646 }
1647
1648 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pEnvironment);
1649 if (dwErrorCode != ERROR_SUCCESS)
1650 {
1651 goto Cleanup;
1652 }
1653
1654 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDriverPath);
1655 if (dwErrorCode != ERROR_SUCCESS)
1656 {
1657 goto Cleanup;
1658 }
1659
1660 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDataFile);
1661 if (dwErrorCode != ERROR_SUCCESS)
1662 {
1663 goto Cleanup;
1664 }
1665
1666 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pConfigFile);
1667 if (dwErrorCode != ERROR_SUCCESS)
1668 {
1669 goto Cleanup;
1670 }
1671
1672 break;
1673 }
1674
1675 case 3:
1676 {
1677 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pName);
1678 if (dwErrorCode != ERROR_SUCCESS)
1679 {
1680 goto Cleanup;
1681 }
1682
1683 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pEnvironment);
1684 if (dwErrorCode != ERROR_SUCCESS)
1685 {
1686 goto Cleanup;
1687 }
1688
1689 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDriverPath);
1690 if (dwErrorCode != ERROR_SUCCESS)
1691 {
1692 goto Cleanup;
1693 }
1694
1695 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDataFile);
1696 if (dwErrorCode != ERROR_SUCCESS)
1697 {
1698 goto Cleanup;
1699 }
1700
1701 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pConfigFile);
1702 if (dwErrorCode != ERROR_SUCCESS)
1703 {
1704 goto Cleanup;
1705 }
1706
1707 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pHelpFile);
1708 if (dwErrorCode != ERROR_SUCCESS)
1709 {
1710 goto Cleanup;
1711 }
1712
1713 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDependentFiles);
1714 if (dwErrorCode != ERROR_SUCCESS)
1715 {
1716 goto Cleanup;
1717 }
1718
1719 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pMonitorName);
1720 if (dwErrorCode != ERROR_SUCCESS)
1721 {
1722 goto Cleanup;
1723 }
1724
1725 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDefaultDataType);
1726 if (dwErrorCode != ERROR_SUCCESS)
1727 {
1728 goto Cleanup;
1729 }
1730
1731 break;
1732 }
1733
1734 case 4:
1735 {
1736 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pName);
1737 if (dwErrorCode != ERROR_SUCCESS)
1738 {
1739 goto Cleanup;
1740 }
1741
1742 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pEnvironment);
1743 if (dwErrorCode != ERROR_SUCCESS)
1744 {
1745 goto Cleanup;
1746 }
1747
1748 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDriverPath);
1749 if (dwErrorCode != ERROR_SUCCESS)
1750 {
1751 goto Cleanup;
1752 }
1753
1754 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDataFile);
1755 if (dwErrorCode != ERROR_SUCCESS)
1756 {
1757 goto Cleanup;
1758 }
1759
1760 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pConfigFile);
1761 if (dwErrorCode != ERROR_SUCCESS)
1762 {
1763 goto Cleanup;
1764 }
1765
1766 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pHelpFile);
1767 if (dwErrorCode != ERROR_SUCCESS)
1768 {
1769 goto Cleanup;
1770 }
1771
1772 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDependentFiles);
1773 if (dwErrorCode != ERROR_SUCCESS)
1774 {
1775 goto Cleanup;
1776 }
1777
1778 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pMonitorName);
1779 if (dwErrorCode != ERROR_SUCCESS)
1780 {
1781 goto Cleanup;
1782 }
1783
1784 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDefaultDataType);
1785 if (dwErrorCode != ERROR_SUCCESS)
1786 {
1787 goto Cleanup;
1788 }
1789
1790 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames);
1791 if (dwErrorCode != ERROR_SUCCESS)
1792 {
1793 goto Cleanup;
1794 }
1795
1796 break;
1797 }
1798
1799 case 5:
1800 {
1801 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pName);
1802 if (dwErrorCode != ERROR_SUCCESS)
1803 {
1804 goto Cleanup;
1805 }
1806
1807 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pEnvironment);
1808 if (dwErrorCode != ERROR_SUCCESS)
1809 {
1810 goto Cleanup;
1811 }
1812
1813 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDriverPath);
1814 if (dwErrorCode != ERROR_SUCCESS)
1815 {
1816 goto Cleanup;
1817 }
1818
1819 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDataFile);
1820 if (dwErrorCode != ERROR_SUCCESS)
1821 {
1822 goto Cleanup;
1823 }
1824
1825 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pConfigFile);
1826 if (dwErrorCode != ERROR_SUCCESS)
1827 {
1828 goto Cleanup;
1829 }
1830
1831 break;
1832 }
1833
1834 case 6:
1835 {
1836 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pName);
1837 if (dwErrorCode != ERROR_SUCCESS)
1838 {
1839 goto Cleanup;
1840 }
1841
1842 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pEnvironment);
1843 if (dwErrorCode != ERROR_SUCCESS)
1844 {
1845 goto Cleanup;
1846 }
1847
1848 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDriverPath);
1849 if (dwErrorCode != ERROR_SUCCESS)
1850 {
1851 goto Cleanup;
1852 }
1853
1854 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDataFile);
1855 if (dwErrorCode != ERROR_SUCCESS)
1856 {
1857 goto Cleanup;
1858 }
1859
1860 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pConfigFile);
1861 if (dwErrorCode != ERROR_SUCCESS)
1862 {
1863 goto Cleanup;
1864 }
1865
1866 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pHelpFile);
1867 if (dwErrorCode != ERROR_SUCCESS)
1868 {
1869 goto Cleanup;
1870 }
1871
1872 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDependentFiles);
1873 if (dwErrorCode != ERROR_SUCCESS)
1874 {
1875 goto Cleanup;
1876 }
1877
1878 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pMonitorName);
1879 if (dwErrorCode != ERROR_SUCCESS)
1880 {
1881 goto Cleanup;
1882 }
1883
1884 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDefaultDataType);
1885 if (dwErrorCode != ERROR_SUCCESS)
1886 {
1887 goto Cleanup;
1888 }
1889
1890 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames);
1891 if (dwErrorCode != ERROR_SUCCESS)
1892 {
1893 goto Cleanup;
1894 }
1895
1896 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszMfgName);
1897 if (dwErrorCode != ERROR_SUCCESS)
1898 {
1899 goto Cleanup;
1900 }
1901
1902 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszOEMUrl);
1903 if (dwErrorCode != ERROR_SUCCESS)
1904 {
1905 goto Cleanup;
1906 }
1907
1908 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszHardwareID);
1909 if (dwErrorCode != ERROR_SUCCESS)
1910 {
1911 goto Cleanup;
1912 }
1913
1914 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszProvider);
1915 if (dwErrorCode != ERROR_SUCCESS)
1916 {
1917 goto Cleanup;
1918 }
1919 }
1920 }
1921
1922 dwErrorCode = ERROR_SUCCESS;
1923
1924 Cleanup:
1925 if (pwszEnvironment)
1926 {
1927 HeapFree(hProcessHeap, 0, pwszEnvironment);
1928 }
1929
1930 SetLastError(dwErrorCode);
1931 return (dwErrorCode == ERROR_SUCCESS);
1932 }
1933
1934 BOOL WINAPI
1935 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
1936 {
1937 DWORD dwErrorCode;
1938 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1939
1940 TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1941
1942 // Sanity checks.
1943 if (!pHandle)
1944 {
1945 dwErrorCode = ERROR_INVALID_HANDLE;
1946 goto Cleanup;
1947 }
1948
1949 // Dismiss invalid levels already at this point.
1950 if (Level > 8 || Level < 1)
1951 {
1952 dwErrorCode = ERROR_INVALID_LEVEL;
1953 goto Cleanup;
1954 }
1955
1956 if (cbBuf && pDriverInfo)
1957 ZeroMemory(pDriverInfo, cbBuf);
1958
1959 // Do the RPC call
1960 RpcTryExcept
1961 {
1962 dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
1963 }
1964 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1965 {
1966 dwErrorCode = RpcExceptionCode();
1967 ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode);
1968 }
1969 RpcEndExcept;
1970
1971 if (dwErrorCode == ERROR_SUCCESS)
1972 {
1973 // Replace relative offset addresses in the output by absolute pointers.
1974 ASSERT(Level <= 5);
1975 MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
1976 }
1977
1978 Cleanup:
1979 SetLastError(dwErrorCode);
1980 return (dwErrorCode == ERROR_SUCCESS);
1981 }
1982
1983 BOOL WINAPI
1984 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
1985 {
1986 DWORD dwErrorCode;
1987 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1988
1989 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
1990
1991 // Sanity checks.
1992 if (!pHandle)
1993 {
1994 dwErrorCode = ERROR_INVALID_HANDLE;
1995 goto Cleanup;
1996 }
1997
1998 // Dismiss invalid levels already at this point.
1999 if (Level > 9)
2000 {
2001 dwErrorCode = ERROR_INVALID_LEVEL;
2002 goto Cleanup;
2003 }
2004
2005 if (cbBuf && pPrinter)
2006 ZeroMemory(pPrinter, cbBuf);
2007
2008 // Do the RPC call
2009 RpcTryExcept
2010 {
2011 dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
2012 }
2013 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2014 {
2015 dwErrorCode = RpcExceptionCode();
2016 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
2017 }
2018 RpcEndExcept;
2019
2020 if (dwErrorCode == ERROR_SUCCESS)
2021 {
2022 // Replace relative offset addresses in the output by absolute pointers.
2023 ASSERT(Level <= 9);
2024 MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
2025 }
2026
2027 Cleanup:
2028 SetLastError(dwErrorCode);
2029 return (dwErrorCode == ERROR_SUCCESS);
2030 }
2031
2032 BOOL WINAPI
2033 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
2034 {
2035 BOOL bReturnValue = FALSE;
2036 DWORD cch;
2037 PWSTR pwszPrinterName = NULL;
2038 PRINTER_DEFAULTSW wDefault = { 0 };
2039
2040 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault);
2041
2042 if (pPrinterName)
2043 {
2044 // Convert pPrinterName to a Unicode string pwszPrinterName
2045 cch = strlen(pPrinterName);
2046
2047 pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2048 if (!pwszPrinterName)
2049 {
2050 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2051 ERR("HeapAlloc failed!\n");
2052 goto Cleanup;
2053 }
2054
2055 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
2056 }
2057
2058 if (pDefault)
2059 {
2060 wDefault.DesiredAccess = pDefault->DesiredAccess;
2061
2062 if (pDefault->pDatatype)
2063 {
2064 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
2065 cch = strlen(pDefault->pDatatype);
2066
2067 wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2068 if (!wDefault.pDatatype)
2069 {
2070 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2071 ERR("HeapAlloc failed!\n");
2072 goto Cleanup;
2073 }
2074
2075 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
2076 }
2077
2078 if (pDefault->pDevMode)
2079 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
2080 }
2081
2082 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
2083
2084 Cleanup:
2085 if (wDefault.pDatatype)
2086 HeapFree(hProcessHeap, 0, wDefault.pDatatype);
2087
2088 if (wDefault.pDevMode)
2089 HeapFree(hProcessHeap, 0, wDefault.pDevMode);
2090
2091 if (pwszPrinterName)
2092 HeapFree(hProcessHeap, 0, pwszPrinterName);
2093
2094 return bReturnValue;
2095 }
2096
2097 BOOL WINAPI
2098 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
2099 {
2100 DWORD dwErrorCode;
2101 HANDLE hPrinter;
2102 PSPOOLER_HANDLE pHandle;
2103 PWSTR pDatatype = NULL;
2104 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
2105 ACCESS_MASK AccessRequired = 0;
2106
2107 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault);
2108
2109 // Sanity check
2110 if (!phPrinter)
2111 {
2112 dwErrorCode = ERROR_INVALID_PARAMETER;
2113 goto Cleanup;
2114 }
2115
2116 // Prepare the additional parameters in the format required by _RpcOpenPrinter
2117 if (pDefault)
2118 {
2119 pDatatype = pDefault->pDatatype;
2120 DevModeContainer.cbBuf = sizeof(DEVMODEW);
2121 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
2122 AccessRequired = pDefault->DesiredAccess;
2123 }
2124
2125 // Do the RPC call
2126 RpcTryExcept
2127 {
2128 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
2129 }
2130 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2131 {
2132 dwErrorCode = RpcExceptionCode();
2133 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
2134 }
2135 RpcEndExcept;
2136
2137 if (dwErrorCode == ERROR_SUCCESS)
2138 {
2139 // Create a new SPOOLER_HANDLE structure.
2140 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
2141 if (!pHandle)
2142 {
2143 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2144 ERR("HeapAlloc failed!\n");
2145 goto Cleanup;
2146 }
2147
2148 pHandle->hPrinter = hPrinter;
2149 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
2150
2151 // Return it as phPrinter.
2152 *phPrinter = (HANDLE)pHandle;
2153 }
2154
2155 Cleanup:
2156 SetLastError(dwErrorCode);
2157 return (dwErrorCode == ERROR_SUCCESS);
2158 }
2159
2160 BOOL WINAPI
2161 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
2162 {
2163 DWORD dwErrorCode;
2164 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2165
2166 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
2167
2168 // Sanity checks.
2169 if (!pHandle)
2170 {
2171 dwErrorCode = ERROR_INVALID_HANDLE;
2172 goto Cleanup;
2173 }
2174
2175 // Do the RPC call
2176 RpcTryExcept
2177 {
2178 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
2179 }
2180 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2181 {
2182 dwErrorCode = RpcExceptionCode();
2183 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
2184 }
2185 RpcEndExcept;
2186
2187 Cleanup:
2188 SetLastError(dwErrorCode);
2189 return (dwErrorCode == ERROR_SUCCESS);
2190 }
2191
2192 BOOL WINAPI
2193 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
2194 {
2195 TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
2196 UNIMPLEMENTED;
2197 return FALSE;
2198 }
2199
2200 BOOL WINAPI
2201 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
2202 {
2203 TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault);
2204 UNIMPLEMENTED;
2205 return FALSE;
2206 }
2207
2208 BOOL WINAPI
2209 SetDefaultPrinterA(LPCSTR pszPrinter)
2210 {
2211 BOOL bReturnValue = FALSE;
2212 DWORD cch;
2213 PWSTR pwszPrinter = NULL;
2214
2215 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter);
2216
2217 if (pszPrinter)
2218 {
2219 // Convert pszPrinter to a Unicode string pwszPrinter
2220 cch = strlen(pszPrinter);
2221
2222 pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2223 if (!pwszPrinter)
2224 {
2225 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2226 ERR("HeapAlloc failed!\n");
2227 goto Cleanup;
2228 }
2229
2230 MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
2231 }
2232
2233 bReturnValue = SetDefaultPrinterW(pwszPrinter);
2234
2235 Cleanup:
2236 if (pwszPrinter)
2237 HeapFree(hProcessHeap, 0, pwszPrinter);
2238
2239 return bReturnValue;
2240 }
2241
2242 BOOL WINAPI
2243 SetDefaultPrinterW(LPCWSTR pszPrinter)
2244 {
2245 const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
2246
2247 DWORD cbDeviceValueData;
2248 DWORD cbPrinterValueData = 0;
2249 DWORD cchPrinter;
2250 DWORD dwErrorCode;
2251 HKEY hDevicesKey = NULL;
2252 HKEY hWindowsKey = NULL;
2253 PWSTR pwszDeviceValueData = NULL;
2254 WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
2255
2256 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter);
2257
2258 // Open the Devices registry key.
2259 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
2260 if (dwErrorCode != ERROR_SUCCESS)
2261 {
2262 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
2263 goto Cleanup;
2264 }
2265
2266 // Did the caller give us a printer to set as default?
2267 if (pszPrinter && *pszPrinter)
2268 {
2269 // Check if the given printer exists and query the value data size.
2270 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
2271 if (dwErrorCode == ERROR_FILE_NOT_FOUND)
2272 {
2273 dwErrorCode = ERROR_INVALID_PRINTER_NAME;
2274 goto Cleanup;
2275 }
2276 else if (dwErrorCode != ERROR_SUCCESS)
2277 {
2278 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
2279 goto Cleanup;
2280 }
2281
2282 cchPrinter = wcslen(pszPrinter);
2283 }
2284 else
2285 {
2286 // If there is already a default printer, we're done!
2287 cchPrinter = _countof(wszPrinter);
2288 if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
2289 {
2290 dwErrorCode = ERROR_SUCCESS;
2291 goto Cleanup;
2292 }
2293
2294 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
2295 cchPrinter = _countof(wszPrinter);
2296 dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
2297 if (dwErrorCode != ERROR_MORE_DATA)
2298 goto Cleanup;
2299
2300 pszPrinter = wszPrinter;
2301 }
2302
2303 // We now need to query the value data, which has the format "winspool,<Port>:"
2304 // and make "<Printer Name>,winspool,<Port>:" out of it.
2305 // Allocate a buffer large enough for the final data.
2306 cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
2307 pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
2308 if (!pwszDeviceValueData)
2309 {
2310 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2311 ERR("HeapAlloc failed!\n");
2312 goto Cleanup;
2313 }
2314
2315 // Copy the Printer Name and a comma into it.
2316 CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
2317 pwszDeviceValueData[cchPrinter] = L',';
2318
2319 // Append the value data, which has the format "winspool,<Port>:"
2320 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
2321 if (dwErrorCode != ERROR_SUCCESS)
2322 goto Cleanup;
2323
2324 // Open the Windows registry key.
2325 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
2326 if (dwErrorCode != ERROR_SUCCESS)
2327 {
2328 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
2329 goto Cleanup;
2330 }
2331
2332 // Store our new default printer.
2333 dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
2334 if (dwErrorCode != ERROR_SUCCESS)
2335 {
2336 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
2337 goto Cleanup;
2338 }
2339
2340 Cleanup:
2341 if (hDevicesKey)
2342 RegCloseKey(hDevicesKey);
2343
2344 if (hWindowsKey)
2345 RegCloseKey(hWindowsKey);
2346
2347 if (pwszDeviceValueData)
2348 HeapFree(hProcessHeap, 0, pwszDeviceValueData);
2349
2350 SetLastError(dwErrorCode);
2351 return (dwErrorCode == ERROR_SUCCESS);
2352 }
2353
2354 BOOL WINAPI
2355 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
2356 {
2357 TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
2358 UNIMPLEMENTED;
2359 return FALSE;
2360 }
2361
2362 BOOL WINAPI
2363 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
2364 {
2365 TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
2366 UNIMPLEMENTED;
2367 return FALSE;
2368 }
2369
2370 BOOL WINAPI
2371 SplDriverUnloadComplete(LPWSTR pDriverFile)
2372 {
2373 TRACE("DriverUnloadComplete(%S)\n", pDriverFile);
2374 UNIMPLEMENTED;
2375 return TRUE; // return true for now.
2376 }
2377
2378 DWORD WINAPI
2379 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
2380 {
2381 DOC_INFO_1W wDocInfo1 = { 0 };
2382 DWORD cch;
2383 DWORD dwErrorCode;
2384 DWORD dwReturnValue = 0;
2385 PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
2386
2387 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
2388
2389 // Only check the minimum required for accessing pDocInfo.
2390 // Additional sanity checks are done in StartDocPrinterW.
2391 if (!pDocInfo1)
2392 {
2393 dwErrorCode = ERROR_INVALID_PARAMETER;
2394 goto Cleanup;
2395 }
2396
2397 if (Level != 1)
2398 {
2399 dwErrorCode = ERROR_INVALID_LEVEL;
2400 goto Cleanup;
2401 }
2402
2403 if (pDocInfo1->pDatatype)
2404 {
2405 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
2406 cch = strlen(pDocInfo1->pDatatype);
2407
2408 wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2409 if (!wDocInfo1.pDatatype)
2410 {
2411 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2412 ERR("HeapAlloc failed!\n");
2413 goto Cleanup;
2414 }
2415
2416 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
2417 }
2418
2419 if (pDocInfo1->pDocName)
2420 {
2421 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
2422 cch = strlen(pDocInfo1->pDocName);
2423
2424 wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2425 if (!wDocInfo1.pDocName)
2426 {
2427 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2428 ERR("HeapAlloc failed!\n");
2429 goto Cleanup;
2430 }
2431
2432 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
2433 }
2434
2435 if (pDocInfo1->pOutputFile)
2436 {
2437 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
2438 cch = strlen(pDocInfo1->pOutputFile);
2439
2440 wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2441 if (!wDocInfo1.pOutputFile)
2442 {
2443 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2444 ERR("HeapAlloc failed!\n");
2445 goto Cleanup;
2446 }
2447
2448 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
2449 }
2450
2451 dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
2452 dwErrorCode = GetLastError();
2453
2454 Cleanup:
2455 if (wDocInfo1.pDatatype)
2456 HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
2457
2458 if (wDocInfo1.pDocName)
2459 HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
2460
2461 if (wDocInfo1.pOutputFile)
2462 HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
2463
2464 SetLastError(dwErrorCode);
2465 return dwReturnValue;
2466 }
2467
2468 DWORD WINAPI
2469 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
2470 {
2471 DWORD cbAddJobInfo1;
2472 DWORD cbNeeded;
2473 DWORD dwErrorCode;
2474 DWORD dwReturnValue = 0;
2475 PADDJOB_INFO_1W pAddJobInfo1 = NULL;
2476 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
2477 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2478
2479 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
2480
2481 // Sanity checks.
2482 if (!pHandle)
2483 {
2484 dwErrorCode = ERROR_INVALID_HANDLE;
2485 goto Cleanup;
2486 }
2487
2488 if (!pDocInfo1)
2489 {
2490 dwErrorCode = ERROR_INVALID_PARAMETER;
2491 goto Cleanup;
2492 }
2493
2494 if (Level != 1)
2495 {
2496 dwErrorCode = ERROR_INVALID_LEVEL;
2497 goto Cleanup;
2498 }
2499
2500 if (pHandle->bStartedDoc)
2501 {
2502 dwErrorCode = ERROR_INVALID_PRINTER_STATE;
2503 goto Cleanup;
2504 }
2505
2506 // Check if we want to redirect output into a file.
2507 if (pDocInfo1->pOutputFile)
2508 {
2509 // Do a StartDocPrinter RPC call in this case.
2510 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
2511 }
2512 else
2513 {
2514 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
2515 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
2516 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
2517 if (!pAddJobInfo1)
2518 {
2519 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2520 ERR("HeapAlloc failed!\n");
2521 goto Cleanup;
2522 }
2523
2524 // Try to add a new job.
2525 // This only succeeds if the printer is set to do spooled printing.
2526 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
2527 {
2528 // Do spooled printing.
2529 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
2530 }
2531 else if (GetLastError() == ERROR_INVALID_ACCESS)
2532 {
2533 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
2534 // In this case, we do a StartDocPrinter RPC call.
2535 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
2536 }
2537 else
2538 {
2539 dwErrorCode = GetLastError();
2540 ERR("AddJobW failed with error %lu!\n", dwErrorCode);
2541 goto Cleanup;
2542 }
2543 }
2544
2545 if (dwErrorCode == ERROR_SUCCESS)
2546 {
2547 pHandle->bStartedDoc = TRUE;
2548 dwReturnValue = pHandle->dwJobID;
2549 }
2550
2551 Cleanup:
2552 if (pAddJobInfo1)
2553 HeapFree(hProcessHeap, 0, pAddJobInfo1);
2554
2555 SetLastError(dwErrorCode);
2556 return dwReturnValue;
2557 }
2558
2559 BOOL WINAPI
2560 StartPagePrinter(HANDLE hPrinter)
2561 {
2562 DWORD dwErrorCode;
2563 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2564
2565 TRACE("StartPagePrinter(%p)\n", hPrinter);
2566
2567 // Sanity checks.
2568 if (!pHandle)
2569 {
2570 dwErrorCode = ERROR_INVALID_HANDLE;
2571 goto Cleanup;
2572 }
2573
2574 // Do the RPC call
2575 RpcTryExcept
2576 {
2577 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
2578 }
2579 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2580 {
2581 dwErrorCode = RpcExceptionCode();
2582 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
2583 }
2584 RpcEndExcept;
2585
2586 Cleanup:
2587 SetLastError(dwErrorCode);
2588 return (dwErrorCode == ERROR_SUCCESS);
2589 }
2590
2591 BOOL WINAPI
2592 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
2593 {
2594 DWORD dwErrorCode;
2595 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2596
2597 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2598
2599 // Sanity checks.
2600 if (!pHandle)
2601 {
2602 dwErrorCode = ERROR_INVALID_HANDLE;
2603 goto Cleanup;
2604 }
2605
2606 if (!pHandle->bStartedDoc)
2607 {
2608 dwErrorCode = ERROR_SPL_NO_STARTDOC;
2609 goto Cleanup;
2610 }
2611
2612 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
2613 {
2614 // Write to the spool file. This doesn't need an RPC request.
2615 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
2616 {
2617 dwErrorCode = GetLastError();
2618 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
2619 goto Cleanup;
2620 }
2621
2622 dwErrorCode = ERROR_SUCCESS;
2623 }
2624 else
2625 {
2626 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
2627 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
2628
2629 // Do the RPC call
2630 RpcTryExcept
2631 {
2632 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
2633 }
2634 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2635 {
2636 dwErrorCode = RpcExceptionCode();
2637 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
2638 }
2639 RpcEndExcept;
2640 }
2641
2642 Cleanup:
2643 SetLastError(dwErrorCode);
2644 return (dwErrorCode == ERROR_SUCCESS);
2645 }
2646
2647 BOOL WINAPI
2648 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2649 {
2650 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
2651 return FALSE;
2652 }