[LOCALSPL]
[reactos.git] / reactos / win32ss / printing / providers / localspl / printprocessors.c
index ea29a00..5d6c178 100644 (file)
@@ -8,8 +8,8 @@
 #include "precomp.h"
 
 
 #include "precomp.h"
 
 
-// Global Variables
-RTL_GENERIC_TABLE PrintProcessorTable;
+// Local Variables
+static LIST_ENTRY _PrintProcessorList;
 
 /**
  * @name _OpenEnvironment
 
 /**
  * @name _OpenEnvironment
@@ -24,18 +24,16 @@ RTL_GENERIC_TABLE PrintProcessorTable;
  * You can use it for further tasks and have to close it with RegCloseKey.
  *
  * @return
  * You can use it for further tasks and have to close it with RegCloseKey.
  *
  * @return
- * TRUE if the environment is valid and a registry key was opened, FALSE otherwise.
- * In case of failure, Last Error will be set to ERROR_INVALID_ENVIRONMENT.
+ * A Windows Error Code indicating success or failure.
  */
  */
-static BOOL
+static DWORD
 _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
 {
     const WCHAR wszEnvironmentsKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\";
 _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
 {
     const WCHAR wszEnvironmentsKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\";
-    const DWORD cchEnvironmentsKey = sizeof(wszEnvironmentsKey) / sizeof(WCHAR) - 1;
+    const DWORD cchEnvironmentsKey = _countof(wszEnvironmentsKey) - 1;
 
 
-    BOOL bReturnValue = FALSE;
     DWORD cchEnvironment;
     DWORD cchEnvironment;
-    LONG lStatus;
+    DWORD dwErrorCode;
     PWSTR pwszEnvironmentKey = NULL;
 
     // Use the current environment if none was supplied.
     PWSTR pwszEnvironmentKey = NULL;
 
     // Use the current environment if none was supplied.
@@ -44,10 +42,10 @@ _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
 
     // Construct the registry key of the demanded environment.
     cchEnvironment = wcslen(pEnvironment);
 
     // Construct the registry key of the demanded environment.
     cchEnvironment = wcslen(pEnvironment);
-    pwszEnvironmentKey = HeapAlloc(hProcessHeap, 0, (cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
+    pwszEnvironmentKey = DllAllocSplMem((cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
     if (!pwszEnvironmentKey)
     {
     if (!pwszEnvironmentKey)
     {
-        ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+        ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
@@ -55,137 +53,114 @@ _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
     CopyMemory(&pwszEnvironmentKey[cchEnvironmentsKey], pEnvironment, (cchEnvironment + 1) * sizeof(WCHAR));
 
     // Open the registry key.
     CopyMemory(&pwszEnvironmentKey[cchEnvironmentsKey], pEnvironment, (cchEnvironment + 1) * sizeof(WCHAR));
 
     // Open the registry key.
-    lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszEnvironmentKey, 0, KEY_READ, hKey);
-    if (lStatus == ERROR_FILE_NOT_FOUND)
+    dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszEnvironmentKey, 0, KEY_READ, hKey);
+    if (dwErrorCode == ERROR_FILE_NOT_FOUND)
     {
     {
-        SetLastError(ERROR_INVALID_ENVIRONMENT);
+        dwErrorCode = ERROR_INVALID_ENVIRONMENT;
         goto Cleanup;
     }
         goto Cleanup;
     }
-    else if (lStatus != ERROR_SUCCESS)
+    else if (dwErrorCode != ERROR_SUCCESS)
     {
     {
-        ERR("RegOpenKeyExW failed with status %ld!\n", lStatus);
+        ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
-    bReturnValue = TRUE;
-
 Cleanup:
     if (pwszEnvironmentKey)
 Cleanup:
     if (pwszEnvironmentKey)
-        HeapFree(hProcessHeap, 0, pwszEnvironmentKey);
+        DllFreeSplMem(pwszEnvironmentKey);
 
 
-    return bReturnValue;
+    return dwErrorCode;
 }
 
 }
 
-/**
- * @name _PrinterTableCompareRoutine
- *
- * RTL_GENERIC_COMPARE_ROUTINE for the Print Processor Table.
- * Does a case-insensitive comparison, because e.g. LocalEnumPrintProcessorDatatypes doesn't match the case when looking for Print Processors.
- */
-static RTL_GENERIC_COMPARE_RESULTS NTAPI
-_PrintProcessorTableCompareRoutine(PRTL_GENERIC_TABLE Table, PVOID FirstStruct, PVOID SecondStruct)
+BOOL
+FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
 {
 {
-    PLOCAL_PRINT_PROCESSOR A = (PLOCAL_PRINT_PROCESSOR)FirstStruct;
-    PLOCAL_PRINT_PROCESSOR B = (PLOCAL_PRINT_PROCESSOR)SecondStruct;
+    DWORD i;
+    PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1;
 
 
-    int iResult = wcsicmp(A->pwszName, B->pwszName);
+    for (i = 0; i < pPrintProcessor->dwDatatypeCount; i++)
+    {
+        if (wcsicmp(pCurrentDatatype->pName, pwszDatatype) == 0)
+            return TRUE;
 
 
-    if (iResult < 0)
-        return GenericLessThan;
-    else if (iResult > 0)
-        return GenericGreaterThan;
-    else
-        return GenericEqual;
+        ++pCurrentDatatype;
+    }
+
+    return FALSE;
 }
 
 }
 
-/**
- * @name _DatatypeTableCompareRoutine
- *
- * RTL_GENERIC_COMPARE_ROUTINE for the Datatype Table.
- * Does a case-insensitive comparison, because e.g. LocalOpenPrinter doesn't match the case when looking for Datatypes.
- */
-static RTL_GENERIC_COMPARE_RESULTS NTAPI
-_DatatypeTableCompareRoutine(PRTL_GENERIC_TABLE Table, PVOID FirstStruct, PVOID SecondStruct)
+PLOCAL_PRINT_PROCESSOR
+FindPrintProcessor(PCWSTR pwszName)
 {
 {
-    PWSTR A = (PWSTR)FirstStruct;
-    PWSTR B = (PWSTR)SecondStruct;
+    PLIST_ENTRY pEntry;
+    PLOCAL_PRINT_PROCESSOR pPrintProcessor;
 
 
-    int iResult = wcsicmp(A, B);
+    for (pEntry = _PrintProcessorList.Flink; pEntry != &_PrintProcessorList; pEntry = pEntry->Flink)
+    {
+        pPrintProcessor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_PROCESSOR, Entry);
 
 
-    if (iResult < 0)
-        return GenericLessThan;
-    else if (iResult > 0)
-        return GenericGreaterThan;
-    else
-        return GenericEqual;
+        if (wcsicmp(pPrintProcessor->pwszName, pwszName) == 0)
+            return pPrintProcessor;
+    }
+
+    return NULL;
 }
 
 /**
 }
 
 /**
- * @name InitializePrintProcessorTable
+ * @name InitializePrintProcessorList
  *
  *
- * Initializes a RTL_GENERIC_TABLE of locally available Print Processors.
- * The table is searchable by name and returns pointers to the functions of the loaded Print Processor DLL.
+ * Initializes a singly linked list of locally available Print Processors.
  */
  */
-void
-InitializePrintProcessorTable()
+BOOL
+InitializePrintProcessorList()
 {
     DWORD cbDatatypes;
     DWORD cbFileName;
     DWORD cchPrintProcessorPath;
     DWORD cchMaxSubKey;
     DWORD cchPrintProcessorName;
 {
     DWORD cbDatatypes;
     DWORD cbFileName;
     DWORD cchPrintProcessorPath;
     DWORD cchMaxSubKey;
     DWORD cchPrintProcessorName;
-    DWORD dwDatatypes;
+    DWORD dwErrorCode;
     DWORD dwSubKeys;
     DWORD i;
     DWORD dwSubKeys;
     DWORD i;
-    DWORD j;
     HINSTANCE hinstPrintProcessor;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
     HKEY hSubSubKey = NULL;
     HINSTANCE hinstPrintProcessor;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
     HKEY hSubSubKey = NULL;
-    LONG lStatus;
-    PDATATYPES_INFO_1W pDatatypesInfo1 = NULL;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
-    PWSTR pwszDatatype = NULL;
-    PWSTR pwszPrintProcessorName = NULL;
     WCHAR wszFileName[MAX_PATH];
     WCHAR wszPrintProcessorPath[MAX_PATH];
 
     WCHAR wszFileName[MAX_PATH];
     WCHAR wszPrintProcessorPath[MAX_PATH];
 
-    // Initialize an empty table for our Print Processors.
-    // We will search it by Print Processor name.
-    RtlInitializeGenericTable(&PrintProcessorTable, _PrintProcessorTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL);
+    // Initialize an empty list for our Print Processors.
+    InitializeListHead(&_PrintProcessorList);
     
     // Prepare the path to the Print Processor directory.
     if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
     
     // Prepare the path to the Print Processor directory.
     if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
+    {
+        dwErrorCode = GetLastError();
         goto Cleanup;
         goto Cleanup;
+    }
 
     cchPrintProcessorPath /= sizeof(WCHAR);
     wszPrintProcessorPath[cchPrintProcessorPath++] = L'\\';
 
     // Open the environment registry key.
 
     cchPrintProcessorPath /= sizeof(WCHAR);
     wszPrintProcessorPath[cchPrintProcessorPath++] = L'\\';
 
     // Open the environment registry key.
-    if (!_OpenEnvironment(NULL, &hKey))
+    dwErrorCode = _OpenEnvironment(NULL, &hKey);
+    if (dwErrorCode != ERROR_SUCCESS)
         goto Cleanup;
 
     // Open the "Print Processors" subkey.
         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.
         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 = HeapAlloc(hProcessHeap, 0, (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("HeapAlloc failed with error %lu!\n", GetLastError());
+        ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
@@ -202,48 +177,63 @@ InitializePrintProcessorTable()
         if (pPrintProcessor)
         {
             if (pPrintProcessor->pwszName)
         if (pPrintProcessor)
         {
             if (pPrintProcessor->pwszName)
-                HeapFree(hProcessHeap, 0, pPrintProcessor->pwszName);
+                DllFreeSplStr(pPrintProcessor->pwszName);
+
+            if (pPrintProcessor->pDatatypesInfo1)
+                DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
 
 
-            HeapFree(hProcessHeap, 0, pPrintProcessor);
+            DllFreeSplMem(pPrintProcessor);
             pPrintProcessor = NULL;
         }
 
             pPrintProcessor = NULL;
         }
 
-        if (pDatatypesInfo1)
+        // Create a new LOCAL_PRINT_PROCESSOR structure for it.
+        pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
+        if (!pPrintProcessor)
         {
         {
-            HeapFree(hProcessHeap, 0, pDatatypesInfo1);
-            pDatatypesInfo1 = NULL;
+            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.
         }
 
         // 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.
             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);
             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)
         {
             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;
         }
 
             continue;
         }
 
@@ -252,16 +242,12 @@ InitializePrintProcessorTable()
 
         // Try to load it.
         hinstPrintProcessor = LoadLibraryW(wszPrintProcessorPath);
 
         // 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;
         }
 
         {
             ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
             continue;
         }
 
-        // Create a new LOCAL_PRINT_PROCESSOR structure for it.
-        pPrintProcessor = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_PRINT_PROCESSOR));
-        pPrintProcessor->pwszName = DuplicateStringW(pwszPrintProcessorName);
-
         // Get and verify all its function pointers.
         pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
         if (!pPrintProcessor->pfnClosePrintProcessor)
         // Get and verify all its function pointers.
         pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
         if (!pPrintProcessor->pfnClosePrintProcessor)
@@ -306,74 +292,55 @@ InitializePrintProcessorTable()
         }
 
         // Get all supported datatypes.
         }
 
         // Get all supported datatypes.
-        pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &dwDatatypes);
-        pDatatypesInfo1 = HeapAlloc(hProcessHeap, 0, cbDatatypes);
-        if (!pDatatypesInfo1)
+        pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &pPrintProcessor->dwDatatypeCount);
+        pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
+        if (!pPrintProcessor->pDatatypesInfo1)
         {
         {
-            ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
             goto Cleanup;
         }
 
             goto Cleanup;
         }
 
-        if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, (PBYTE)pDatatypesInfo1, cbDatatypes, &cbDatatypes, &dwDatatypes))
+        if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, (PBYTE)pPrintProcessor->pDatatypesInfo1, cbDatatypes, &cbDatatypes, &pPrintProcessor->dwDatatypeCount))
         {
             ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
             continue;
         }
 
         {
             ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
             continue;
         }
 
