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