1 /*
2 * PROJECT:     ReactOS Spooler API
3 * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE:     Functions related to Print Processors
5 * COPYRIGHT:   Copyright 2015-2018 Colin Finck (colin@reactos.org)
6 */
7 
8 #include "precomp.h"
9 #include <marshalling/printprocessors.h>
10 #include <prtprocenv.h>
11 
12 BOOL WINAPI
13 AddPrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPathName, PSTR pPrintProcessorName)
14 {
15     UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
16     BOOL Ret;
17 
18     TRACE("AddPrintProcessorA(%s, %s, %s, %s)\n", pName, pEnvironment, pPathName, pPrintProcessorName);
19 
20     AsciiToUnicode(&NameW, pName);
21     AsciiToUnicode(&EnvW, pEnvironment);
22     AsciiToUnicode(&PathW, pPathName);
23     AsciiToUnicode(&ProcessorW, pPrintProcessorName);
24 
25     Ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
26 
27     RtlFreeUnicodeString(&ProcessorW);
28     RtlFreeUnicodeString(&PathW);
29     RtlFreeUnicodeString(&EnvW);
30     RtlFreeUnicodeString(&NameW);
31 
32     return Ret;
33 }
34 
35 BOOL WINAPI
36 AddPrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPathName, PWSTR pPrintProcessorName)
37 {
38     DWORD dwErrorCode;
39 
40     TRACE("AddPrintProcessorW(%S, %S, %S, %S)\n", pName, pEnvironment, pPathName, pPrintProcessorName);
41 
42     RpcTryExcept
43     {
44         dwErrorCode = _RpcAddPrintProcessor( pName, pEnvironment, pPathName, pPrintProcessorName );
45     }
46     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
47     {
48         dwErrorCode = RpcExceptionCode();
49         ERR("_RpcPrintProcessor failed with exception code %lu!\n", dwErrorCode);
50     }
51     RpcEndExcept;
52 
53     SetLastError(dwErrorCode);
54     return (dwErrorCode == ERROR_SUCCESS);
55 }
56 
57 BOOL WINAPI
58 DeletePrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPrintProcessorName)
59 {
60     UNICODE_STRING NameW, EnvW, ProcessorW;
61     BOOL Ret;
62 
63     TRACE("DeletePrintProcessorA(%s, %s, %s)\n", pName, pEnvironment, pPrintProcessorName);
64 
65     AsciiToUnicode(&NameW, pName);
66     AsciiToUnicode(&EnvW, pEnvironment);
67     AsciiToUnicode(&ProcessorW, pPrintProcessorName);
68 
69     Ret = DeletePrintProcessorW(NameW.Buffer, EnvW.Buffer, ProcessorW.Buffer);
70 
71     RtlFreeUnicodeString(&ProcessorW);
72     RtlFreeUnicodeString(&EnvW);
73     RtlFreeUnicodeString(&NameW);
74 
75     return Ret;
76 }
77 
78 BOOL WINAPI
79 DeletePrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProcessorName)
80 {
81     DWORD dwErrorCode;
82 
83     TRACE("DeletePrintProcessorW(%S, %S, %S)\n", pName, pEnvironment, pPrintProcessorName);
84 
85     RpcTryExcept
86     {
87         dwErrorCode = _RpcDeletePrintProcessor( pName, pEnvironment, pPrintProcessorName );
88     }
89     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
90     {
91         dwErrorCode = RpcExceptionCode();
92         ERR("_RpcDeletePrintProcessor failed with exception code %lu!\n", dwErrorCode);
93     }
94     RpcEndExcept;
95 
96     SetLastError(dwErrorCode);
97     return (dwErrorCode == ERROR_SUCCESS);
98 }
99 
100 BOOL WINAPI
101 EnumPrintProcessorDatatypesA(PSTR pName, LPSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
102 {
103     TRACE("EnumPrintProcessorDatatypesA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
104     UNIMPLEMENTED;
105     return FALSE;
106 }
107 
108 BOOL WINAPI
109 EnumPrintProcessorDatatypesW(PWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
110 {
111     DWORD dwErrorCode;
112 
113     TRACE("EnumPrintProcessorDatatypesW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
114 
115     // Sanity checks
116     if (Level != 1)
117     {
118         dwErrorCode = ERROR_INVALID_LEVEL;
119         goto Cleanup;
120     }
121 
122     // Do the RPC call
123     RpcTryExcept
124     {
125         dwErrorCode = _RpcEnumPrintProcessorDatatypes(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
126     }
127     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
128     {
129         dwErrorCode = RpcExceptionCode();
130         ERR("_RpcEnumPrintProcessorDatatypes failed with exception code %lu!\n", dwErrorCode);
131     }
132     RpcEndExcept;
133 
134     if (dwErrorCode == ERROR_SUCCESS)
135     {
136         // Replace relative offset addresses in the output by absolute pointers.
137         MarshallUpStructuresArray(cbBuf, pDatatypes, *pcReturned, DatatypesInfo1Marshalling.pInfo, DatatypesInfo1Marshalling.cbStructureSize, TRUE);
138     }
139 
140 Cleanup:
141     SetLastError(dwErrorCode);
142     return (dwErrorCode == ERROR_SUCCESS);
143 }
144 
145 BOOL WINAPI
146 EnumPrintProcessorsA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
147 {
148     BOOL    res;
149     LPBYTE  bufferW = NULL;
150     LPWSTR  nameW = NULL;
151     LPWSTR  envW = NULL;
152     DWORD   needed = 0;
153     DWORD   numentries = 0;
154     INT     len;
155 
156     TRACE("EnumPrintProcessorsA(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
157 
158     /* convert names to unicode */
159     if (pName)
160     {
161         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
162         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
163         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
164     }
165     if (pEnvironment)
166     {
167         len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
168         envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
169         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
170     }
171 
172     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
173     needed = cbBuf * sizeof(WCHAR);
174     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
175     res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
176 
177     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
178     {
179         if (pcbNeeded) needed = *pcbNeeded;
180         /* HeapReAlloc return NULL, when bufferW was NULL */
181         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
182                               HeapAlloc(GetProcessHeap(), 0, needed);
183 
184         /* Try again with the large Buffer */
185         res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
186     }
187     numentries = pcReturned ? *pcReturned : 0;
188     needed = 0;
189 
190     if (res)
191     {
192         /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
193         DWORD   index;
194         LPSTR   ptr;
195         PPRINTPROCESSOR_INFO_1W ppiw;
196         PPRINTPROCESSOR_INFO_1A ppia;
197 
198         /* First pass: calculate the size for all Entries */
199         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
200         ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo;
201         index = 0;
202         while (index < numentries)
203         {
204             index++;
205             needed += sizeof(PRINTPROCESSOR_INFO_1A);
206             TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
207 
208             needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
209                                             NULL, 0, NULL, NULL);
210 
211             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
212             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
213         }
214 
215         /* check for errors and quit on failure */
216         if (cbBuf < needed)
217         {
218             SetLastError(ERROR_INSUFFICIENT_BUFFER);
219             res = FALSE;
220             goto epp_cleanup;
221         }
222 
223         len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
224         ptr = (LPSTR) &pPrintProcessorInfo[len];        /* start of strings */
225         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
226         ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
227         ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo;
228         index = 0;
229         /* Second Pass: Fill the User Buffer (if we have one) */
230         while ((index < numentries) && pPrintProcessorInfo)
231         {
232             index++;
233             TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
234             ppia->pName = ptr;
235             len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
236                                             ptr, cbBuf , NULL, NULL);
237             ptr += len;
238             cbBuf -= len;
239 
240             ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
241             ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
242 
243         }
244     }
245 epp_cleanup:
246     if (pcbNeeded)  *pcbNeeded = needed;
247     if (pcReturned) *pcReturned = (res) ? numentries : 0;
248 
249     if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
250     if (envW) HeapFree(GetProcessHeap(), 0, envW);
251     if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
252 
253     TRACE("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries);
254 
255     return (res);
256 
257 }
258 
259 BOOL WINAPI
260 EnumPrintProcessorsW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
261 {
262     DWORD dwErrorCode;
263 
264     TRACE("EnumPrintProcessorsW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
265 
266     // Choose our current environment if the caller didn't give any.
267     if (!pEnvironment)
268         pEnvironment = (PWSTR)wszCurrentEnvironment;
269 
270     // Do the RPC call
271     RpcTryExcept
272     {
273         dwErrorCode = _RpcEnumPrintProcessors(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
274     }
275     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
276     {
277         dwErrorCode = RpcExceptionCode();
278     }
279     RpcEndExcept;
280 
281     if (dwErrorCode == ERROR_SUCCESS)
282     {
283         // Replace relative offset addresses in the output by absolute pointers.
284         MarshallUpStructuresArray(cbBuf, pPrintProcessorInfo, *pcReturned, PrintProcessorInfo1Marshalling.pInfo, PrintProcessorInfo1Marshalling.cbStructureSize, TRUE);
285     }
286 
287     SetLastError(dwErrorCode);
288     return (dwErrorCode == ERROR_SUCCESS);
289 }
290 
291 BOOL WINAPI
292 GetPrintProcessorDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
293 {
294     BOOL bReturnValue = FALSE;
295     DWORD cch;
296     PWSTR pwszName = NULL;
297     PWSTR pwszEnvironment = NULL;
298     PWSTR pwszPrintProcessorInfo = NULL;
299 
300     TRACE("GetPrintProcessorDirectoryA(%s, %s, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
301 
302     if (pName)
303     {
304         // Convert pName to a Unicode string pwszName.
305         cch = strlen(pName);
306 
307         pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
308         if (!pwszName)
309         {
310             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
311             ERR("HeapAlloc failed!\n");
312             goto Cleanup;
313         }
314 
315         MultiByteToWideChar(CP_ACP, 0, pName, -1, pwszName, cch + 1);
316     }
317 
318     if (pEnvironment)
319     {
320         // Convert pEnvironment to a Unicode string pwszEnvironment.
321         cch = strlen(pEnvironment);
322 
323         pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
324         if (!pwszEnvironment)
325         {
326             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
327             ERR("HeapAlloc failed!\n");
328             goto Cleanup;
329         }
330 
331         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1);
332     }
333 
334     if (cbBuf && pPrintProcessorInfo)
335     {
336         // Allocate a temporary buffer for the Unicode result.
337         // We can just go with cbBuf here. The user should have set it based on pcbNeeded returned in a previous call and our
338         // pcbNeeded is the same for the A and W functions.
339         pwszPrintProcessorInfo = HeapAlloc(hProcessHeap, 0, cbBuf);
340         if (!pwszPrintProcessorInfo)
341         {
342             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
343             ERR("HeapAlloc failed!\n");
344             goto Cleanup;
345         }
346     }
347 
348     bReturnValue = GetPrintProcessorDirectoryW(pwszName, pwszEnvironment, Level, (PBYTE)pwszPrintProcessorInfo, cbBuf, pcbNeeded);
349 
350     if (bReturnValue)
351     {
352         // Convert pwszPrintProcessorInfo to an ANSI string pPrintProcessorInfo.
353         WideCharToMultiByte(CP_ACP, 0, pwszPrintProcessorInfo, -1, (PSTR)pPrintProcessorInfo, cbBuf, NULL, NULL);
354     }
355 
356 Cleanup:
357     if (pwszName)
358         HeapFree(hProcessHeap, 0, pwszName);
359 
360     if (pwszEnvironment)
361         HeapFree(hProcessHeap, 0, pwszEnvironment);
362 
363     if (pwszPrintProcessorInfo)
364         HeapFree(hProcessHeap, 0, pwszPrintProcessorInfo);
365 
366     return bReturnValue;
367 }
368 
369 BOOL WINAPI
370 GetPrintProcessorDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
371 {
372     DWORD dwErrorCode;
373 
374     TRACE("GetPrintProcessorDirectoryW(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
375 
376     // Sanity checks
377     if (Level != 1)
378     {
379         dwErrorCode = ERROR_INVALID_LEVEL;
380         goto Cleanup;
381     }
382 
383     // Choose our current environment if the caller didn't give any.
384     if (!pEnvironment)
385         pEnvironment = (PWSTR)wszCurrentEnvironment;
386 
387     // Do the RPC call
388     RpcTryExcept
389     {
390         dwErrorCode = _RpcGetPrintProcessorDirectory(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
391     }
392     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
393     {
394         dwErrorCode = RpcExceptionCode();
395     }
396     RpcEndExcept;
397 
398 Cleanup:
399     SetLastError(dwErrorCode);
400     return (dwErrorCode == ERROR_SUCCESS);
401 }
402