* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Print Processors
- * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT: Copyright 2015-2016 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
* Checks a supplied pEnvironment variable for validity and opens its registry key.
*
* @param pEnvironment
- * The pEnvironment variable to check. Can be NULL to use the current environment.
+ * The pEnvironment variable to check.
*
* @param hKey
* On success, this variable will contain a HKEY to the opened registry key of the environment.
DWORD dwErrorCode;
PWSTR pwszEnvironmentKey = NULL;
- // Use the current environment if none was supplied.
+ // Sanity checks
if (!pEnvironment)
- pEnvironment = wszCurrentEnvironment;
+ {
+ dwErrorCode = ERROR_INVALID_ENVIRONMENT;
+ goto Cleanup;
+ }
// Construct the registry key of the demanded environment.
cchEnvironment = wcslen(pEnvironment);
}
BOOL
-FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype)
+FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
{
DWORD i;
PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1;
+ if (!pwszDatatype)
+ return FALSE;
+
for (i = 0; i < pPrintProcessor->dwDatatypeCount; i++)
{
if (wcsicmp(pCurrentDatatype->pName, pwszDatatype) == 0)
}
PLOCAL_PRINT_PROCESSOR
-FindPrintProcessor(PWSTR pwszName)
+FindPrintProcessor(PCWSTR pwszName)
{
PLIST_ENTRY pEntry;
PLOCAL_PRINT_PROCESSOR pPrintProcessor;
- for (pEntry = _PrintProcessorList.Flink; pEntry; pEntry = pEntry->Flink)
+ if (!pwszName)
+ return NULL;
+
+ for (pEntry = _PrintProcessorList.Flink; pEntry != &_PrintProcessorList; pEntry = pEntry->Flink)
{
pPrintProcessor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_PROCESSOR, Entry);
*
* Initializes a singly linked list of locally available Print Processors.
*/
-void
+BOOL
InitializePrintProcessorList()
{
DWORD cbDatatypes;
DWORD cchPrintProcessorPath;
DWORD cchMaxSubKey;
DWORD cchPrintProcessorName;
+ DWORD dwErrorCode;
DWORD dwSubKeys;
DWORD i;
HINSTANCE hinstPrintProcessor;
HKEY hKey = NULL;
HKEY hSubKey = NULL;
HKEY hSubSubKey = NULL;
- LONG lStatus;
PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
- PWSTR pwszPrintProcessorName = NULL;
WCHAR wszFileName[MAX_PATH];
WCHAR wszPrintProcessorPath[MAX_PATH];
InitializeListHead(&_PrintProcessorList);
// Prepare the path to the Print Processor directory.
- if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
+ if (!LocalGetPrintProcessorDirectory(NULL, (PWSTR)wszCurrentEnvironment, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
+ {
+ dwErrorCode = GetLastError();
goto Cleanup;
+ }
+ // LocalGetPrintProcessorDirectory returns the number of copied bytes. Convert this into a number of characters without the terminating null-character.
cchPrintProcessorPath /= sizeof(WCHAR);
- wszPrintProcessorPath[cchPrintProcessorPath++] = L'\\';
+ --cchPrintProcessorPath;
+
+ // Append a trailing backslash.
+ wszPrintProcessorPath[cchPrintProcessorPath] = L'\\';
+ ++cchPrintProcessorPath;
// Open the environment registry key.
- if (_OpenEnvironment(NULL, &hKey) != ERROR_SUCCESS)
+ dwErrorCode = _OpenEnvironment(wszCurrentEnvironment, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
goto Cleanup;
// Open the "Print Processors" subkey.
- lStatus = RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
- if (lStatus != ERROR_SUCCESS)
+ dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
{
- ERR("RegOpenKeyExW failed with status %ld!\n", lStatus);
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
// Get the number of Print Processors and maximum sub key length.
- lStatus = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
- if (lStatus != ERROR_SUCCESS)
- {
- ERR("RegQueryInfoKeyW failed with status %ld!\n", lStatus);
- goto Cleanup;
- }
-
- // Allocate a temporary buffer for the Print Processor names.
- pwszPrintProcessorName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
- if (!pwszPrintProcessorName)
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
{
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
pPrintProcessor = NULL;
}
+ // Create a new LOCAL_PRINT_PROCESSOR structure for it.
+ pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
+ if (!pPrintProcessor)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Allocate memory for the Print Monitor Name.
+ pPrintProcessor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+ if (!pPrintProcessor->pwszName)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
// Get the name of this Print Processor.
- cchPrintProcessorName = cchMaxSubKey;
- lStatus = RegEnumKeyExW(hSubKey, i, pwszPrintProcessorName, &cchPrintProcessorName, NULL, NULL, NULL, NULL);
- if (lStatus != ERROR_SUCCESS)
+ cchPrintProcessorName = cchMaxSubKey + 1;
+ dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pPrintProcessor->pwszName, &cchPrintProcessorName, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
{
- ERR("RegEnumKeyExW failed with status %ld!\n", lStatus);
+ ERR("RegEnumKeyExW failed with status %ld!\n", dwErrorCode);
continue;
}
// Open this Print Processor's registry key.
- lStatus = RegOpenKeyExW(hSubKey, pwszPrintProcessorName, 0, KEY_READ, &hSubSubKey);
- if (lStatus != ERROR_SUCCESS)
+ dwErrorCode = (DWORD)RegOpenKeyExW(hSubKey, pPrintProcessor->pwszName, 0, KEY_READ, &hSubSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
{
- ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %ld!\n", pwszPrintProcessorName, lStatus);
+ ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
continue;
}
// Get the file name of the Print Processor.
cbFileName = sizeof(wszFileName);
- lStatus = RegQueryValueExW(hSubSubKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
- if (lStatus != ERROR_SUCCESS)
+ dwErrorCode = (DWORD)RegQueryValueExW(hSubSubKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
+ if (dwErrorCode != ERROR_SUCCESS)
{
- ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %ld!\n", pwszPrintProcessorName, lStatus);
+ ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
continue;
}
// Verify that our buffer is large enough.
if (cchPrintProcessorPath + cbFileName / sizeof(WCHAR) > MAX_PATH)
{
- ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName, pwszPrintProcessorName);
+ ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName, pPrintProcessor->pwszName);
continue;
}
// Try to load it.
hinstPrintProcessor = LoadLibraryW(wszPrintProcessorPath);
- if (lStatus != ERROR_SUCCESS)
+ if (!hinstPrintProcessor)
{
ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
continue;
}
- // Create a new LOCAL_PRINT_PROCESSOR structure for it.
- pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
- pPrintProcessor->pwszName = AllocSplStr(pwszPrintProcessorName);
-
// Get and verify all its function pointers.
pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
if (!pPrintProcessor->pfnClosePrintProcessor)
pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
if (!pPrintProcessor->pDatatypesInfo1)
{
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
pPrintProcessor = NULL;
}
+ dwErrorCode = ERROR_SUCCESS;
+
Cleanup:
// Inside the loop
if (hSubSubKey)
}
// Outside the loop
- if (pwszPrintProcessorName)
- DllFreeSplStr(pwszPrintProcessorName);
-
if (hSubKey)
RegCloseKey(hSubKey);
if (hKey)
RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
/**
DWORD cchMaxSubKey;
DWORD cchPrintProcessor;
DWORD dwErrorCode;
+ DWORD dwPrintProcessorCount;
DWORD i;
HKEY hKey = NULL;
HKEY hSubKey = NULL;
}
// Get the number of Print Processors and maximum sub key length.
- dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, pcReturned, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwPrintProcessorCount, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
// Determine the required size of the output buffer.
*pcbNeeded = 0;
- for (i = 0; i < *pcReturned; i++)
+ for (i = 0; i < dwPrintProcessorCount; i++)
{
// RegEnumKeyExW sucks! Unlike similar API functions, it only returns the actual numbers of characters copied when you supply a buffer large enough.
// So use pwszTemp with its size cchMaxSubKey for this.
- cchPrintProcessor = cchMaxSubKey;
+ cchPrintProcessor = cchMaxSubKey + 1;
dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pwszTemp, &cchPrintProcessor, NULL, NULL, NULL, NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
// Put the Print Processor strings right after the last PRINTPROCESSOR_INFO_1W structure.
pCurrentOutputPrintProcessorInfo = pPrintProcessorInfo;
- pCurrentOutputPrintProcessor = pPrintProcessorInfo + *pcReturned * sizeof(PRINTPROCESSOR_INFO_1W);
+ pCurrentOutputPrintProcessor = pPrintProcessorInfo + dwPrintProcessorCount * sizeof(PRINTPROCESSOR_INFO_1W);
// Copy over all Print Processors.
- for (i = 0; i < *pcReturned; i++)
+ for (i = 0; i < dwPrintProcessorCount; i++)
{
// This isn't really correct, but doesn't cause any harm, because we've extensively checked the size of the supplied buffer above.
- cchPrintProcessor = cchMaxSubKey;
+ cchPrintProcessor = cchMaxSubKey + 1;
// Copy the Print Processor name.
dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, (PWSTR)pCurrentOutputPrintProcessor, &cchPrintProcessor, NULL, NULL, NULL, NULL);
}
// We've finished successfully!
+ *pcReturned = dwPrintProcessorCount;
dwErrorCode = ERROR_SUCCESS;
Cleanup:
*
* @param pEnvironment
* One of the predefined operating system and architecture "environment" strings (like "Windows NT x86").
- * Alternatively, NULL to output the Print Processor directory of the current environment.
*
* @param Level
* The level of the (non-existing) structure supplied through pPrintProcessorInfo. This must be 1.
* A more specific error code can be obtained through GetLastError.
*/
BOOL WINAPI
-LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+LocalGetPrintProcessorDirectory(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
{
const WCHAR wszPath[] = L"\\PRTPROCS\\";
const DWORD cchPath = _countof(wszPath) - 1;
- DWORD cbDataWritten;
+ DWORD cbDirectoryName;
DWORD dwErrorCode;
HKEY hKey = NULL;
-
- // Sanity checks
- if (Level != 1)
- {
- dwErrorCode = ERROR_INVALID_LEVEL;
- goto Cleanup;
- }
-
- if (!pcbNeeded)
- {
- // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
- dwErrorCode = ERROR_INVALID_PARAMETER;
- goto Cleanup;
- }
+ PWSTR pwszDirectory = (PWSTR)pPrintProcessorInfo;
// Verify pEnvironment and open its registry key.
dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
goto Cleanup;
+ }
// Determine the size of the required buffer.
- dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, NULL, pcbNeeded);
+ dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, NULL, &cbDirectoryName);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
- *pcbNeeded += cchSpoolDirectory;
- *pcbNeeded += cchPath;
+ *pcbNeeded = (cchSpoolDirectory + cchPath) * sizeof(WCHAR) + cbDirectoryName;
// Is the supplied buffer large enough?
if (cbBuf < *pcbNeeded)
}
// Copy the path to the "prtprocs" directory into pPrintProcessorInfo
- CopyMemory(pPrintProcessorInfo, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
- CopyMemory(&pPrintProcessorInfo[cchSpoolDirectory], wszPath, cchPath * sizeof(WCHAR));
+ CopyMemory(pwszDirectory, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
+ CopyMemory(&pwszDirectory[cchSpoolDirectory], wszPath, cchPath * sizeof(WCHAR));
// Get the directory name from the registry.
- dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, &pPrintProcessorInfo[cchSpoolDirectory + cchPath], &cbDataWritten);
+ dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, (PBYTE)&pwszDirectory[cchSpoolDirectory + cchPath], &cbDirectoryName);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);