ReactOS 0.4.15-dev-7788-g1ad9096
printprocessors.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions related to Print Processors
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6 */
7
8#include "precomp.h"
9
10
11// Local Variables
13
29static DWORD
31{
32 const WCHAR wszEnvironmentsKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\";
33 const DWORD cchEnvironmentsKey = _countof(wszEnvironmentsKey) - 1;
34
35 DWORD cchEnvironment;
36 DWORD dwErrorCode;
37 PWSTR pwszEnvironmentKey = NULL;
38
39 // Sanity checks
40 if (!pEnvironment)
41 {
42 dwErrorCode = ERROR_INVALID_ENVIRONMENT;
43 goto Cleanup;
44 }
45
46 // Construct the registry key of the demanded environment.
47 cchEnvironment = wcslen(pEnvironment);
48 pwszEnvironmentKey = DllAllocSplMem((cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
49 if (!pwszEnvironmentKey)
50 {
51 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
52 ERR("DllAllocSplMem failed!\n");
53 goto Cleanup;
54 }
55
56 CopyMemory(pwszEnvironmentKey, wszEnvironmentsKey, cchEnvironmentsKey * sizeof(WCHAR));
57 CopyMemory(&pwszEnvironmentKey[cchEnvironmentsKey], pEnvironment, (cchEnvironment + 1) * sizeof(WCHAR));
58
59 // Open the registry key.
60 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszEnvironmentKey, 0, KEY_READ, hKey);
61 if (dwErrorCode == ERROR_FILE_NOT_FOUND)
62 {
63 dwErrorCode = ERROR_INVALID_ENVIRONMENT;
64 goto Cleanup;
65 }
66 else if (dwErrorCode != ERROR_SUCCESS)
67 {
68 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
69 goto Cleanup;
70 }
71
73 if (pwszEnvironmentKey)
74 DllFreeSplMem(pwszEnvironmentKey);
75
76 return dwErrorCode;
77}
78
79BOOL
80FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
81{
82 DWORD i;
83 PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1;
84
85 TRACE("FindDatatype(%p, %S)\n", pPrintProcessor, pwszDatatype);
86
87 if (!pwszDatatype)
88 return FALSE;
89
90 for (i = 0; i < pPrintProcessor->dwDatatypeCount; i++)
91 {
92 if (wcsicmp(pCurrentDatatype->pName, pwszDatatype) == 0)
93 return TRUE;
94
95 ++pCurrentDatatype;
96 }
97
98 return FALSE;
99}
100
103{
105 PLOCAL_PRINT_PROCESSOR pPrintProcessor;
106
107 TRACE("FindPrintProcessor(%S)\n", pwszName);
108
109 if (!pwszName)
110 return NULL;
111
113 {
115
116 if (wcsicmp(pPrintProcessor->pwszName, pwszName) == 0)
117 return pPrintProcessor;
118 }
119
120 return NULL;
121}
122
128BOOL
130{
131 DWORD cbDatatypes;
132 DWORD cbFileName;
133 DWORD cchPrintProcessorPath;
134 DWORD cchMaxSubKey;
135 DWORD cchPrintProcessorName;
136 DWORD dwErrorCode;
137 DWORD dwSubKeys;
138 DWORD i;
139 HINSTANCE hinstPrintProcessor;
140 HKEY hKey = NULL;
141 HKEY hSubKey = NULL;
142 HKEY hSubSubKey = NULL;
143 PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
145 WCHAR wszPrintProcessorPath[MAX_PATH];
146
147 TRACE("InitializePrintProcessorList()\n");
148
149 // Initialize an empty list for our Print Processors.
151
152 // Prepare the path to the Print Processor directory.
153 if (!LocalGetPrintProcessorDirectory(NULL, (PWSTR)wszCurrentEnvironment, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
154 {
155 dwErrorCode = GetLastError();
156 goto Cleanup;
157 }
158
159 // LocalGetPrintProcessorDirectory returns the number of copied bytes. Convert this into a number of characters without the terminating null-character.
160 cchPrintProcessorPath /= sizeof(WCHAR);
161 --cchPrintProcessorPath;
162
163 // Append a trailing backslash.
164 wszPrintProcessorPath[cchPrintProcessorPath] = L'\\';
165 ++cchPrintProcessorPath;
166
167 // Open the environment registry key.
169 if (dwErrorCode != ERROR_SUCCESS)
170 goto Cleanup;
171
172 // Open the "Print Processors" subkey.
173 dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
174 if (dwErrorCode != ERROR_SUCCESS)
175 {
176 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
177 goto Cleanup;
178 }
179
180 // Get the number of Print Processors and maximum sub key length.
181 dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
182 if (dwErrorCode != ERROR_SUCCESS)
183 {
184 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
185 goto Cleanup;
186 }
187
188 // Loop through all available local Print Processors.
189 for (i = 0; i < dwSubKeys; i++)
190 {
191 // Cleanup tasks from the previous run
192 if (hSubSubKey)
193 {
194 RegCloseKey(hSubSubKey);
195 hSubSubKey = NULL;
196 }
197
198 if (pPrintProcessor)
199 {
200 if (pPrintProcessor->pwszName)
201 DllFreeSplStr(pPrintProcessor->pwszName);
202
203 if (pPrintProcessor->pDatatypesInfo1)
204 DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
205
206 DllFreeSplMem(pPrintProcessor);
207 pPrintProcessor = NULL;
208 }
209
210 // Create a new LOCAL_PRINT_PROCESSOR structure for it.
211 pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
212 if (!pPrintProcessor)
213 {
214 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
215 ERR("DllAllocSplMem failed!\n");
216 goto Cleanup;
217 }
218
219 // Allocate memory for the Print Monitor Name.
220 pPrintProcessor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
221 if (!pPrintProcessor->pwszName)
222 {
223 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
224 ERR("DllAllocSplMem failed!\n");
225 goto Cleanup;
226 }
227
228 // Get the name of this Print Processor.
229 cchPrintProcessorName = cchMaxSubKey + 1;
230 dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pPrintProcessor->pwszName, &cchPrintProcessorName, NULL, NULL, NULL, NULL);
231 if (dwErrorCode != ERROR_SUCCESS)
232 {
233 ERR("RegEnumKeyExW failed with status %ld!\n", dwErrorCode);
234 continue;
235 }
236
237 // Open this Print Processor's registry key.
238 dwErrorCode = (DWORD)RegOpenKeyExW(hSubKey, pPrintProcessor->pwszName, 0, KEY_READ, &hSubSubKey);
239 if (dwErrorCode != ERROR_SUCCESS)
240 {
241 ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
242 continue;
243 }
244
245 // Get the file name of the Print Processor.
246 cbFileName = sizeof(wszFileName);
247 dwErrorCode = (DWORD)RegQueryValueExW(hSubSubKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
248 if (dwErrorCode != ERROR_SUCCESS)
249 {
250 ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
251 continue;
252 }
253
254 // Verify that our buffer is large enough.
255 if (cchPrintProcessorPath + cbFileName / sizeof(WCHAR) > MAX_PATH)
256 {
257 ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName, pPrintProcessor->pwszName);
258 continue;
259 }
260
261 // Construct the full path to the Print Processor.
262 CopyMemory(&wszPrintProcessorPath[cchPrintProcessorPath], wszFileName, cbFileName);
263
264 // Try to load it.
265 hinstPrintProcessor = LoadLibraryW(wszPrintProcessorPath);
266 if (!hinstPrintProcessor)
267 {
268 ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
269 continue;
270 }
271
272 // Get and verify all its function pointers.
273 pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
274 if (!pPrintProcessor->pfnClosePrintProcessor)
275 {
276 ERR("Print Processor \"%S\" exports no ClosePrintProcessor!\n", wszPrintProcessorPath);
277 continue;
278 }
279
280 pPrintProcessor->pfnControlPrintProcessor = (PControlPrintProcessor)GetProcAddress(hinstPrintProcessor, "ControlPrintProcessor");
281 if (!pPrintProcessor->pfnControlPrintProcessor)
282 {
283 ERR("Print Processor \"%S\" exports no ControlPrintProcessor!\n", wszPrintProcessorPath);
284 continue;
285 }
286
287 pPrintProcessor->pfnEnumPrintProcessorDatatypesW = (PEnumPrintProcessorDatatypesW)GetProcAddress(hinstPrintProcessor, "EnumPrintProcessorDatatypesW");
288 if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW)
289 {
290 ERR("Print Processor \"%S\" exports no EnumPrintProcessorDatatypesW!\n", wszPrintProcessorPath);
291 continue;
292 }
293
294 pPrintProcessor->pfnGetPrintProcessorCapabilities = (PGetPrintProcessorCapabilities)GetProcAddress(hinstPrintProcessor, "GetPrintProcessorCapabilities");
295 if (!pPrintProcessor->pfnGetPrintProcessorCapabilities)
296 {
297 ERR("Print Processor \"%S\" exports no GetPrintProcessorCapabilities!\n", wszPrintProcessorPath);
298 continue;
299 }
300
301 pPrintProcessor->pfnOpenPrintProcessor = (POpenPrintProcessor)GetProcAddress(hinstPrintProcessor, "OpenPrintProcessor");
302 if (!pPrintProcessor->pfnOpenPrintProcessor)
303 {
304 ERR("Print Processor \"%S\" exports no OpenPrintProcessor!\n", wszPrintProcessorPath);
305 continue;
306 }
307
308 pPrintProcessor->pfnPrintDocumentOnPrintProcessor = (PPrintDocumentOnPrintProcessor)GetProcAddress(hinstPrintProcessor, "PrintDocumentOnPrintProcessor");
309 if (!pPrintProcessor->pfnPrintDocumentOnPrintProcessor)
310 {
311 ERR("Print Processor \"%S\" exports no PrintDocumentOnPrintProcessor!\n", wszPrintProcessorPath);
312 continue;
313 }
314
315 // Get all supported datatypes.
316 pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &pPrintProcessor->dwDatatypeCount);
317 pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
318 if (!pPrintProcessor->pDatatypesInfo1)
319 {
320 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
321 ERR("DllAllocSplMem failed!\n");
322 goto Cleanup;
323 }
324
325 if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, (PBYTE)pPrintProcessor->pDatatypesInfo1, cbDatatypes, &cbDatatypes, &pPrintProcessor->dwDatatypeCount))
326 {
327 ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
328 continue;
329 }
330
331 // Add the Print Processor to the list.
332 InsertTailList(&_PrintProcessorList, &pPrintProcessor->Entry);
333
334 // Don't let the cleanup routines free this.
335 pPrintProcessor = NULL;
336 }
337
338 dwErrorCode = ERROR_SUCCESS;
339
340Cleanup:
341 // Inside the loop
342 if (hSubSubKey)
343 RegCloseKey(hSubSubKey);
344
345 if (pPrintProcessor)
346 {
347 if (pPrintProcessor->pwszName)
348 DllFreeSplStr(pPrintProcessor->pwszName);
349
350 if (pPrintProcessor->pDatatypesInfo1)
351 DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
352
353 DllFreeSplMem(pPrintProcessor);
354 }
355
356 // Outside the loop
357 if (hSubKey)
358 RegCloseKey(hSubKey);
359
360 if (hKey)
362
363 SetLastError(dwErrorCode);
364 return (dwErrorCode == ERROR_SUCCESS);
365}
366
402LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
403{
404 DWORD dwErrorCode;
405 PLOCAL_PRINT_PROCESSOR pPrintProcessor;
406
407 TRACE("LocalEnumPrintProcessorDatatypes(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
408
409 // Sanity checks
410 if (Level != 1)
411 {
412 dwErrorCode = ERROR_INVALID_LEVEL;
413 goto Cleanup;
414 }
415
416 // Try to find the Print Processor.
417 pPrintProcessor = FindPrintProcessor(pPrintProcessorName);
418 if (!pPrintProcessor)
419 {
420 dwErrorCode = ERROR_UNKNOWN_PRINTPROCESSOR;
421 goto Cleanup;
422 }
423
424 // Call its EnumPrintProcessorDatatypesW function.
425 if (pPrintProcessor->pfnEnumPrintProcessorDatatypesW(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned))
426 dwErrorCode = ERROR_SUCCESS;
427 else
428 dwErrorCode = GetLastError();
429
430Cleanup:
431 SetLastError(dwErrorCode);
432 return (dwErrorCode == ERROR_SUCCESS);
433}
434
471LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
472{
473 DWORD cchMaxSubKey;
474 DWORD cchPrintProcessor;
475 DWORD dwErrorCode;
476 DWORD dwPrintProcessorCount;
477 DWORD i;
478 HKEY hKey = NULL;
479 HKEY hSubKey = NULL;
480 PBYTE pCurrentOutputPrintProcessor;
481 PBYTE pCurrentOutputPrintProcessorInfo;
482 PRINTPROCESSOR_INFO_1W PrintProcessorInfo1;
483 PWSTR pwszTemp = NULL;
484
485 TRACE("LocalEnumPrintProcessors(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
486
487 // Sanity checks
488 if (Level != 1)
489 {
490 dwErrorCode = ERROR_INVALID_LEVEL;
491 goto Cleanup;
492 }
493
494 if (!pcbNeeded || !pcReturned)
495 {
496 // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
497 dwErrorCode = ERROR_INVALID_PARAMETER;
498 goto Cleanup;
499 }
500
501 // Verify pEnvironment and open its registry key.
502 // We use the registry and not the PrintProcessorList here, because the caller may request information about a different environment.
503 dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
504 if (dwErrorCode != ERROR_SUCCESS)
505 goto Cleanup;
506
507 // Open the "Print Processors" subkey.
508 dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
509 if (dwErrorCode != ERROR_SUCCESS)
510 {
511 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
512 goto Cleanup;
513 }
514
515 // Get the number of Print Processors and maximum sub key length.
516 dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwPrintProcessorCount, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
517 if (dwErrorCode != ERROR_SUCCESS)
518 {
519 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
520 goto Cleanup;
521 }
522
523 // Allocate a temporary buffer to let RegEnumKeyExW succeed.
524 pwszTemp = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
525 if (!pwszTemp)
526 {
527 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
528 ERR("DllAllocSplMem failed!\n");
529 goto Cleanup;
530 }
531
532 // Determine the required size of the output buffer.
533 *pcbNeeded = 0;
534
535 for (i = 0; i < dwPrintProcessorCount; i++)
536 {
537 // RegEnumKeyExW sucks! Unlike similar API functions, it only returns the actual numbers of characters copied when you supply a buffer large enough.
538 // So use pwszTemp with its size cchMaxSubKey for this.
539 cchPrintProcessor = cchMaxSubKey + 1;
540 dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pwszTemp, &cchPrintProcessor, NULL, NULL, NULL, NULL);
541 if (dwErrorCode != ERROR_SUCCESS)
542 {
543 ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode);
544 goto Cleanup;
545 }
546
547 *pcbNeeded += sizeof(PRINTPROCESSOR_INFO_1W) + (cchPrintProcessor + 1) * sizeof(WCHAR);
548 }
549
550 // Check if the supplied buffer is large enough.
551 if (cbBuf < *pcbNeeded)
552 {
553 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
554 goto Cleanup;
555 }
556
557 // Put the Print Processor strings right after the last PRINTPROCESSOR_INFO_1W structure.
558 pCurrentOutputPrintProcessorInfo = pPrintProcessorInfo;
559 pCurrentOutputPrintProcessor = pPrintProcessorInfo + dwPrintProcessorCount * sizeof(PRINTPROCESSOR_INFO_1W);
560
561 // Copy over all Print Processors.
562 for (i = 0; i < dwPrintProcessorCount; i++)
563 {
564 // This isn't really correct, but doesn't cause any harm, because we've extensively checked the size of the supplied buffer above.
565 cchPrintProcessor = cchMaxSubKey + 1;
566
567 // Copy the Print Processor name.
568 dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, (PWSTR)pCurrentOutputPrintProcessor, &cchPrintProcessor, NULL, NULL, NULL, NULL);
569 if (dwErrorCode != ERROR_SUCCESS)
570 {
571 ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode);
572 goto Cleanup;
573 }
574
575 // Fill and copy the PRINTPROCESSOR_INFO_1W structure belonging to this Print Processor.
576 PrintProcessorInfo1.pName = (PWSTR)pCurrentOutputPrintProcessor;
577 CopyMemory(pCurrentOutputPrintProcessorInfo, &PrintProcessorInfo1, sizeof(PRINTPROCESSOR_INFO_1W));
578
579 // Advance to the next PRINTPROCESSOR_INFO_1W location and string location in the output buffer.
580 pCurrentOutputPrintProcessor += (cchPrintProcessor + 1) * sizeof(WCHAR);
581 pCurrentOutputPrintProcessorInfo += sizeof(PRINTPROCESSOR_INFO_1W);
582 }
583
584 // We've finished successfully!
585 *pcReturned = dwPrintProcessorCount;
586 dwErrorCode = ERROR_SUCCESS;
587
588Cleanup:
589 if (pwszTemp)
590 DllFreeSplMem(pwszTemp);
591
592 if (hSubKey)
593 RegCloseKey(hSubKey);
594
595 if (hKey)
597
598 SetLastError(dwErrorCode);
599 return (dwErrorCode == ERROR_SUCCESS);
600}
601
634{
635 const WCHAR wszPath[] = L"\\PRTPROCS\\";
636 const DWORD cchPath = _countof(wszPath) - 1;
637
638 DWORD cbDirectoryName;
639 DWORD dwErrorCode;
640 HKEY hKey = NULL;
641 PWSTR pwszDirectory = (PWSTR)pPrintProcessorInfo;
642
643 TRACE("LocalGetPrintProcessorDirectory(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
644
645 // Verify pEnvironment and open its registry key.
646 dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
647 if (dwErrorCode != ERROR_SUCCESS)
648 {
649 ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
650 goto Cleanup;
651 }
652
653 // Determine the size of the required buffer.
654 dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, NULL, &cbDirectoryName);
655 if (dwErrorCode != ERROR_SUCCESS)
656 {
657 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
658 goto Cleanup;
659 }
660
661 *pcbNeeded = (cchSpoolDirectory + cchPath) * sizeof(WCHAR) + cbDirectoryName;
662
663 // Is the supplied buffer large enough?
664 if (cbBuf < *pcbNeeded)
665 {
666 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
667 goto Cleanup;
668 }
669
670 // Copy the path to the "prtprocs" directory into pPrintProcessorInfo
671 CopyMemory(pwszDirectory, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
672 CopyMemory(&pwszDirectory[cchSpoolDirectory], wszPath, cchPath * sizeof(WCHAR));
673
674 // Get the directory name from the registry.
675 dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, (PBYTE)&pwszDirectory[cchSpoolDirectory + cchPath], &cbDirectoryName);
676 if (dwErrorCode != ERROR_SUCCESS)
677 {
678 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
679 goto Cleanup;
680 }
681
682 // We've finished successfully!
683 dwErrorCode = ERROR_SUCCESS;
684
685Cleanup:
686 if (hKey)
688
689 SetLastError(dwErrorCode);
690 return (dwErrorCode == ERROR_SUCCESS);
691}
BOOL(WINAPI * PEnumPrintProcessorDatatypesW)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD)
static WCHAR wszFileName[MAX_PATH]
Definition: wordpad.c:71
const WCHAR wszCurrentEnvironment[]
Definition: prtprocenv.h:11
#define ERR(fmt,...)
Definition: debug.h:110
#define RegCloseKey(hKey)
Definition: registry.h:49
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3362
LONG WINAPI RegEnumKeyExW(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPWSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: reg.c:2533
LONG WINAPI RegQueryInfoKeyW(HKEY hKey, LPWSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
Definition: reg.c:3691
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4132
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define SetLastError(x)
Definition: compat.h:752
#define GetProcAddress(x, y)
Definition: compat.h:753
#define MAX_PATH
Definition: compat.h:34
#define LoadLibraryW(x)
Definition: compat.h:747
#define wcsicmp
Definition: compat.h:15
static const WCHAR Cleanup[]
Definition: register.c:80
#define InsertTailList(ListHead, Entry)
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static LPSTR pName
Definition: security.c:75
#define KEY_READ
Definition: nt_native.h:1023
#define DWORD
Definition: nt_native.h:44
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
DWORD * PDWORD
Definition: pedump.c:68
BOOL InitializePrintProcessorList(void)
BOOL WINAPI LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
BOOL WINAPI LocalGetPrintProcessorDirectory(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
static LIST_ENTRY _PrintProcessorList
PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PCWSTR pwszName)
static DWORD _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
BOOL FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
BOOL WINAPI LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
#define _countof(array)
Definition: sndvol32.h:68
#define TRACE(s)
Definition: solgame.cpp:4
base of all file and directory entries
Definition: entries.h:83
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PEnumPrintProcessorDatatypesW pfnEnumPrintProcessorDatatypesW
Definition: precomp.h:106
LIST_ENTRY Entry
Definition: precomp.h:100
PGetPrintProcessorCapabilities pfnGetPrintProcessorCapabilities
Definition: precomp.h:107
PControlPrintProcessor pfnControlPrintProcessor
Definition: precomp.h:105
PPrintDocumentOnPrintProcessor pfnPrintDocumentOnPrintProcessor
Definition: precomp.h:109
PClosePrintProcessor pfnClosePrintProcessor
Definition: precomp.h:104
POpenPrintProcessor pfnOpenPrintProcessor
Definition: precomp.h:108
PDATATYPES_INFO_1W pDatatypesInfo1
Definition: precomp.h:102
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
unsigned char * LPBYTE
Definition: typedefs.h:53
uint32_t * LPDWORD
Definition: typedefs.h:59
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
BOOL WINAPI DllFreeSplStr(PWSTR pwszString)
Definition: memory.c:130
DWORD cchSpoolDirectory
Definition: main.c:16
WCHAR wszSpoolDirectory[MAX_PATH]
Definition: main.c:15
BOOL(WINAPI * PControlPrintProcessor)(HANDLE, DWORD)
Definition: precomp.h:46
BOOL(WINAPI * PClosePrintProcessor)(HANDLE)
Definition: precomp.h:45
DWORD(WINAPI * PGetPrintProcessorCapabilities)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD)
Definition: precomp.h:48
BOOL(WINAPI * PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR)
Definition: precomp.h:50
HANDLE(WINAPI * POpenPrintProcessor)(LPWSTR, PPRINTPROCESSOROPENDATA)
Definition: precomp.h:49
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CopyMemory
Definition: winbase.h:1710
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3828
#define WINAPI
Definition: msvc.h:6
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
#define ERROR_INVALID_ENVIRONMENT
Definition: winerror.h:1112
#define ERROR_UNKNOWN_PRINTPROCESSOR
Definition: winerror.h:1105
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
struct _PRINTPROCESSOR_INFO_1W PRINTPROCESSOR_INFO_1W
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184