[LOCALSPL]
authorColin Finck <colin@reactos.org>
Tue, 7 Jul 2015 17:06:48 +0000 (17:06 +0000)
committerColin Finck <colin@reactos.org>
Tue, 7 Jul 2015 17:06:48 +0000 (17:06 +0000)
- Initialize all Print Monitors on startup and keep a list of them.
- Implement LocalEnumMonitors and LocalEnumPorts.
- Check the result of the initialization functions.

[SPOOLSS]
- Implement support for multiple Print Providers.
  Initialize them on startup and keep a list here as well.
- Implement all functions that had simple stubs in the C code. This still needs to be done for the remaining functions stubbed in the .spec file.
  But generally spoken, this always boils down to 3 cases:
    * Forward the call to the Local Spooler (for general functions like GetPrintProcessorDirectory).
    * Forward the call to the Print Provider we used for OpenPrinter (for functions like SetJob).
    * Forward the call to all Print Providers and collect the results (for functions like EnumPrinters).

svn path=/branches/colins-printing-for-freedom/; revision=68375

18 files changed:
reactos/win32ss/printing/base/spoolss/CMakeLists.txt
reactos/win32ss/printing/base/spoolss/jobs.c
reactos/win32ss/printing/base/spoolss/main.c
reactos/win32ss/printing/base/spoolss/memory.c
reactos/win32ss/printing/base/spoolss/monitors.c [new file with mode: 0644]
reactos/win32ss/printing/base/spoolss/ports.c
reactos/win32ss/printing/base/spoolss/precomp.h
reactos/win32ss/printing/base/spoolss/printers.c
reactos/win32ss/printing/base/spoolss/printprocessors.c
reactos/win32ss/printing/base/spoolss/spoolss.spec
reactos/win32ss/printing/providers/localspl/CMakeLists.txt
reactos/win32ss/printing/providers/localspl/jobs.c
reactos/win32ss/printing/providers/localspl/main.c
reactos/win32ss/printing/providers/localspl/monitors.c [new file with mode: 0644]
reactos/win32ss/printing/providers/localspl/ports.c [new file with mode: 0644]
reactos/win32ss/printing/providers/localspl/precomp.h
reactos/win32ss/printing/providers/localspl/printers.c
reactos/win32ss/printing/providers/localspl/printprocessors.c

