[LOCALSPL]

- 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
This commit is contained in:
Colin Finck 2015-07-07 17:06:48 +00:00
parent 91eab8a77a
commit b83f56253b
18 changed files with 1132 additions and 166 deletions

View file

@ -6,6 +6,7 @@ list(APPEND SOURCE
jobs.c
main.c
memory.c
monitors.c
ports.c
precomp.h
printers.c

View file

@ -8,31 +8,76 @@
#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)
{
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
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)
{
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)
{
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);
}

View file

@ -7,10 +7,180 @@
#include "precomp.h"
// Global Variables
HANDLE hProcessHeap;
PRINTPROVIDOR LocalSplFuncs;
LIST_ENTRY PrintProviderList;
static DWORD
_AddPrintProviderToList(PCWSTR pwszFileName)
{
DWORD dwErrorCode;
HINSTANCE hinstPrintProvider;
PInitializePrintProvidor pfnInitializePrintProvidor;
PSPOOLSS_PRINT_PROVIDER pPrintProvider = NULL;
// Try to load it.
hinstPrintProvider = LoadLibraryW(pwszFileName);
if (!hinstPrintProvider)
{
dwErrorCode = GetLastError();
ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
goto Cleanup;
}
// 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;
}
static BOOL
_InitializePrintProviderList()
{
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;
}
// 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("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;
}
// Allocate a temporary buffer for the Print Provider names.
pwszPrintProviderName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
if (!pwszPrintProviderName)
{
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)
{
@ -18,7 +188,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
hProcessHeap = GetProcessHeap();
hProcessHeap = GetProcessHeap();
break;
}
@ -28,32 +198,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
BOOL WINAPI
InitializeRouter(HANDLE SpoolerStatusHandle)
{
HINSTANCE hinstLocalSpl;
PInitializePrintProvidor pfnInitializePrintProvidor;
// 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)
{
ERR("LoadLibraryW for localspl failed with error %lu!\n", GetLastError());
return FALSE;
}
pfnInitializePrintProvidor = (PInitializePrintProvidor)GetProcAddress(hinstLocalSpl, "InitializePrintProvidor");
if (!pfnInitializePrintProvidor)
{
ERR("GetProcAddress failed with error %lu!\n", GetLastError());
return FALSE;
}
if (!pfnInitializePrintProvidor(&LocalSplFuncs, sizeof(PRINTPROVIDOR), NULL))
{
ERR("InitializePrintProvidor failed for localspl with error %lu!\n", GetLastError());
return FALSE;
}
return TRUE;
return _InitializePrintProviderList();
}
BOOL WINAPI

View 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)
{

View file

@ -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;
}

View 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
* PURPOSE: Functions related to ports
* PURPOSE: Functions related to Ports of the Print Monitors
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
*/
@ -10,5 +10,55 @@
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;
}

View file

@ -15,17 +15,40 @@
#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);
// Function pointer to InitializePrintProvidor of a provider DLL
// Function pointers
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;
extern PRINTPROVIDOR LocalSplFuncs;
extern LIST_ENTRY PrintProviderList;
#endif

View file

@ -11,71 +11,262 @@
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)
{
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)
{
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
EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, 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 && !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
GetPrinterDriverW(HANDLE hPrinter, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded)
{
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
GetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD cbBuf, PDWORD pcbNeeded)
{
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
OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW 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
EnumPrintersW(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
{
return LocalSplFuncs.fpEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
}
BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
{
return FALSE;
}
BOOL WINAPI
GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
{
return FALSE;
}
BOOL WINAPI
OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
{
return LocalSplFuncs.fpOpenPrinter(pPrinterName, phPrinter, pDefault);
}
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
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)
{
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
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)
{
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);
}

View file

@ -8,19 +8,25 @@
#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
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
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);
}

View file

@ -60,16 +60,16 @@
@ 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
@ stdcall EnumPortsW(ptr long ptr long ptr ptr)
@ stdcall EnumPortsW(wstr long ptr long ptr ptr)
@ 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

View file

@ -6,6 +6,8 @@ include_directories(${REACTOS_SOURCE_DIR}/lib/skiplist)
list(APPEND SOURCE
jobs.c
main.c
monitors.c
ports.c
precomp.h
printers.c
printprocessors.c

View file

@ -102,7 +102,7 @@ GetNextJobID(PDWORD dwJobID)
return TRUE;
}
void
BOOL
InitializeGlobalJobList()
{
const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
@ -110,6 +110,7 @@ InitializeGlobalJobList()
const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
const DWORD cchPattern = sizeof("?????") - 1;
DWORD dwErrorCode;
DWORD dwJobID;
HANDLE hFind;
PLOCAL_JOB pJob = NULL;
@ -133,6 +134,7 @@ InitializeGlobalJobList()
if (hFind == INVALID_HANDLE_VALUE)
{
// No unfinished jobs found.
dwErrorCode = ERROR_SUCCESS;
goto Cleanup;
}
@ -159,6 +161,7 @@ InitializeGlobalJobList()
// 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;
}
@ -166,16 +169,22 @@ InitializeGlobalJobList()
// 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));
dwErrorCode = ERROR_SUCCESS;
Cleanup:
// Outside the loop
if (hFind)
FindClose(hFind);
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
void

View file