-        // Add the supported datatypes to the datatype table.
-        RtlInitializeGenericTable(&pPrintProcessor->DatatypeTable, _DatatypeTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL);
-
-        for (j = 0; j < dwDatatypes; j++)
-        {
-            pwszDatatype = DuplicateStringW(pDatatypesInfo1->pName);
-
-            if (!RtlInsertElementGenericTable(&pPrintProcessor->DatatypeTable, pDatatypesInfo1->pName, sizeof(PWSTR), NULL))
-            {
-                ERR("RtlInsertElementGenericTable failed for iteration %lu with error %lu!\n", j, GetLastError());
-                goto Cleanup;
-            }
-
-            ++pDatatypesInfo1;
-        }
-
-        // Add the Print Processor to the table.
-        if (!RtlInsertElementGenericTable(&PrintProcessorTable, pPrintProcessor, sizeof(LOCAL_PRINT_PROCESSOR), NULL))
-        {
-            ERR("RtlInsertElementGenericTable failed for iteration %lu with error %lu!\n", i, GetLastError());
-            goto Cleanup;
-        }
+        // Add the Print Processor to the list.
+        InsertTailList(&_PrintProcessorList, &pPrintProcessor->Entry);
 
         // Don't let the cleanup routines free this.
 
         // Don't let the cleanup routines free this.
