[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / win32ss / printing / base / winspool / printprocessors.c
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 }