index fe1d628..67a7e1f 100644 (file)
@@ -6,6 +6,7 @@ list(APPEND SOURCE
     jobs.c
     main.c
     memory.c
     jobs.c
     main.c
     memory.c
+    monitors.c
     ports.c
     precomp.h
     printers.c
     ports.c
     precomp.h
     printers.c
index 5d85a69..d3e5eb7 100644 (file)
@@ -8,31 +8,76 @@
 #include "precomp.h"
 
 BOOL WINAPI
 #include "precomp.h"
 
 BOOL WINAPI
-AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
+AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
 {
 {
-    return LocalSplFuncs.fpAddJob(hPrinter, Level, pData, cbBuf, pcbNeeded);
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpAddJob(pHandle->hPrinter, Level, pData, cbBuf, pcbNeeded);
 }
 
 BOOL WINAPI
 EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
 }
 
 BOOL WINAPI
 EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
-    return LocalSplFuncs.fpEnumJobs(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpEnumJobs(pHandle->hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded)
+GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
 {
 {
-    return LocalSplFuncs.fpGetJob(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpGetJob(pHandle->hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
 }
 
 BOOL WINAPI
 ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
 {
 }
 
 BOOL WINAPI
 ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
 {
-    return LocalSplFuncs.fpScheduleJob(hPrinter, dwJobID);
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpScheduleJob(pHandle->hPrinter, dwJobID);
 }
 
 BOOL WINAPI
 SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
 {
 }
 
 BOOL WINAPI
 SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
 {
-    return LocalSplFuncs.fpSetJob(hPrinter, JobId, Level, pJobInfo, Command);
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpSetJob(pHandle->hPrinter, JobId, Level, pJobInfo, Command);
 }
 }
index bc9963b..673186c 100644 (file)
 
 #include "precomp.h"
 
 
 #include "precomp.h"
 
+// Global Variables
 HANDLE hProcessHeap;
 HANDLE hProcessHeap;
-PRINTPROVIDOR LocalSplFuncs;
+LIST_ENTRY PrintProviderList;
 
 
 
 
-BOOL WINAPI
-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+static DWORD
+_AddPrintProviderToList(PCWSTR pwszFileName)
 {
 {
-    switch (fdwReason)
+    DWORD dwErrorCode;
+    HINSTANCE hinstPrintProvider;
+    PInitializePrintProvidor pfnInitializePrintProvidor;
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider = NULL;
+
+    // Try to load it.
+    hinstPrintProvider = LoadLibraryW(pwszFileName);
+    if (!hinstPrintProvider)
     {
     {
-        case DLL_PROCESS_ATTACH:
-            DisableThreadLibraryCalls(hinstDLL);
-            hProcessHeap = GetProcessHeap();
-            break;
+        dwErrorCode = GetLastError();
+        ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
+        goto Cleanup;
     }
 
     }
 
-    return TRUE;
+    // Get the initialization routine.
+    pfnInitializePrintProvidor = (PInitializePrintProvidor)GetProcAddress(hinstPrintProvider, "InitializePrintProvidor");
+    if (!pfnInitializePrintProvidor)
+    {
+        dwErrorCode = GetLastError();
+        ERR("GetProcAddress failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Create a new SPOOLSS_PRINT_PROVIDER structure for it.
+    pPrintProvider = DllAllocSplMem(sizeof(SPOOLSS_PRINT_PROVIDER));
+    if (!pPrintProvider)
+    {
+        dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+        ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Call the Print Provider initialization function.
+    if (!pfnInitializePrintProvidor(&pPrintProvider->PrintProvider, sizeof(PRINTPROVIDOR), NULL))
+    {
+        dwErrorCode = GetLastError();
+        ERR("InitializePrintProvidor failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Add this Print Provider to the list.
+    InsertTailList(&PrintProviderList, &pPrintProvider->Entry);
+
+    // Don't let the cleanup routine free this.
+    pPrintProvider = NULL;
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    if (pPrintProvider)
+        DllFreeSplMem(pPrintProvider);
+
+    return dwErrorCode;
 }
 
 }
 
-BOOL WINAPI
-InitializeRouter(HANDLE SpoolerStatusHandle)
+static BOOL
+_InitializePrintProviderList()
 {
 {
-    HINSTANCE hinstLocalSpl;
-    PInitializePrintProvidor pfnInitializePrintProvidor;
+    DWORD cbFileName;
+    DWORD cchMaxSubKey;
+    DWORD cchPrintProviderName;
+    DWORD dwErrorCode;
+    DWORD dwSubKeys;
+    DWORD i;
+    HKEY hKey = NULL;
+    HKEY hSubKey = NULL;
+    PWSTR pwszPrintProviderName = NULL;
+    WCHAR wszFileName[MAX_PATH];
+
+    // Initialize an empty list for our Print Providers.
+    InitializeListHead(&PrintProviderList);
+
+    // First add the Local Spooler.
+    // This one must exist and must be the first one in the list.
+    dwErrorCode = _AddPrintProviderToList(L"localspl");
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+        ERR("The Local Spooler could not be loaded!\n");
+        goto Cleanup;
+    }
 
 
-    // Only initialize localspl.dll for now.
-    // This function should later look for all available print providers in the registry and initialize all of them.
-    hinstLocalSpl = LoadLibraryW(L"localspl");
-    if (!hinstLocalSpl)
+    // Now add additional Print Providers from the registry.
+    // First of all, open the key containing print providers.
+    dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers", 0, KEY_READ, &hKey);
+    if (dwErrorCode != ERROR_SUCCESS)
     {
     {
-        ERR("LoadLibraryW for localspl failed with error %lu!\n", GetLastError());
-        return FALSE;
+        ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
     }
 
     }
 
-    pfnInitializePrintProvidor = (PInitializePrintProvidor)GetProcAddress(hinstLocalSpl, "InitializePrintProvidor");
-    if (!pfnInitializePrintProvidor)
+    // Get the number of Print Providers and maximum sub key length.
+    dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (dwErrorCode != ERROR_SUCCESS)
     {
     {
-        ERR("GetProcAddress failed with error %lu!\n", GetLastError());
-        return FALSE;
+        ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
     }
 
     }
 
-    if (!pfnInitializePrintProvidor(&LocalSplFuncs, sizeof(PRINTPROVIDOR), NULL))
+    // Allocate a temporary buffer for the Print Provider names.
+    pwszPrintProviderName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+    if (!pwszPrintProviderName)
     {
     {
-        ERR("InitializePrintProvidor failed for localspl with error %lu!\n", GetLastError());
-        return FALSE;
+        dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+        ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Loop through all available Print Providers.
+    for (i = 0; i < dwSubKeys; i++)
+    {
+        // Cleanup tasks from the previous run
+        if (hSubKey)
+        {
+            RegCloseKey(hSubKey);
+            hSubKey = NULL;
+        }
+
+        // Get the name of this Print Provider.
+        cchPrintProviderName = cchMaxSubKey + 1;
+        dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pwszPrintProviderName, &cchPrintProviderName, NULL, NULL, NULL, NULL);
+        if (dwErrorCode != ERROR_SUCCESS)
+        {
+            ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
+            continue;
+        }
+
+        // Open this Print Provider's registry key.
+        dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pwszPrintProviderName, 0, KEY_READ, &hSubKey);
+        if (dwErrorCode != ERROR_SUCCESS)
+        {
+            ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pwszPrintProviderName, dwErrorCode);
+            continue;
+        }
+
+        // Get the file name of the Print Provider.
+        cbFileName = MAX_PATH * sizeof(WCHAR);
+        dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
+        if (dwErrorCode != ERROR_SUCCESS)
+        {
+            ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+            continue;
+        }
+
+        // Load and add it to the list.
+        dwErrorCode = _AddPrintProviderToList(wszFileName);
+        if (dwErrorCode != ERROR_SUCCESS)
+            continue;
+    }
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    // Inside the loop
+    if (hSubKey)
+        RegCloseKey(hSubKey);
+
+    // Outside the loop
+    if (pwszPrintProviderName)
+        DllFreeSplMem(pwszPrintProviderName);
+
+    if (hKey)
+        RegCloseKey(hKey);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hinstDLL);
+                       hProcessHeap = GetProcessHeap();
+            break;
     }
 
     return TRUE;
 }
 
     }
 
     return TRUE;
 }
 
+BOOL WINAPI
+InitializeRouter(HANDLE SpoolerStatusHandle)
+{
+    return _InitializePrintProviderList();
+}
+
 BOOL WINAPI
 SplInitializeWinSpoolDrv(PVOID* pTable)
 {
 BOOL WINAPI
 SplInitializeWinSpoolDrv(PVOID* pTable)
 {
index d16a8a3..96a7fd1 100644 (file)
@@ -9,17 +9,17 @@
 
 
 /**
 
 
 /**
-* @name AllocSplStr
-*
-* Allocates memory for a Unicode string and copies the input string into it.
-* Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr.
-*
-* @param pwszInput
-* The input string to copy
-*
-* @return
-* Pointer to the copied string or NULL if no memory could be allocated.
-*/
+ * @name AllocSplStr
+ *
+ * Allocates memory for a Unicode string and copies the input string into it.
+ * Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr.
+ *
+ * @param pwszInput
+ * The input string to copy
+ *
+ * @return
+ * Pointer to the copied string or NULL if no memory could be allocated.
+ */
 PWSTR WINAPI
 AllocSplStr(PCWSTR pwszInput)
 {
 PWSTR WINAPI
 AllocSplStr(PCWSTR pwszInput)
 {
diff --git a/reactos/win32ss/printing/base/spoolss/monitors.c b/reactos/win32ss/printing/base/spoolss/monitors.c
new file mode 100644 (file)
index 0000000..1a7a258
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * PROJECT:     ReactOS Spooler Router
+ * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Functions related to Print Monitors
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    BOOL bReturnValue;
+    DWORD cbCallBuffer;
+    DWORD cbNeeded;
+    DWORD dwReturned;
+    PBYTE pCallBuffer;
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+    PLIST_ENTRY pEntry;
+
+    // Sanity checks.
+    if ((cbBuf && !pMonitors) || !pcbNeeded || !pcReturned)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    // Begin counting.
+    *pcbNeeded = 0;
+    *pcReturned = 0;
+
+    // At the beginning, we have the full buffer available.
+    cbCallBuffer = cbBuf;
+    pCallBuffer = pMonitors;
+
+    // Loop through all Print Provider.
+    for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+    {
+        pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+        // Check if this Print Provider provides an EnumMonitors function.
+        if (!pPrintProvider->PrintProvider.fpEnumMonitors)
+            continue;
+
+        // Call the EnumMonitors function of this Print Provider.
+        bReturnValue = pPrintProvider->PrintProvider.fpEnumMonitors(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+        // Add the returned counts to the total values.
+        *pcbNeeded += cbNeeded;
+        *pcReturned += dwReturned;
+
+        // Reduce the available buffer size for the next call without risking an underflow.
+        if (cbNeeded < cbCallBuffer)
+            cbCallBuffer -= cbNeeded;
+        else
+            cbCallBuffer = 0;
+
+        // Advance the buffer if the caller provided it.
+        if (pCallBuffer)
+            pCallBuffer += cbNeeded;
+
+        // Check if we shall not ask other Print Providers.
+        if (bReturnValue == ROUTER_STOP_ROUTING)
+            break;
+    }
+
+    return bReturnValue;
+}
index 6fedbaa..52b0b6c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:     ReactOS Spooler Router
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
 /*
  * PROJECT:     ReactOS Spooler Router
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
- * PURPOSE:     Functions related to ports
+ * PURPOSE:     Functions related to Ports of the Print Monitors
  * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
  */
 
  * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
  */
 
 BOOL WINAPI
 EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
 BOOL WINAPI
 EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
-    return FALSE;
+    BOOL bReturnValue;
+    DWORD cbCallBuffer;
+    DWORD cbNeeded;
+    DWORD dwReturned;
+    PBYTE pCallBuffer;
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+    PLIST_ENTRY pEntry;
+
+    // Sanity checks.
+    if ((cbBuf && !pPorts) || !pcbNeeded || !pcReturned)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    // Begin counting.
+    *pcbNeeded = 0;
+    *pcReturned = 0;
+
+    // At the beginning, we have the full buffer available.
+    cbCallBuffer = cbBuf;
+    pCallBuffer = pPorts;
+
+    // Loop through all Print Provider.
+    for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+    {
+        pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+        // Call the EnumPorts function of this Print Provider.
+        bReturnValue = pPrintProvider->PrintProvider.fpEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+        // Add the returned counts to the total values.
+        *pcbNeeded += cbNeeded;
+        *pcReturned += dwReturned;
+
+        // Reduce the available buffer size for the next call without risking an underflow.
+        if (cbNeeded < cbCallBuffer)
+            cbCallBuffer -= cbNeeded;
+        else
+            cbCallBuffer = 0;
+
+        // Advance the buffer if the caller provided it.
+        if (pCallBuffer)
+            pCallBuffer += cbNeeded;
+
+        // Check if we shall not ask other Print Providers.
+        if (bReturnValue == ROUTER_STOP_ROUTING)
+            break;
+    }
+
+    return bReturnValue;
 }
 }
index 70477bc..b23649c 100644 (file)
 #include <winreg.h>
 #include <winspool.h>
 #include <winsplp.h>
 #include <winreg.h>
 #include <winspool.h>
 #include <winsplp.h>
+#include <ndk/rtlfuncs.h>
 
 #include <spoolss.h>
 
 #include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(spoolss);
 
 
 #include <spoolss.h>
 
 #include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(spoolss);
 
-// Function pointer to InitializePrintProvidor of a provider DLL
+// Function pointers
 typedef BOOL (WINAPI *PInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
 
 typedef BOOL (WINAPI *PInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
 
+// Structures
+/**
+ * Describes a Print Provider.
+ */
+typedef struct _SPOOLSS_PRINT_PROVIDER
+{
+    LIST_ENTRY Entry;
+    PRINTPROVIDOR PrintProvider;
+}
+SPOOLSS_PRINT_PROVIDER, *PSPOOLSS_PRINT_PROVIDER;
+
+/*
+ * Describes a handle returned by OpenPrinterW.
+ * We can't just pass the handle returned by the Print Provider, because spoolss has to remember which Print Provider opened this handle.
+ */
+typedef struct _SPOOLSS_PRINTER_HANDLE
+{
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider;         /** Pointer to the Print Provider that opened this printer. */
+    HANDLE hPrinter;                                /** The handle returned by fpOpenPrinter of the Print Provider and passed to subsequent Print Provider functions. */
+}
+SPOOLSS_PRINTER_HANDLE, *PSPOOLSS_PRINTER_HANDLE;
+
 // main.c
 extern HANDLE hProcessHeap;
 // main.c
 extern HANDLE hProcessHeap;
-extern PRINTPROVIDOR LocalSplFuncs;
+extern LIST_ENTRY PrintProviderList;
 
 #endif
 
 #endif
index f080912..2bbf698 100644 (file)
 BOOL WINAPI
 ClosePrinter(HANDLE hPrinter)
 {
 BOOL WINAPI
 ClosePrinter(HANDLE hPrinter)
 {
-    return FALSE;
+    BOOL bReturnValue;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    // FIXME: Call FindClosePrinterChangeNotification for all created change notifications (according to MSDN).
+
+    // Call CloseHandle of the Print Provider.
+    bReturnValue = pHandle->pPrintProvider->PrintProvider.fpClosePrinter(pHandle->hPrinter);
+
+    // Free our handle information.
+    DllFreeSplMem(pHandle);
+
+    return bReturnValue;
 }
 
 BOOL WINAPI
 EndDocPrinter(HANDLE hPrinter)
 {
 }
 
 BOOL WINAPI
 EndDocPrinter(HANDLE hPrinter)
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpEndDocPrinter(pHandle->hPrinter);
 }
 
 BOOL WINAPI
 EndPagePrinter(HANDLE hPrinter)
 {
 }
 
 BOOL WINAPI
 EndPagePrinter(HANDLE hPrinter)
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpEndPagePrinter(pHandle->hPrinter);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-EnumPrintersW(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
 {
-    return LocalSplFuncs.fpEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    BOOL bReturnValue;
+    DWORD cbCallBuffer;
+    DWORD cbNeeded;
+    DWORD dwReturned;
+    PBYTE pCallBuffer;
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+    PLIST_ENTRY pEntry;
+
+    // Sanity checks.
+    if ((cbBuf && !pPrinterEnum) || !pcbNeeded || !pcReturned)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    // Begin counting.
+    *pcbNeeded = 0;
+    *pcReturned = 0;
+
+    // At the beginning, we have the full buffer available.
+    cbCallBuffer = cbBuf;
+    pCallBuffer = pPrinterEnum;
+
+    // Loop through all Print Provider.
+    for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+    {
+        pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+        // Call the EnumPrinters function of this Print Provider.
+        bReturnValue = pPrintProvider->PrintProvider.fpEnumPrinters(Flags, Name, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+        // Add the returned counts to the total values.
+        *pcbNeeded += cbNeeded;
+        *pcReturned += dwReturned;
+
+        // Reduce the available buffer size for the next call without risking an underflow.
+        if (cbNeeded < cbCallBuffer)
+            cbCallBuffer -= cbNeeded;
+        else
+            cbCallBuffer = 0;
+
+        // Advance the buffer if the caller provided it.
+        if (pCallBuffer)
+            pCallBuffer += cbNeeded;
+    }
+
+    return bReturnValue;
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+GetPrinterDriverW(HANDLE hPrinter, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded)
 {
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
+GetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD cbBuf, PDWORD pcbNeeded)
 {
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
+OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
 {
 {
-    return LocalSplFuncs.fpOpenPrinter(pPrinterName, phPrinter, pDefault);
+    BOOL bReturnValue;
+    HANDLE hPrinter;
+    PLIST_ENTRY pEntry;
+    PSPOOLSS_PRINTER_HANDLE pHandle;
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+
+    // Sanity checks.
+    if (!pPrinterName || !phPrinter)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    // Loop through all Print Providers to find one able to open this Printer.
+    for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+    {
+        pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+        bReturnValue = pPrintProvider->PrintProvider.fpOpenPrinter(pPrinterName, &hPrinter, pDefault);
+        if (bReturnValue == ROUTER_SUCCESS)
+        {
+            // This Print Provider has opened this Printer.
+            // Store this information and return a handle.
+            pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
+            if (!pHandle)
+            {
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+                return FALSE;
+            }
+
+            pHandle->pPrintProvider = pPrintProvider;
+            pHandle->hPrinter = hPrinter;
+            *phPrinter = (HANDLE)pHandle;
+
+            SetLastError(ERROR_SUCCESS);
+            return TRUE;
+        }
+        else if (bReturnValue == ROUTER_STOP_ROUTING)
+        {
+            ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
+            return FALSE;
+        }
+    }
+
+    // We found no Print Provider able to open this Printer.
+    return FALSE;
 }
 
 BOOL WINAPI
 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
 {
 }
 
 BOOL WINAPI
 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
 }
 
 DWORD WINAPI
 }
 
 DWORD WINAPI
-StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
+StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
 {
 {
-    return 0;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpStartDocPrinter(pHandle->hPrinter, Level, pDocInfo);
 }
 
 BOOL WINAPI
 StartPagePrinter(HANDLE hPrinter)
 {
 }
 
 BOOL WINAPI
 StartPagePrinter(HANDLE hPrinter)
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpStartPagePrinter(pHandle->hPrinter);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
+WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
 {
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
 }
 
 BOOL WINAPI
 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
 {
 }
 
 BOOL WINAPI
 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
 {
-    return FALSE;
+    PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hXcv;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return pHandle->pPrintProvider->PrintProvider.fpXcvData(pHandle->hPrinter, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
 }
 }
index 91c1236..643f72f 100644 (file)
@@ -8,19 +8,25 @@
 #include "precomp.h"
 
 BOOL WINAPI
 #include "precomp.h"
 
 BOOL WINAPI
-EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+EnumPrintProcessorDatatypesW(PWSTR pName, PWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
 {
-    return LocalSplFuncs.fpEnumPrintProcessorDatatypes(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
+    // Always call this function on the Local Spooler.
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider = CONTAINING_RECORD(&PrintProviderList.Flink, SPOOLSS_PRINT_PROVIDER, Entry);
+    return pPrintProvider->PrintProvider.fpEnumPrintProcessorDatatypes(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+EnumPrintProcessorsW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
 {
-    return LocalSplFuncs.fpEnumPrintProcessors(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
+    // Always call this function on the Local Spooler.
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider = CONTAINING_RECORD(&PrintProviderList.Flink, SPOOLSS_PRINT_PROVIDER, Entry);
+    return pPrintProvider->PrintProvider.fpEnumPrintProcessors(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
-GetPrintProcessorDirectoryW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+GetPrintProcessorDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
 {
 {
-    return LocalSplFuncs.fpGetPrintProcessorDirectory(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
+    // Always call this function on the Local Spooler.
+    PSPOOLSS_PRINT_PROVIDER pPrintProvider = CONTAINING_RECORD(&PrintProviderList.Flink, SPOOLSS_PRINT_PROVIDER, Entry);
+    return pPrintProvider->PrintProvider.fpGetPrintProcessorDirectory(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
 }
 }
index c4bbac2..49dbc0d 100644 (file)
 @ stdcall EndPagePrinter(long)
 @ stub EnumFormsW
 @ stdcall EnumJobsW(long long long long ptr long ptr ptr)
 @ stdcall EndPagePrinter(long)
 @ stub EnumFormsW
 @ stdcall EnumJobsW(long long long long ptr long ptr ptr)
-@ stub EnumMonitorsW
+@ stdcall EnumMonitorsW(wstr long ptr long ptr ptr)
 @ stub EnumPerMachineConnectionsW
 @ stub EnumPerMachineConnectionsW
-@ stdcall EnumPortsW(ptr long ptr long ptr ptr)
+@ stdcall EnumPortsW(wstr long ptr long ptr ptr)
 @ stub EnumPrinterDataExW
 @ stub EnumPrinterDataW
 @ stub EnumPrinterDriversW
 @ stub EnumPrinterKeyW
 @ stub EnumPrinterDataExW
 @ stub EnumPrinterDataW
 @ stub EnumPrinterDriversW
 @ stub EnumPrinterKeyW
-@ stdcall EnumPrintersW(long ptr long ptr long ptr ptr)
-@ stdcall EnumPrintProcessorDatatypesW(ptr ptr long ptr long ptr ptr)
-@ stdcall EnumPrintProcessorsW(ptr ptr long ptr long ptr ptr)
+@ stdcall EnumPrintersW(long wstr long ptr long ptr ptr)
+@ stdcall EnumPrintProcessorDatatypesW(wstr wstr long ptr long ptr ptr)
+@ stdcall EnumPrintProcessorsW(wstr wstr long ptr long ptr ptr)
 @ stub FindClosePrinterChangeNotification
 @ stub FlushPrinter
 @ stub FormatPrinterForRegistryKey
 @ stub FindClosePrinterChangeNotification
 @ stub FlushPrinter
 @ stub FormatPrinterForRegistryKey
index bf2a542..78d9600 100644 (file)
@@ -6,6 +6,8 @@ include_directories(${REACTOS_SOURCE_DIR}/lib/skiplist)
 list(APPEND SOURCE
     jobs.c
     main.c
 list(APPEND SOURCE
     jobs.c
     main.c
+    monitors.c
+    ports.c
     precomp.h
     printers.c
     printprocessors.c
     precomp.h
     printers.c
     printprocessors.c
index 35291ac..fd7c7fc 100644 (file)
@@ -102,7 +102,7 @@ GetNextJobID(PDWORD dwJobID)
     return TRUE;
 }
 
     return TRUE;
 }
 
-void
+BOOL
 InitializeGlobalJobList()
 {
     const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
 InitializeGlobalJobList()
 {
     const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
@@ -110,6 +110,7 @@ InitializeGlobalJobList()
     const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
     const DWORD cchPattern = sizeof("?????") - 1;
 
     const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
     const DWORD cchPattern = sizeof("?????") - 1;
 
+    DWORD dwErrorCode;
     DWORD dwJobID;
     HANDLE hFind;
     PLOCAL_JOB pJob = NULL;
     DWORD dwJobID;
     HANDLE hFind;
     PLOCAL_JOB pJob = NULL;
@@ -133,6 +134,7 @@ InitializeGlobalJobList()
     if (hFind == INVALID_HANDLE_VALUE)
     {
         // No unfinished jobs found.
     if (hFind == INVALID_HANDLE_VALUE)
     {
         // No unfinished jobs found.
+        dwErrorCode = ERROR_SUCCESS;
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
@@ -159,6 +161,7 @@ InitializeGlobalJobList()
         // Add it to the Global Job List.
         if (!InsertElementSkiplist(&GlobalJobList, pJob))
         {
         // Add it to the Global Job List.
         if (!InsertElementSkiplist(&GlobalJobList, pJob))
         {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
             ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID);
             goto Cleanup;
         }
             ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID);
             goto Cleanup;
         }
@@ -166,16 +169,22 @@ InitializeGlobalJobList()
         // Add it to the Printer's Job List.
         if (!InsertElementSkiplist(&pJob->pPrinter->JobList, pJob))
         {
         // Add it to the Printer's Job List.
         if (!InsertElementSkiplist(&pJob->pPrinter->JobList, pJob))
         {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
             ERR("InsertElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID);
             goto Cleanup;
         }
     }
     while (FindNextFileW(hFind, &FindData));
 
             ERR("InsertElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID);
             goto Cleanup;
         }
     }
     while (FindNextFileW(hFind, &FindData));
 
+    dwErrorCode = ERROR_SUCCESS;
+
 Cleanup:
     // Outside the loop
     if (hFind)
         FindClose(hFind);
 Cleanup:
     // Outside the loop
     if (hFind)
         FindClose(hFind);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 void
 }
 
 void
index c9b3e73..2e62069 100644 (file)
@@ -23,6 +23,8 @@ const WCHAR wszCurrentEnvironment[] =
     #error Unsupported architecture
 #endif
 
     #error Unsupported architecture
 #endif
 
+const DWORD cbCurrentEnvironment = sizeof(wszCurrentEnvironment);
+
 const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
 
 const WCHAR* wszPrintProviderInfo[3] = {
 const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
 
 const WCHAR* wszPrintProviderInfo[3] = {
@@ -70,8 +72,8 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
     NULL,                                       // fpGetForm
     NULL,                                       // fpSetForm
     NULL,                                       // fpEnumForms
     NULL,                                       // fpGetForm
     NULL,                                       // fpSetForm
     NULL,                                       // fpEnumForms
-    NULL,                                       // fpEnumMonitors
-    NULL,                                       // fpEnumPorts
+    LocalEnumMonitors,                          // fpEnumMonitors
+    LocalEnumPorts,                             // fpEnumPorts
     NULL,                                       // fpAddPort
     NULL,                                       // fpConfigurePort
     NULL,                                       // fpDeletePort
     NULL,                                       // fpAddPort
     NULL,                                       // fpConfigurePort
     NULL,                                       // fpDeletePort
@@ -142,13 +144,15 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             _GetSpoolDirectory();
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             _GetSpoolDirectory();
-            InitializePrintProcessorList();
-            InitializePrinterList();
-            InitializeGlobalJobList();
-            break;
-    }
 
 
-    return TRUE;
+            return InitializePrintMonitorList() &&
+                   InitializePrintProcessorList() &&
+                   InitializePrinterList() &&
+                   InitializeGlobalJobList();
+
+        default:
+            return TRUE;
+    }
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
diff --git a/reactos/win32ss/printing/providers/localspl/monitors.c b/reactos/win32ss/printing/providers/localspl/monitors.c
new file mode 100644 (file)
index 0000000..0dd2b70
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * 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 Monitors
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Local Variables
+LIST_ENTRY PrintMonitorList;
+
+BOOL
+InitializePrintMonitorList()
+{
+    const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors";
+    const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
+
+    DWORD cchMaxSubKey;
+    DWORD cchPrintMonitorName;
+    DWORD dwErrorCode;
+    DWORD dwSubKeys;
+    DWORD i;
+    HINSTANCE hinstPrintMonitor = NULL;
+    HKEY hKey = NULL;
+    HKEY hSubKey = NULL;
+    MONITORINIT MonitorInit;
+    PInitializePrintMonitor pfnInitializePrintMonitor;
+    PInitializePrintMonitor2 pfnInitializePrintMonitor2;
+    PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
+    PWSTR pwszRegistryPath = NULL;
+
+    // Initialize an empty list for our Print Monitors.
+    InitializeListHead(&PrintMonitorList);
+
+    // Open the key containing Print Monitors.
+    dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszMonitorsPath, 0, KEY_READ, &hKey);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+        ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Get the number of Print Providers and maximum sub key length.
+    dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+        ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Loop through all available Print Providers.
+    for (i = 0; i < dwSubKeys; i++)
+    {
+        // Cleanup tasks from the previous run
+        if (hSubKey)
+        {
+            RegCloseKey(hSubKey);
+            hSubKey = NULL;
+        }
+
+        if (pwszRegistryPath)
+        {
+            DllFreeSplMem(pwszRegistryPath);
+            pwszRegistryPath = NULL;
+        }
+
+        if (pPrintMonitor)
+        {
+            if (pPrintMonitor->pwszFileName)
+                DllFreeSplMem(pPrintMonitor->pwszFileName);
+
+            if (pPrintMonitor->pwszName)
+                DllFreeSplMem(pPrintMonitor->pwszName);
+
+            DllFreeSplMem(pPrintMonitor);
+            pPrintMonitor = NULL;
+        }
+
+        // Create a new LOCAL_PRINT_MONITOR structure for it.
+        pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
+        if (!pPrintMonitor)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+            goto Cleanup;
+        }
+
+        // Allocate memory for the Print Monitor Name.
+        pPrintMonitor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+        if (!pPrintMonitor->pwszName)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+            goto Cleanup;
+        }
+
+        // Get the name of this Print Monitor.
+        cchPrintMonitorName = cchMaxSubKey + 1;
+        dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pPrintMonitor->pwszName, &cchPrintMonitorName, NULL, NULL, NULL, NULL);
+        if (dwErrorCode != ERROR_SUCCESS)
+        {
+            ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
+            continue;
+        }
+
+        // Open this Print Monitor's registry key.
+        dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pPrintMonitor->pwszName, 0, KEY_READ, &hSubKey);
+        if (dwErrorCode != ERROR_SUCCESS)
+        {
+            ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pPrintMonitor->pwszName, dwErrorCode);
+            continue;
+        }
+
+        // Get the file name of the Print Monitor.
+        pPrintMonitor->pwszFileName = AllocAndRegQueryWSZ(hSubKey, L"Driver");
+        if (!pPrintMonitor->pwszFileName)
+            continue;
+
+        // Try to load it.
+        hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
+        if (!hinstPrintMonitor)
+        {
+            ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
+            continue;
+        }
+
+        // Try to find a Level 2 initialization routine first.
+        pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
+        if (pfnInitializePrintMonitor2)
+        {
+            // Prepare a MONITORINIT structure.
+            MonitorInit.cbSize = sizeof(MONITORINIT);
+            MonitorInit.bLocal = TRUE;
+
+            // TODO: Fill the other fields.
+
+            // Call the Level 2 initialization routine.
+            pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
+            if (!pPrintMonitor->pMonitor)
+            {
+                ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
+                continue;
+            }
+
+            pPrintMonitor->bIsLevel2 = TRUE;
+        }
+        else
+        {
+            // Try to find a Level 1 initialization routine then.
+            pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
+            if (pfnInitializePrintMonitor)
+            {
+                // Construct the registry path.
+                pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
+                if (!pwszRegistryPath)
+                {
+                    dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+                    ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+                    goto Cleanup;
+                }
+
+                CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
+                pwszRegistryPath[cchMonitorsPath] = L'\\';
+                CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
+
+                // Call the Level 1 initialization routine.
+                pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
+                if (!pPrintMonitor->pMonitor)
+                {
+                    ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
+                    continue;
+                }
+            }
+            else
+            {
+                ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
+                continue;
+            }
+        }
+
+        // Add this Print Monitor to the list.
+        InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
+
+        // Don't let the cleanup routine free this.
+        pPrintMonitor = NULL;
+    }
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    // Inside the loop
+    if (hSubKey)
+        RegCloseKey(hSubKey);
+
+    if (pwszRegistryPath)
+        DllFreeSplMem(pwszRegistryPath);
+
+    if (pPrintMonitor)
+    {
+        if (pPrintMonitor->pwszFileName)
+            DllFreeSplMem(pPrintMonitor->pwszFileName);
+
+        if (pPrintMonitor->pwszName)
+            DllFreeSplMem(pPrintMonitor->pwszName);
+
+        DllFreeSplMem(pPrintMonitor);
+    }
+
+    // Outside the loop
+    if (hKey)
+        RegCloseKey(hKey);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    DWORD cbFileName;
+    DWORD cbMonitorName;
+    DWORD dwErrorCode;
+    PBYTE pStart;
+    PBYTE pEnd;
+    PLIST_ENTRY pEntry;
+    PLOCAL_PRINT_MONITOR pPrintMonitor;
+    MONITOR_INFO_2W MonitorInfo2;               // MONITOR_INFO_1W is a subset of MONITOR_INFO_2W, so we can handle both in one function here.
+
+    // Sanity checks.
+    if (Level > 2)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    if ((cbBuf && !pMonitors) || !pcbNeeded || !pcReturned)
+    {
+        dwErrorCode = ERROR_INVALID_PARAMETER;
+        goto Cleanup;
+    }
+
+    // Begin counting.
+    *pcbNeeded = 0;
+    *pcReturned = 0;
+
+    // Count the required buffer size and the number of monitors.
+    for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+    {
+        pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+        cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
+        cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
+
+        if (Level == 1)
+            *pcbNeeded += sizeof(MONITOR_INFO_1W) + cbMonitorName;
+        else
+            *pcbNeeded += sizeof(MONITOR_INFO_2W) + cbMonitorName + cbCurrentEnvironment + cbFileName;
+    }
+
+    // Check if the supplied buffer is large enough.
+    if (cbBuf < *pcbNeeded)
+    {
+        dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+        goto Cleanup;
+    }
+
+    // Put the strings at the end of the buffer.
+    pStart = pMonitors;
+    pEnd = &pMonitors[cbBuf];
+
+    for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+    {
+        pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+        // Copy the monitor name.
+        cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
+        pEnd -= cbMonitorName;
+        MonitorInfo2.pName = (PWSTR)pEnd;
+        CopyMemory(pEnd, pPrintMonitor->pwszName, cbMonitorName);
+
+        if (Level == 1)
+        {
+            // Finally copy the structure.
+            CopyMemory(pStart, &MonitorInfo2, sizeof(MONITOR_INFO_1W));
+            pStart += sizeof(MONITOR_INFO_1W);
+        }
+        else
+        {
+            // Copy the environment.
+            pEnd -= cbCurrentEnvironment;
+            MonitorInfo2.pEnvironment = (PWSTR)pEnd;
+            CopyMemory(pEnd, wszCurrentEnvironment, cbCurrentEnvironment);
+
+            // Copy the file name.
+            cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
+            pEnd -= cbFileName;
+            MonitorInfo2.pDLLName = (PWSTR)pEnd;
+            CopyMemory(pEnd, pPrintMonitor->pwszFileName, cbFileName);
+
+            // Finally copy the structure.
+            CopyMemory(pStart, &MonitorInfo2, sizeof(MONITOR_INFO_2W));
+            pStart += sizeof(MONITOR_INFO_2W);
+        }
+
+        (*pcReturned)++;
+    }
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
diff --git a/reactos/win32ss/printing/providers/localspl/ports.c b/reactos/win32ss/printing/providers/localspl/ports.c
new file mode 100644 (file)
index 0000000..6748368
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * PROJECT:     ReactOS Local Spooler
+ * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Functions related to Ports of the Print Monitors
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+
+BOOL WINAPI
+LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    BOOL bReturnValue;
+    DWORD cbCallBuffer;
+    DWORD cbNeeded;
+    DWORD dwReturned;
+    PBYTE pCallBuffer;
+    PLOCAL_PRINT_MONITOR pPrintMonitor;
+    PLIST_ENTRY pEntry;
+
+    // Sanity checks.
+    if ((cbBuf && !pPorts) || !pcbNeeded || !pcReturned)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    // Begin counting.
+    *pcbNeeded = 0;
+    *pcReturned = 0;
+
+    // At the beginning, we have the full buffer available.
+    cbCallBuffer = cbBuf;
+    pCallBuffer = pPorts;
+
+    // Loop through all Print Monitors.
+    for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+    {
+        pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+        // Call the EnumPorts function of this Print Monitor.
+        if (pPrintMonitor->bIsLevel2)
+            bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+        else
+            bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+        // Add the returned counts to the total values.
+        *pcbNeeded += cbNeeded;
+        *pcReturned += dwReturned;
+
+        // Reduce the available buffer size for the next call without risking an underflow.
+        if (cbNeeded < cbCallBuffer)
+            cbCallBuffer -= cbNeeded;
+        else
+            cbCallBuffer = 0;
+
+        // Advance the buffer if the caller provided it.
+        if (pCallBuffer)
+            pCallBuffer += cbNeeded;
+    }
+
+    return bReturnValue;
+}
index 82d567d..7447ef4 100644 (file)
@@ -45,6 +45,8 @@ typedef BOOL (WINAPI *PEnumPrintProcessorDatatypesW)(LPWSTR, LPWSTR, DWORD, LPBY
 typedef DWORD (WINAPI *PGetPrintProcessorCapabilities)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
 typedef HANDLE (WINAPI *POpenPrintProcessor)(LPWSTR, PPRINTPROCESSOROPENDATA);
 typedef BOOL (WINAPI *PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR);
 typedef DWORD (WINAPI *PGetPrintProcessorCapabilities)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
 typedef HANDLE (WINAPI *POpenPrintProcessor)(LPWSTR, PPRINTPROCESSOROPENDATA);
 typedef BOOL (WINAPI *PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR);
+typedef LPMONITOREX(WINAPI *PInitializePrintMonitor)(PWSTR);
+typedef LPMONITOR2(WINAPI *PInitializePrintMonitor2)(PMONITORINIT, PHANDLE);
 
 // Structures
 /**
 
 // Structures
 /**
@@ -142,6 +144,21 @@ typedef struct _LOCAL_HANDLE
 }
 LOCAL_HANDLE, *PLOCAL_HANDLE;
 
 }
 LOCAL_HANDLE, *PLOCAL_HANDLE;
 
+/**
+ * Describes a Print Monitor.
+ */
+typedef struct _LOCAL_PRINT_MONITOR
+{
+    LIST_ENTRY Entry;
+    PWSTR pwszName;                     /** Name of the Print Monitor as read from the registry. */
+    PWSTR pwszFileName;                 /** DLL File Name of the Print Monitor. */
+    BOOL bIsLevel2;                     /** Whether this Print Monitor supplies an InitializePrintMonitor2 API (preferred) instead of InitializePrintMonitor. */
+    PVOID pMonitor;                     /** For bIsLevel2 == TRUE:  LPMONITOR2 pointer returned by InitializePrintMonitor2.
+                                            For bIsLevel2 == FALSE: LPMONITOREX pointer returned by InitializePrintMonitor. */
+    HANDLE hMonitor;                    /** Only used when bIsLevel2 == TRUE: Handle returned by InitializePrintMonitor2. */
+}
+LOCAL_PRINT_MONITOR, *PLOCAL_PRINT_MONITOR;
+
 /**
  * Describes the header of a print job serialized into a shadow file (.SHD)
  * Documented in http://www.undocprint.org/formats/winspool/shd
 /**
  * Describes the header of a print job serialized into a shadow file (.SHD)
  * Documented in http://www.undocprint.org/formats/winspool/shd
@@ -184,7 +201,7 @@ SHD_HEADER, *PSHD_HEADER;
 // jobs.c
 extern SKIPLIST GlobalJobList;
 BOOL GetNextJobID(PDWORD dwJobID);
 // jobs.c
 extern SKIPLIST GlobalJobList;
 BOOL GetNextJobID(PDWORD dwJobID);
-void InitializeGlobalJobList();
+BOOL InitializeGlobalJobList();
 void InitializePrinterJobList(PLOCAL_PRINTER pPrinter);
 BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded);
 BOOL WINAPI LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 void InitializePrinterJobList(PLOCAL_PRINTER pPrinter);
 BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded);
 BOOL WINAPI LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
@@ -196,14 +213,23 @@ BOOL WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob);
 
 // main.c
 extern const WCHAR wszCurrentEnvironment[];
 
 // main.c
 extern const WCHAR wszCurrentEnvironment[];
+extern const DWORD cbCurrentEnvironment;
 extern const WCHAR wszDefaultDocumentName[];
 extern const WCHAR* wszPrintProviderInfo[3];
 extern WCHAR wszSpoolDirectory[MAX_PATH];
 extern DWORD cchSpoolDirectory;
 
 extern const WCHAR wszDefaultDocumentName[];
 extern const WCHAR* wszPrintProviderInfo[3];
 extern WCHAR wszSpoolDirectory[MAX_PATH];
 extern DWORD cchSpoolDirectory;
 
+// monitors.c
+extern LIST_ENTRY PrintMonitorList;
+BOOL InitializePrintMonitorList();
+BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
+
+// ports.c
+BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
+
 // printers.c
 extern SKIPLIST PrinterList;
 // printers.c
 extern SKIPLIST PrinterList;
-void InitializePrinterList();
+BOOL InitializePrinterList();
 BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault);
 DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo);
 BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault);
 DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo);
@@ -216,7 +242,7 @@ BOOL WINAPI LocalClosePrinter(HANDLE hPrinter);
 // printprocessors.c
 BOOL FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype);
 PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PWSTR pwszName);
 // printprocessors.c
 BOOL FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype);
 PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PWSTR pwszName);
-void InitializePrintProcessorList();
+BOOL InitializePrintProcessorList();
 BOOL WINAPI LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 BOOL WINAPI LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 BOOL WINAPI LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded);
 BOOL WINAPI LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 BOOL WINAPI LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
 BOOL WINAPI LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded);
index c7e89c5..b121dea 100644 (file)
@@ -33,18 +33,18 @@ _PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
  * The list is searchable by name and returns information about the printers, including their job queues.
  * During this process, the job queues are also initialized.
  */
  * The list is searchable by name and returns information about the printers, including their job queues.
  * During this process, the job queues are also initialized.
  */
-void
+BOOL
 InitializePrinterList()
 {
     const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers";
 
     DWORD cbData;
     DWORD cchPrinterName;
 InitializePrinterList()
 {
     const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers";
 
     DWORD cbData;
     DWORD cchPrinterName;
+    DWORD dwErrorCode;
     DWORD dwSubKeys;
     DWORD i;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
     DWORD dwSubKeys;
     DWORD i;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
-    LONG lStatus;
     PLOCAL_PRINTER pPrinter = NULL;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor;
     PWSTR pwszPrintProcessor = NULL;
     PLOCAL_PRINTER pPrinter = NULL;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor;
     PWSTR pwszPrintProcessor = NULL;
@@ -54,18 +54,18 @@ InitializePrinterList()
     InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
 
     // Open our printers registry key. Each subkey is a local printer there.
     InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
 
     // Open our printers registry key. Each subkey is a local printer there.
-    lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey);
-    if (lStatus != ERROR_SUCCESS)
+    dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey);
+    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 subkeys.
         goto Cleanup;
     }
 
     // Get the number of subkeys.
-    lStatus = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-    if (lStatus != ERROR_SUCCESS)
+    dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, NULL, 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;
     }
 
         goto Cleanup;
     }
 
@@ -105,23 +105,23 @@ InitializePrinterList()
 
         // Get the name of this printer.
         cchPrinterName = _countof(wszPrinterName);
 
         // Get the name of this printer.
         cchPrinterName = _countof(wszPrinterName);
-        lStatus = RegEnumKeyExW(hKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL);
-        if (lStatus == ERROR_MORE_DATA)
+        dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL);
+        if (dwErrorCode == ERROR_MORE_DATA)
         {
             // This printer name exceeds the maximum length and is invalid.
             continue;
         }
         {
             // This printer name exceeds the maximum length and is invalid.
             continue;
         }
-        else if (lStatus != ERROR_SUCCESS)
+        else if (dwErrorCode != ERROR_SUCCESS)
         {
         {
-            ERR("RegEnumKeyExW failed for iteration %lu with status %ld!\n", i, lStatus);
+            ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
             continue;
         }
 
         // Open this Printer's registry key.
             continue;
         }
 
         // Open this Printer's registry key.
-        lStatus = RegOpenKeyExW(hKey, wszPrinterName, 0, KEY_READ, &hSubKey);
-        if (lStatus != ERROR_SUCCESS)
+        dwErrorCode = (DWORD)RegOpenKeyExW(hKey, wszPrinterName, 0, KEY_READ, &hSubKey);
+        if (dwErrorCode != ERROR_SUCCESS)
         {
         {
-            ERR("RegOpenKeyExW failed for Printer \"%S\" with status %ld!\n", wszPrinterName, lStatus);
+            ERR("RegOpenKeyExW failed for Printer \"%S\" with status %lu!\n", wszPrinterName, dwErrorCode);
             continue;
         }
 
             continue;
         }
 
@@ -142,6 +142,7 @@ InitializePrinterList()
         pPrinter = DllAllocSplMem(sizeof(LOCAL_PRINTER));
         if (!pPrinter)
         {
         pPrinter = DllAllocSplMem(sizeof(LOCAL_PRINTER));
         if (!pPrinter)
         {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
             ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
             goto Cleanup;
         }
             ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
             goto Cleanup;
         }
@@ -174,28 +175,28 @@ InitializePrinterList()
 
         // Get the default DevMode.
         cbData = sizeof(DEVMODEW);
 
         // Get the default DevMode.
         cbData = sizeof(DEVMODEW);
-        lStatus = RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)&pPrinter->DefaultDevMode, &cbData);
-        if (lStatus != ERROR_SUCCESS || cbData != sizeof(DEVMODEW))
+        dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)&pPrinter->DefaultDevMode, &cbData);
+        if (dwErrorCode != ERROR_SUCCESS || cbData != sizeof(DEVMODEW))
         {
         {
-            ERR("Couldn't query a valid DevMode for Printer \"%S\", status is %ld, cbData is %lu!\n", wszPrinterName, lStatus, cbData);
+            ERR("Couldn't query a valid DevMode for Printer \"%S\", status is %lu, cbData is %lu!\n", wszPrinterName, dwErrorCode, cbData);
             continue;
         }
 
         // Get the Attributes.
         cbData = sizeof(DWORD);
             continue;
         }
 
         // Get the Attributes.
         cbData = sizeof(DWORD);
-        lStatus = RegQueryValueExW(hSubKey, L"Attributes", NULL, NULL, (PBYTE)&pPrinter->dwAttributes, &cbData);
-        if (lStatus != ERROR_SUCCESS)
+        dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Attributes", NULL, NULL, (PBYTE)&pPrinter->dwAttributes, &cbData);
+        if (dwErrorCode != ERROR_SUCCESS)
         {
         {
-            ERR("Couldn't query Attributes for Printer \"%S\", status is %ld!\n", wszPrinterName, lStatus);
+            ERR("Couldn't query Attributes for Printer \"%S\", status is %lu!\n", wszPrinterName, dwErrorCode);
             continue;
         }
 
         // Get the Status.
         cbData = sizeof(DWORD);
             continue;
         }
 
         // Get the Status.
         cbData = sizeof(DWORD);
-        lStatus = RegQueryValueExW(hSubKey, L"Status", NULL, NULL, (PBYTE)&pPrinter->dwStatus, &cbData);
-        if (lStatus != ERROR_SUCCESS)
+        dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Status", NULL, NULL, (PBYTE)&pPrinter->dwStatus, &cbData);
+        if (dwErrorCode != ERROR_SUCCESS)
         {
         {
-            ERR("Couldn't query Status for Printer \"%S\", status is %ld!\n", wszPrinterName, lStatus);
+            ERR("Couldn't query Status for Printer \"%S\", status is %lu!\n", wszPrinterName, dwErrorCode);
             continue;
         }
 
             continue;
         }
 
@@ -210,6 +211,8 @@ InitializePrinterList()
         pPrinter = NULL;
     }
 
         pPrinter = NULL;
     }
 
+    dwErrorCode = ERROR_SUCCESS;
+
 Cleanup:
     // Inside the loop
     if (hSubKey)
 Cleanup:
     // Inside the loop
     if (hSubKey)
@@ -238,6 +241,9 @@ Cleanup:
     // Outside the loop
     if (hKey)
         RegCloseKey(hKey);
     // Outside the loop
     if (hKey)
         RegCloseKey(hKey);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 
 }
 
 
index 9898598..e4bd6b3 100644 (file)
@@ -111,7 +111,7 @@ FindPrintProcessor(PWSTR pwszName)
  *
  * Initializes a singly linked list of locally available Print Processors.
  */
  *
  * Initializes a singly linked list of locally available Print Processors.
  */
-void
+BOOL
 InitializePrintProcessorList()
 {
     DWORD cbDatatypes;
 InitializePrintProcessorList()
 {
     DWORD cbDatatypes;
@@ -119,15 +119,14 @@ InitializePrintProcessorList()
     DWORD cchPrintProcessorPath;
     DWORD cchMaxSubKey;
     DWORD cchPrintProcessorName;
     DWORD cchPrintProcessorPath;
     DWORD cchMaxSubKey;
     DWORD cchPrintProcessorName;
+    DWORD dwErrorCode;
     DWORD dwSubKeys;
     DWORD i;
     HINSTANCE hinstPrintProcessor;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
     HKEY hSubSubKey = NULL;
     DWORD dwSubKeys;
     DWORD i;
     HINSTANCE hinstPrintProcessor;
     HKEY hKey = NULL;
     HKEY hSubKey = NULL;
     HKEY hSubSubKey = NULL;
-    LONG lStatus;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
-    PWSTR pwszPrintProcessorName = NULL;
     WCHAR wszFileName[MAX_PATH];
     WCHAR wszPrintProcessorPath[MAX_PATH];
 
     WCHAR wszFileName[MAX_PATH];
     WCHAR wszPrintProcessorPath[MAX_PATH];
 
@@ -136,36 +135,32 @@ InitializePrintProcessorList()
     
     // 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) != ERROR_SUCCESS)
+    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 = 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;
     }
 
         goto Cleanup;
     }
 
@@ -191,36 +186,54 @@ InitializePrintProcessorList()
             pPrintProcessor = NULL;
         }
 
             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 + 1;
         // Get the name of this Print Processor.
         cchPrintProcessorName = cchMaxSubKey + 1;
-        lStatus = RegEnumKeyExW(hSubKey, i, pwszPrintProcessorName, &cchPrintProcessorName, NULL, NULL, NULL, NULL);
-        if (lStatus != ERROR_SUCCESS)
+        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;
         }
 
@@ -229,16 +242,12 @@ InitializePrintProcessorList()
 
         // 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 = 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)
         // Get and verify all its function pointers.
         pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
         if (!pPrintProcessor->pfnClosePrintProcessor)
@@ -287,6 +296,7 @@ InitializePrintProcessorList()
         pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
         if (!pPrintProcessor->pDatatypesInfo1)
         {
         pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
         if (!pPrintProcessor->pDatatypesInfo1)
         {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
             ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
             goto Cleanup;
         }
             ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
             goto Cleanup;
         }
@@ -304,6 +314,8 @@ InitializePrintProcessorList()
         pPrintProcessor = NULL;
     }
 
         pPrintProcessor = NULL;
     }
 
+    dwErrorCode = ERROR_SUCCESS;
+
 Cleanup:
     // Inside the loop
     if (hSubSubKey)
 Cleanup:
     // Inside the loop
     if (hSubSubKey)
@@ -321,14 +333,14 @@ Cleanup:
     }
 
     // Outside the loop
     }
 
     // Outside the loop
-    if (pwszPrintProcessorName)
-        DllFreeSplStr(pwszPrintProcessorName);
-
     if (hSubKey)
         RegCloseKey(hSubKey);
 
     if (hKey)
         RegCloseKey(hKey);
     if (hSubKey)
         RegCloseKey(hSubKey);
 
     if (hKey)
         RegCloseKey(hKey);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 /**
 }
 
 /**