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