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