-        pwszDatatype = NULL;
         pPrintProcessor = NULL;
     }
 
         pPrintProcessor = NULL;
     }
 
-Cleanup:
-    if (pwszDatatype)
-        HeapFree(hProcessHeap, 0, pwszDatatype);
+    dwErrorCode = ERROR_SUCCESS;
 
 
-    if (pDatatypesInfo1)
-        HeapFree(hProcessHeap, 0, pDatatypesInfo1);
+Cleanup:
+    // Inside the loop
+    if (hSubSubKey)
+        RegCloseKey(hSubSubKey);
 
     if (pPrintProcessor)
     {
         if (pPrintProcessor->pwszName)
 
     if (pPrintProcessor)
     {
         if (pPrintProcessor->pwszName)
-            HeapFree(hProcessHeap, 0, pPrintProcessor->pwszName);
-
-        HeapFree(hProcessHeap, 0, pPrintProcessor);
-    }
+            DllFreeSplStr(pPrintProcessor->pwszName);
 
 
-    if (pwszPrintProcessorName)
-        HeapFree(hProcessHeap, 0, pwszPrintProcessorName);
+        if (pPrintProcessor->pDatatypesInfo1)
+            DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
 
 
-    if (hSubSubKey)
-        RegCloseKey(hSubSubKey);
+        DllFreeSplMem(pPrintProcessor);
+    }
 
 
+    // Outside the loop
     if (hSubKey)
         RegCloseKey(hSubKey);
 
     if (hKey)
         RegCloseKey(hKey);
     if (hSubKey)
         RegCloseKey(hSubKey);
 
     if (hKey)
         RegCloseKey(hKey);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 /**
 }
 
 /**
@@ -413,25 +380,33 @@ Cleanup:
 BOOL WINAPI
 LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
 BOOL WINAPI
 LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
+    DWORD dwErrorCode;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor;
 
     // Sanity checks
     if (Level != 1)
     {
     PLOCAL_PRINT_PROCESSOR pPrintProcessor;
 
     // Sanity checks
     if (Level != 1)
     {
-        SetLastError(ERROR_INVALID_LEVEL);
-        return FALSE;
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
     }
 
     // Try to find the Print Processor.
     }
 
     // Try to find the Print Processor.
-    pPrintProcessor = RtlLookupElementGenericTable(&PrintProcessorTable, pPrintProcessorName);
+    pPrintProcessor = FindPrintProcessor(pPrintProcessorName);
     if (!pPrintProcessor)
     {
     if (!pPrintProcessor)
     {
-        SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
-        return FALSE;
+        dwErrorCode = ERROR_UNKNOWN_PRINTPROCESSOR;
+        goto Cleanup;
     }
 
     // Call its EnumPrintProcessorDatatypesW function.
     }
 
     // Call its EnumPrintProcessorDatatypesW function.
-    return pPrintProcessor->pfnEnumPrintProcessorDatatypesW(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
+    if (pPrintProcessor->pfnEnumPrintProcessorDatatypesW(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned))
+        dwErrorCode = ERROR_SUCCESS;
+    else
+        dwErrorCode = GetLastError();
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 /**
 }
 
 /**
@@ -472,73 +447,75 @@ LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD
 BOOL WINAPI
 LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
 BOOL WINAPI
 LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
-    BOOL bReturnValue = FALSE;
     DWORD cchMaxSubKey;
     DWORD cchPrintProcessor;
     DWORD cchMaxSubKey;
     DWORD cchPrintProcessor;
+    DWORD dwErrorCode;
+    DWORD dwPrintProcessorCount;
     DWORD i;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
     DWORD i;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
-    LONG lStatus;
     PBYTE pCurrentOutputPrintProcessor;
     PBYTE pCurrentOutputPrintProcessorInfo;
     PRINTPROCESSOR_INFO_1W PrintProcessorInfo1;
     PBYTE pCurrentOutputPrintProcessor;
     PBYTE pCurrentOutputPrintProcessorInfo;
     PRINTPROCESSOR_INFO_1W PrintProcessorInfo1;
-    PWSTR pwszEnvironmentKey = NULL;
     PWSTR pwszTemp = NULL;
 
     // Sanity checks
     if (Level != 1)
     {
     PWSTR pwszTemp = NULL;
 
     // Sanity checks
     if (Level != 1)
     {
-        SetLastError(ERROR_INVALID_LEVEL);
+        dwErrorCode = ERROR_INVALID_LEVEL;
         goto Cleanup;
     }
 
     if (!pcbNeeded || !pcReturned)
     {
         goto Cleanup;
     }
 
     if (!pcbNeeded || !pcReturned)
     {
-        // This error must be caught by RPC and returned as RPC_X_NULL_REF_POINTER.
-        ERR("pcbNeeded or pcReturned is NULL!\n");
+        // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
+        dwErrorCode = ERROR_INVALID_PARAMETER;
         goto Cleanup;
     }
 
     // Verify pEnvironment and open its registry key.
         goto Cleanup;
     }
 
     // Verify pEnvironment and open its registry key.
-    if (!_OpenEnvironment(pEnvironment, &hKey))
+    // We use the registry and not the PrintProcessorList here, because the caller may request information about a different environment.
+    dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
+    if (dwErrorCode != ERROR_SUCCESS)
         goto Cleanup;
 
     // Open the "Print Processors" subkey.
         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.
         goto Cleanup;
     }
 
     // Get the number of Print Processors and maximum sub key length.
-    lStatus = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, pcReturned, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
-    if (lStatus != ERROR_SUCCESS)
+    dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwPrintProcessorCount, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (dwErrorCode != ERROR_SUCCESS)
     {
     {
-        ERR("RegQueryInfoKeyW failed with status %ld!\n", lStatus);
+        ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
         goto Cleanup;
     }
 
     // Allocate a temporary buffer to let RegEnumKeyExW succeed.
         goto Cleanup;
     }
 
     // Allocate a temporary buffer to let RegEnumKeyExW succeed.
-    pwszTemp = HeapAlloc(hProcessHeap, 0, (cchMaxSubKey + 1) * sizeof(WCHAR));
+    pwszTemp = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
     if (!pwszTemp)
     {
     if (!pwszTemp)
     {
-        ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+        dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+        ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
         goto Cleanup;
     }
 
     // Determine the required size of the output buffer.
     *pcbNeeded = 0;
 
         goto Cleanup;
     }
 
     // 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.
     {
         // 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;
-        lStatus = RegEnumKeyExW(hSubKey, i, pwszTemp, &cchPrintProcessor, NULL, NULL, NULL, NULL);
-        if (lStatus != ERROR_SUCCESS)
+        cchPrintProcessor = cchMaxSubKey + 1;
+        dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pwszTemp, &cchPrintProcessor, NULL, NULL, NULL, NULL);
+        if (dwErrorCode != ERROR_SUCCESS)
         {
         {
-            ERR("RegEnumKeyExW failed with status %ld!\n", lStatus);
+            ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode);
             goto Cleanup;
         }
 
             goto Cleanup;
         }
 
@@ -548,25 +525,25 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
     // Check if the supplied buffer is large enough.
     if (cbBuf < *pcbNeeded)
     {
     // Check if the supplied buffer is large enough.
     if (cbBuf < *pcbNeeded)
     {
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
         goto Cleanup;
     }
 
     // Put the Print Processor strings right after the last PRINTPROCESSOR_INFO_1W structure.
     pCurrentOutputPrintProcessorInfo = pPrintProcessorInfo;
         goto Cleanup;
     }
 
     // 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.
 
     // 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.
     {
         // 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.
 
         // Copy the Print Processor name.
-        lStatus = RegEnumKeyExW(hSubKey, i, (PWSTR)pCurrentOutputPrintProcessor, &cchPrintProcessor, NULL, NULL, NULL, NULL);
-        if (lStatus != ERROR_SUCCESS)
+        dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, (PWSTR)pCurrentOutputPrintProcessor, &cchPrintProcessor, NULL, NULL, NULL, NULL);
+        if (dwErrorCode != ERROR_SUCCESS)
         {
         {
-            ERR("RegEnumKeyExW failed with status %ld!\n", lStatus);
+            ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode);
             goto Cleanup;
         }
 
             goto Cleanup;
         }
 
@@ -580,15 +557,12 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
     }
 
     // We've finished successfully!
     }
 
     // We've finished successfully!
-    SetLastError(ERROR_SUCCESS);
-    bReturnValue = TRUE;
+    *pcReturned = dwPrintProcessorCount;
+    dwErrorCode = ERROR_SUCCESS;
 
 Cleanup:
     if (pwszTemp)
 
 Cleanup:
     if (pwszTemp)
-        HeapFree(hProcessHeap, 0, pwszTemp);
-
-    if (pwszEnvironmentKey)
-        HeapFree(hProcessHeap, 0, pwszEnvironmentKey);
+        DllFreeSplMem(pwszTemp);
 
     if (hSubKey)
         RegCloseKey(hSubKey);
 
     if (hSubKey)
         RegCloseKey(hSubKey);
@@ -596,7 +570,8 @@ Cleanup:
     if (hKey)
         RegCloseKey(hKey);
 
     if (hKey)
         RegCloseKey(hKey);
 
-    return bReturnValue;
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 /**
 }
 
 /**
@@ -634,37 +609,36 @@ BOOL WINAPI
 LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded)
 {
     const WCHAR wszPath[] = L"\\PRTPROCS\\";
 LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded)
 {
     const WCHAR wszPath[] = L"\\PRTPROCS\\";
-    const DWORD cchPath = sizeof(wszPath) / sizeof(WCHAR) - 1;
+    const DWORD cchPath = _countof(wszPath) - 1;
 
 
-    BOOL bReturnValue = FALSE;
     DWORD cbDataWritten;
     DWORD cbDataWritten;
+    DWORD dwErrorCode;
     HKEY hKey = NULL;
     HKEY hKey = NULL;
-    LONG lStatus;
-    PWSTR pwszEnvironmentKey = NULL;
 
     // Sanity checks
     if (Level != 1)
     {
 
     // Sanity checks
     if (Level != 1)
     {
-        SetLastError(ERROR_INVALID_LEVEL);
+        dwErrorCode = ERROR_INVALID_LEVEL;
         goto Cleanup;
     }
 
     if (!pcbNeeded)
     {
         goto Cleanup;
     }
 
     if (!pcbNeeded)
     {
-        // This error must be caught by RPC and returned as RPC_X_NULL_REF_POINTER.
-        ERR("pcbNeeded is NULL!\n");
+        // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
+        dwErrorCode = ERROR_INVALID_PARAMETER;
         goto Cleanup;
     }
 
     // Verify pEnvironment and open its registry key.
         goto Cleanup;
     }
 
     // Verify pEnvironment and open its registry key.
-    if (!_OpenEnvironment(pEnvironment, &hKey))
+    dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
+    if (dwErrorCode != ERROR_SUCCESS)
         goto Cleanup;
 
     // Determine the size of the required buffer.
         goto Cleanup;
 
     // Determine the size of the required buffer.
-    lStatus = RegQueryValueExW(hKey, L"Directory", NULL, NULL, NULL, pcbNeeded);
-    if (lStatus != ERROR_SUCCESS)
+    dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, NULL, pcbNeeded);
+    if (dwErrorCode != ERROR_SUCCESS)
     {
     {
-        ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
+        ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
@@ -674,7 +648,7 @@ LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
     // Is the supplied buffer large enough?
     if (cbBuf < *pcbNeeded)
     {
     // Is the supplied buffer large enough?
     if (cbBuf < *pcbNeeded)
     {
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
@@ -683,23 +657,20 @@ LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
     CopyMemory(&pPrintProcessorInfo[cchSpoolDirectory], wszPath, cchPath * sizeof(WCHAR));
 
     // Get the directory name from the registry.
     CopyMemory(&pPrintProcessorInfo[cchSpoolDirectory], wszPath, cchPath * sizeof(WCHAR));
 
     // Get the directory name from the registry.
-    lStatus = RegQueryValueExW(hKey, L"Directory", NULL, NULL, &pPrintProcessorInfo[cchSpoolDirectory + cchPath], &cbDataWritten);
-    if (lStatus != ERROR_SUCCESS)
+    dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, &pPrintProcessorInfo[cchSpoolDirectory + cchPath], &cbDataWritten);
+    if (dwErrorCode != ERROR_SUCCESS)
     {
     {
-        ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
+        ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
         goto Cleanup;
     }
 
     // We've finished successfully!
         goto Cleanup;
     }
 
     // We've finished successfully!
-    SetLastError(ERROR_SUCCESS);
-    bReturnValue = TRUE;
+    dwErrorCode = ERROR_SUCCESS;
 
 Cleanup:
 
 Cleanup:
-    if (pwszEnvironmentKey)
-        HeapFree(hProcessHeap, 0, pwszEnvironmentKey);
-
     if (hKey)
         RegCloseKey(hKey);
 
     if (hKey)
         RegCloseKey(hKey);
 
-    return bReturnValue;
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 }