2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions related to Print Processors
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
12 static LIST_ENTRY _PrintProcessorList
;
15 * @name _OpenEnvironment
17 * Checks a supplied pEnvironment variable for validity and opens its registry key.
20 * The pEnvironment variable to check.
23 * On success, this variable will contain a HKEY to the opened registry key of the environment.
24 * You can use it for further tasks and have to close it with RegCloseKey.
27 * A Windows Error Code indicating success or failure.
30 _OpenEnvironment(PCWSTR pEnvironment
, PHKEY hKey
)
32 const WCHAR wszEnvironmentsKey
[] = L
"SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\";
33 const DWORD cchEnvironmentsKey
= _countof(wszEnvironmentsKey
) - 1;
37 PWSTR pwszEnvironmentKey
= NULL
;
42 dwErrorCode
= ERROR_INVALID_ENVIRONMENT
;
46 // Construct the registry key of the demanded environment.
47 cchEnvironment
= wcslen(pEnvironment
);
48 pwszEnvironmentKey
= DllAllocSplMem((cchEnvironmentsKey
+ cchEnvironment
+ 1) * sizeof(WCHAR
));
49 if (!pwszEnvironmentKey
)
51 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
52 ERR("DllAllocSplMem failed!\n");
56 CopyMemory(pwszEnvironmentKey
, wszEnvironmentsKey
, cchEnvironmentsKey
* sizeof(WCHAR
));
57 CopyMemory(&pwszEnvironmentKey
[cchEnvironmentsKey
], pEnvironment
, (cchEnvironment
+ 1) * sizeof(WCHAR
));
59 // Open the registry key.
60 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_LOCAL_MACHINE
, pwszEnvironmentKey
, 0, KEY_READ
, hKey
);
61 if (dwErrorCode
== ERROR_FILE_NOT_FOUND
)
63 dwErrorCode
= ERROR_INVALID_ENVIRONMENT
;
66 else if (dwErrorCode
!= ERROR_SUCCESS
)
68 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
73 if (pwszEnvironmentKey
)
74 DllFreeSplMem(pwszEnvironmentKey
);
80 FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor
, PCWSTR pwszDatatype
)
83 PDATATYPES_INFO_1W pCurrentDatatype
= pPrintProcessor
->pDatatypesInfo1
;
85 TRACE("FindDatatype(%p, %S)\n", pPrintProcessor
, pwszDatatype
);
90 for (i
= 0; i
< pPrintProcessor
->dwDatatypeCount
; i
++)
92 if (wcsicmp(pCurrentDatatype
->pName
, pwszDatatype
) == 0)
101 PLOCAL_PRINT_PROCESSOR
102 FindPrintProcessor(PCWSTR pwszName
)
105 PLOCAL_PRINT_PROCESSOR pPrintProcessor
;
107 TRACE("FindPrintProcessor(%S)\n", pwszName
);
112 for (pEntry
= _PrintProcessorList
.Flink
; pEntry
!= &_PrintProcessorList
; pEntry
= pEntry
->Flink
)
114 pPrintProcessor
= CONTAINING_RECORD(pEntry
, LOCAL_PRINT_PROCESSOR
, Entry
);
116 if (wcsicmp(pPrintProcessor
->pwszName
, pwszName
) == 0)
117 return pPrintProcessor
;
124 * @name InitializePrintProcessorList
126 * Initializes a singly linked list of locally available Print Processors.
129 InitializePrintProcessorList(void)
133 DWORD cchPrintProcessorPath
;
135 DWORD cchPrintProcessorName
;
139 HINSTANCE hinstPrintProcessor
;
142 HKEY hSubSubKey
= NULL
;
143 PLOCAL_PRINT_PROCESSOR pPrintProcessor
= NULL
;
144 WCHAR wszFileName
[MAX_PATH
];
145 WCHAR wszPrintProcessorPath
[MAX_PATH
];
147 TRACE("InitializePrintProcessorList()\n");
149 // Initialize an empty list for our Print Processors.
150 InitializeListHead(&_PrintProcessorList
);
152 // Prepare the path to the Print Processor directory.
153 if (!LocalGetPrintProcessorDirectory(NULL
, (PWSTR
)wszCurrentEnvironment
, 1, (PBYTE
)wszPrintProcessorPath
, sizeof(wszPrintProcessorPath
), &cchPrintProcessorPath
))
155 dwErrorCode
= GetLastError();
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
;
163 // Append a trailing backslash.
164 wszPrintProcessorPath
[cchPrintProcessorPath
] = L
'\\';
165 ++cchPrintProcessorPath
;
167 // Open the environment registry key.
168 dwErrorCode
= _OpenEnvironment(wszCurrentEnvironment
, &hKey
);
169 if (dwErrorCode
!= ERROR_SUCCESS
)
172 // Open the "Print Processors" subkey.
173 dwErrorCode
= (DWORD
)RegOpenKeyExW(hKey
, L
"Print Processors", 0, KEY_READ
, &hSubKey
);
174 if (dwErrorCode
!= ERROR_SUCCESS
)
176 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
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
)
184 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode
);
188 // Loop through all available local Print Processors.
189 for (i
= 0; i
< dwSubKeys
; i
++)
191 // Cleanup tasks from the previous run
194 RegCloseKey(hSubSubKey
);
200 if (pPrintProcessor
->pwszName
)
201 DllFreeSplStr(pPrintProcessor
->pwszName
);
203 if (pPrintProcessor
->pDatatypesInfo1
)
204 DllFreeSplMem(pPrintProcessor
->pDatatypesInfo1
);
206 DllFreeSplMem(pPrintProcessor
);
207 pPrintProcessor
= NULL
;
210 // Create a new LOCAL_PRINT_PROCESSOR structure for it.
211 pPrintProcessor
= DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR
));
212 if (!pPrintProcessor
)
214 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
215 ERR("DllAllocSplMem failed!\n");
219 // Allocate memory for the Print Monitor Name.
220 pPrintProcessor
->pwszName
= DllAllocSplMem((cchMaxSubKey
+ 1) * sizeof(WCHAR
));
221 if (!pPrintProcessor
->pwszName
)
223 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
224 ERR("DllAllocSplMem failed!\n");
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
)
233 ERR("RegEnumKeyExW failed with status %ld!\n", dwErrorCode
);
237 // Open this Print Processor's registry key.
238 dwErrorCode
= (DWORD
)RegOpenKeyExW(hSubKey
, pPrintProcessor
->pwszName
, 0, KEY_READ
, &hSubSubKey
);
239 if (dwErrorCode
!= ERROR_SUCCESS
)
241 ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor
->pwszName
, dwErrorCode
);
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
)
250 ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor
->pwszName
, dwErrorCode
);
254 // Verify that our buffer is large enough.
255 if (cchPrintProcessorPath
+ cbFileName
/ sizeof(WCHAR
) > MAX_PATH
)
257 ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName
, pPrintProcessor
->pwszName
);
261 // Construct the full path to the Print Processor.
262 CopyMemory(&wszPrintProcessorPath
[cchPrintProcessorPath
], wszFileName
, cbFileName
);
265 hinstPrintProcessor
= LoadLibraryW(wszPrintProcessorPath
);
266 if (!hinstPrintProcessor
)
268 ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", wszPrintProcessorPath
, GetLastError());
272 // Get and verify all its function pointers.
273 pPrintProcessor
->pfnClosePrintProcessor
= (PClosePrintProcessor
)GetProcAddress(hinstPrintProcessor
, "ClosePrintProcessor");
274 if (!pPrintProcessor
->pfnClosePrintProcessor
)
276 ERR("Print Processor \"%S\" exports no ClosePrintProcessor!\n", wszPrintProcessorPath
);
280 pPrintProcessor
->pfnControlPrintProcessor
= (PControlPrintProcessor
)GetProcAddress(hinstPrintProcessor
, "ControlPrintProcessor");
281 if (!pPrintProcessor
->pfnControlPrintProcessor
)
283 ERR("Print Processor \"%S\" exports no ControlPrintProcessor!\n", wszPrintProcessorPath
);
287 pPrintProcessor
->pfnEnumPrintProcessorDatatypesW
= (PEnumPrintProcessorDatatypesW
)GetProcAddress(hinstPrintProcessor
, "EnumPrintProcessorDatatypesW");
288 if (!pPrintProcessor
->pfnEnumPrintProcessorDatatypesW
)
290 ERR("Print Processor \"%S\" exports no EnumPrintProcessorDatatypesW!\n", wszPrintProcessorPath
);
294 pPrintProcessor
->pfnGetPrintProcessorCapabilities
= (PGetPrintProcessorCapabilities
)GetProcAddress(hinstPrintProcessor
, "GetPrintProcessorCapabilities");
295 if (!pPrintProcessor
->pfnGetPrintProcessorCapabilities
)
297 ERR("Print Processor \"%S\" exports no GetPrintProcessorCapabilities!\n", wszPrintProcessorPath
);
301 pPrintProcessor
->pfnOpenPrintProcessor
= (POpenPrintProcessor
)GetProcAddress(hinstPrintProcessor
, "OpenPrintProcessor");
302 if (!pPrintProcessor
->pfnOpenPrintProcessor
)
304 ERR("Print Processor \"%S\" exports no OpenPrintProcessor!\n", wszPrintProcessorPath
);
308 pPrintProcessor
->pfnPrintDocumentOnPrintProcessor
= (PPrintDocumentOnPrintProcessor
)GetProcAddress(hinstPrintProcessor
, "PrintDocumentOnPrintProcessor");
309 if (!pPrintProcessor
->pfnPrintDocumentOnPrintProcessor
)
311 ERR("Print Processor \"%S\" exports no PrintDocumentOnPrintProcessor!\n", wszPrintProcessorPath
);
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
)
320 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
321 ERR("DllAllocSplMem failed!\n");
325 if (!pPrintProcessor
->pfnEnumPrintProcessorDatatypesW(NULL
, NULL
, 1, (PBYTE
)pPrintProcessor
->pDatatypesInfo1
, cbDatatypes
, &cbDatatypes
, &pPrintProcessor
->dwDatatypeCount
))
327 ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath
, GetLastError());
331 // Add the Print Processor to the list.
332 InsertTailList(&_PrintProcessorList
, &pPrintProcessor
->Entry
);
334 // Don't let the cleanup routines free this.
335 pPrintProcessor
= NULL
;
338 dwErrorCode
= ERROR_SUCCESS
;
343 RegCloseKey(hSubSubKey
);
347 if (pPrintProcessor
->pwszName
)
348 DllFreeSplStr(pPrintProcessor
->pwszName
);
350 if (pPrintProcessor
->pDatatypesInfo1
)
351 DllFreeSplMem(pPrintProcessor
->pDatatypesInfo1
);
353 DllFreeSplMem(pPrintProcessor
);
358 RegCloseKey(hSubKey
);
363 SetLastError(dwErrorCode
);
364 return (dwErrorCode
== ERROR_SUCCESS
);
368 * @name LocalEnumPrintProcessorDatatypes
370 * Obtains an array of all datatypes supported by a particular Print Processor.
371 * Print Provider function for EnumPrintProcessorDatatypesA/EnumPrintProcessorDatatypesW.
374 * Server Name. Ignored here, because every caller of LocalEnumPrintProcessorDatatypes is interested in the local directory.
376 * @param pPrintProcessorName
377 * The (case-insensitive) name of the Print Processor to query.
380 * The level of the structure supplied through pDatatypes. This must be 1.
383 * Pointer to the buffer that receives an array of DATATYPES_INFO_1W structures.
384 * Can be NULL if you just want to know the required size of the buffer.
387 * Size of the buffer you supplied for pDatatypes, in bytes.
390 * Pointer to a variable that receives the required size of the buffer for pDatatypes, in bytes.
391 * This parameter mustn't be NULL!
394 * Pointer to a variable that receives the number of elements of the DATATYPES_INFO_1W array.
395 * This parameter mustn't be NULL!
398 * TRUE if we successfully copied the array into pDatatypes, FALSE otherwise.
399 * A more specific error code can be obtained through GetLastError.
402 LocalEnumPrintProcessorDatatypes(LPWSTR pName
, LPWSTR pPrintProcessorName
, DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
405 PLOCAL_PRINT_PROCESSOR pPrintProcessor
;
407 TRACE("LocalEnumPrintProcessorDatatypes(%S, %S, %lu, %p, %lu, %p, %p)\n", pName
, pPrintProcessorName
, Level
, pDatatypes
, cbBuf
, pcbNeeded
, pcReturned
);
412 dwErrorCode
= ERROR_INVALID_LEVEL
;
416 // Try to find the Print Processor.
417 pPrintProcessor
= FindPrintProcessor(pPrintProcessorName
);
418 if (!pPrintProcessor
)
420 dwErrorCode
= ERROR_UNKNOWN_PRINTPROCESSOR
;
424 // Call its EnumPrintProcessorDatatypesW function.
425 if (pPrintProcessor
->pfnEnumPrintProcessorDatatypesW(pName
, pPrintProcessorName
, Level
, pDatatypes
, cbBuf
, pcbNeeded
, pcReturned
))
426 dwErrorCode
= ERROR_SUCCESS
;
428 dwErrorCode
= GetLastError();
431 SetLastError(dwErrorCode
);
432 return (dwErrorCode
== ERROR_SUCCESS
);
436 * @name LocalEnumPrintProcessors
438 * Obtains an array of all available Print Processors on this computer.
439 * Print Provider function for EnumPrintProcessorsA/EnumPrintProcessorsW.
442 * Server Name. Ignored here, because every caller of LocalEnumPrintProcessors is interested in the local directory.
444 * @param pEnvironment
445 * One of the predefined operating system and architecture "environment" strings (like "Windows NT x86").
446 * Alternatively, NULL to output the Print Processor directory of the current environment.
449 * The level of the structure supplied through pPrintProcessorInfo. This must be 1.
451 * @param pPrintProcessorInfo
452 * Pointer to the buffer that receives an array of PRINTPROCESSOR_INFO_1W structures.
453 * Can be NULL if you just want to know the required size of the buffer.
456 * Size of the buffer you supplied for pPrintProcessorInfo, in bytes.
459 * Pointer to a variable that receives the required size of the buffer for pPrintProcessorInfo, in bytes.
460 * This parameter mustn't be NULL!
463 * Pointer to a variable that receives the number of elements of the PRINTPROCESSOR_INFO_1W array.
464 * This parameter mustn't be NULL!
467 * TRUE if we successfully copied the array into pPrintProcessorInfo, FALSE otherwise.
468 * A more specific error code can be obtained through GetLastError.
471 LocalEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
, LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
474 DWORD cchPrintProcessor
;
476 DWORD dwPrintProcessorCount
;
480 PBYTE pCurrentOutputPrintProcessor
;
481 PBYTE pCurrentOutputPrintProcessorInfo
;
482 PRINTPROCESSOR_INFO_1W PrintProcessorInfo1
;
483 PWSTR pwszTemp
= NULL
;
485 TRACE("LocalEnumPrintProcessors(%S, %S, %lu, %p, %lu, %p, %p)\n", pName
, pEnvironment
, Level
, pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcReturned
);
490 dwErrorCode
= ERROR_INVALID_LEVEL
;
494 if (!pcbNeeded
|| !pcReturned
)
496 // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
497 dwErrorCode
= ERROR_INVALID_PARAMETER
;
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
)
507 // Open the "Print Processors" subkey.
508 dwErrorCode
= (DWORD
)RegOpenKeyExW(hKey
, L
"Print Processors", 0, KEY_READ
, &hSubKey
);
509 if (dwErrorCode
!= ERROR_SUCCESS
)
511 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
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
)
519 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode
);
523 // Allocate a temporary buffer to let RegEnumKeyExW succeed.
524 pwszTemp
= DllAllocSplMem((cchMaxSubKey
+ 1) * sizeof(WCHAR
));
527 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
528 ERR("DllAllocSplMem failed!\n");
532 // Determine the required size of the output buffer.
535 for (i
= 0; i
< dwPrintProcessorCount
; i
++)
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
)
543 ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode
);
547 *pcbNeeded
+= sizeof(PRINTPROCESSOR_INFO_1W
) + (cchPrintProcessor
+ 1) * sizeof(WCHAR
);
550 // Check if the supplied buffer is large enough.
551 if (cbBuf
< *pcbNeeded
)
553 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
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
);
561 // Copy over all Print Processors.
562 for (i
= 0; i
< dwPrintProcessorCount
; i
++)
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;
567 // Copy the Print Processor name.
568 dwErrorCode
= (DWORD
)RegEnumKeyExW(hSubKey
, i
, (PWSTR
)pCurrentOutputPrintProcessor
, &cchPrintProcessor
, NULL
, NULL
, NULL
, NULL
);
569 if (dwErrorCode
!= ERROR_SUCCESS
)
571 ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode
);
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
));
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
);
584 // We've finished successfully!
585 *pcReturned
= dwPrintProcessorCount
;
586 dwErrorCode
= ERROR_SUCCESS
;
590 DllFreeSplMem(pwszTemp
);
593 RegCloseKey(hSubKey
);
598 SetLastError(dwErrorCode
);
599 return (dwErrorCode
== ERROR_SUCCESS
);
603 * @name LocalGetPrintProcessorDirectory
605 * Obtains the path to the local Print Processor directory.
606 * Print Provider function for GetPrintProcessorDirectoryA/GetPrintProcessorDirectoryW.
609 * Server Name. Ignored here, because every caller of LocalGetPrintProcessorDirectory is interested in the local directory.
611 * @param pEnvironment
612 * One of the predefined operating system and architecture "environment" strings (like "Windows NT x86").
615 * The level of the (non-existing) structure supplied through pPrintProcessorInfo. This must be 1.
617 * @param pPrintProcessorInfo
618 * Pointer to the buffer that receives the full path to the Print Processor directory.
619 * Can be NULL if you just want to know the required size of the buffer.
622 * Size of the buffer you supplied for pPrintProcessorInfo, in bytes.
625 * Pointer to a variable that receives the required size of the buffer for pPrintProcessorInfo, in bytes.
626 * This parameter mustn't be NULL!
629 * TRUE if we successfully copied the directory into pPrintProcessorInfo, FALSE otherwise.
630 * A more specific error code can be obtained through GetLastError.
633 LocalGetPrintProcessorDirectory(PWSTR pName
, PWSTR pEnvironment
, DWORD Level
, PBYTE pPrintProcessorInfo
, DWORD cbBuf
, PDWORD pcbNeeded
)
635 const WCHAR wszPath
[] = L
"\\PRTPROCS\\";
636 const DWORD cchPath
= _countof(wszPath
) - 1;
638 DWORD cbDirectoryName
;
641 PWSTR pwszDirectory
= (PWSTR
)pPrintProcessorInfo
;
643 TRACE("LocalGetPrintProcessorDirectory(%S, %S, %lu, %p, %lu, %p)\n", pName
, pEnvironment
, Level
, pPrintProcessorInfo
, cbBuf
, pcbNeeded
);
645 // Verify pEnvironment and open its registry key.
646 dwErrorCode
= _OpenEnvironment(pEnvironment
, &hKey
);
647 if (dwErrorCode
!= ERROR_SUCCESS
)
649 ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode
);
653 // Determine the size of the required buffer.
654 dwErrorCode
= (DWORD
)RegQueryValueExW(hKey
, L
"Directory", NULL
, NULL
, NULL
, &cbDirectoryName
);
655 if (dwErrorCode
!= ERROR_SUCCESS
)
657 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
661 *pcbNeeded
= (cchSpoolDirectory
+ cchPath
) * sizeof(WCHAR
) + cbDirectoryName
;
663 // Is the supplied buffer large enough?
664 if (cbBuf
< *pcbNeeded
)
666 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
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
));
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
)
678 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode
);
682 // We've finished successfully!
683 dwErrorCode
= ERROR_SUCCESS
;
689 SetLastError(dwErrorCode
);
690 return (dwErrorCode
== ERROR_SUCCESS
);