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