@ -23,6 +23,8 @@ const WCHAR wszCurrentEnvironment[] =
#error Unsupported architecture
#endif
const DWORD cbCurrentEnvironment = sizeof(wszCurrentEnvironment);
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, // fpEnumMonitors
NULL, // fpEnumPorts
LocalEnumMonitors, // fpEnumMonitors
LocalEnumPorts, // fpEnumPorts
NULL, // fpAddPort
NULL, // fpConfigurePort
NULL, // fpDeletePort
@ -142,13 +144,15 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
_GetSpoolDirectory();
InitializePrintProcessorList();
InitializePrinterList();
InitializeGlobalJobList();
break;
}
return TRUE;
return InitializePrintMonitorList() &&
InitializePrintProcessorList() &&
InitializePrinterList() &&
InitializeGlobalJobList();
default:
return TRUE;
}
}
BOOL WINAPI

View file

@ -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);
}

View file

@ -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;
}

View 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 LPMONITOREX(WINAPI *PInitializePrintMonitor)(PWSTR);
typedef LPMONITOR2(WINAPI *PInitializePrintMonitor2)(PMONITORINIT, PHANDLE);
// Structures
/**
@ -142,6 +144,21 @@ typedef struct _LOCAL_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
@ -184,7 +201,7 @@ SHD_HEADER, *PSHD_HEADER;
// 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);
@ -196,14 +213,23 @@ BOOL WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob);
// 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;
// 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;
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);
@ -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);
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);

View 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.
*/
void
BOOL
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;
LONG lStatus;
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.
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.
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;
}
@ -105,23 +105,23 @@ InitializePrinterList()
// 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;
}
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.
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;
}
@ -142,6 +142,7 @@ InitializePrinterList()
pPrinter = DllAllocSplMem(sizeof(LOCAL_PRINTER));
if (!pPrinter)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -174,28 +175,28 @@ InitializePrinterList()
// 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);
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);
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;
}
@ -210,6 +211,8 @@ InitializePrinterList()
pPrinter = NULL;
}
dwErrorCode = ERROR_SUCCESS;
Cleanup:
// Inside the loop
if (hSubKey)
@ -238,6 +241,9 @@ Cleanup:
// Outside the loop
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}

View file

@ -111,7 +111,7 @@ FindPrintProcessor(PWSTR pwszName)
*
* Initializes a singly linked list of locally available Print Processors.
*/
void
BOOL
InitializePrintProcessorList()
{
DWORD cbDatatypes;
@ -119,15 +119,14 @@ InitializePrintProcessorList()
DWORD cchPrintProcessorPath;
DWORD cchMaxSubKey;
DWORD cchPrintProcessorName;
DWORD dwErrorCode;
DWORD dwSubKeys;
DWORD i;
HINSTANCE hinstPrintProcessor;
HKEY hKey = NULL;
HKEY hSubKey = NULL;
HKEY hSubSubKey = NULL;
LONG lStatus;
PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
PWSTR pwszPrintProcessorName = NULL;
WCHAR wszFileName[MAX_PATH];
WCHAR wszPrintProcessorPath[MAX_PATH];
@ -136,36 +135,32 @@ InitializePrintProcessorList()
// Prepare the path to the Print Processor directory.
if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
{
dwErrorCode = GetLastError();
goto Cleanup;
}
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.
lStatus = RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
if (lStatus != ERROR_SUCCESS)
dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed with status %ld!\n", lStatus);
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
// Get the number of Print Processors and maximum sub key length.
lStatus = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
if (lStatus != ERROR_SUCCESS)
dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
if (dwErrorCode != 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)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
@ -191,36 +186,54 @@ InitializePrintProcessorList()
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;
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.
lStatus = RegOpenKeyExW(hSubKey, pwszPrintProcessorName, 0, KEY_READ, &hSubSubKey);
if (lStatus != ERROR_SUCCESS)
dwErrorCode = (DWORD)RegOpenKeyExW(hSubKey, pPrintProcessor->pwszName, 0, KEY_READ, &hSubSubKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %ld!\n", pwszPrintProcessorName, lStatus);
ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
continue;
}
// Get the file name of the Print Processor.
cbFileName = sizeof(wszFileName);
lStatus = RegQueryValueExW(hSubSubKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
if (lStatus != ERROR_SUCCESS)
dwErrorCode = (DWORD)RegQueryValueExW(hSubSubKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %ld!\n", pwszPrintProcessorName, lStatus);
ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
continue;
}
// Verify that our buffer is large enough.
if (cchPrintProcessorPath + cbFileName / sizeof(WCHAR) > MAX_PATH)
{
ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName, pwszPrintProcessorName);
ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName, pPrintProcessor->pwszName);
continue;
}
@ -229,16 +242,12 @@ InitializePrintProcessorList()
// Try to load it.
hinstPrintProcessor = LoadLibraryW(wszPrintProcessorPath);
if (lStatus != ERROR_SUCCESS)
if (!hinstPrintProcessor)
{
ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
continue;
}
// Create a new LOCAL_PRINT_PROCESSOR structure for it.
pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
pPrintProcessor->pwszName = AllocSplStr(pwszPrintProcessorName);
// Get and verify all its function pointers.
pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
if (!pPrintProcessor->pfnClosePrintProcessor)
@ -287,6 +296,7 @@ InitializePrintProcessorList()
pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
if (!pPrintProcessor->pDatatypesInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -304,6 +314,8 @@ InitializePrintProcessorList()
pPrintProcessor = NULL;
}
dwErrorCode = ERROR_SUCCESS;
Cleanup:
// Inside the loop
if (hSubSubKey)
@ -321,14 +333,14 @@ Cleanup:
}
// Outside the loop
if (pwszPrintProcessorName)
DllFreeSplStr(pwszPrintProcessorName);
if (hSubKey)
RegCloseKey(hSubKey);
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
/**