[LOCALSPL]
authorColin Finck <colin@reactos.org>
Mon, 13 Jul 2015 10:18:07 +0000 (10:18 +0000)
committerColin Finck <colin@reactos.org>
Mon, 13 Jul 2015 10:18:07 +0000 (10:18 +0000)
- Rewrite LocalOpenPrinter to also properly support opening Port and Xcv handles.
- Manage a list of Ports and their associated Print Monitors.
- const-ify some parameters.

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

reactos/win32ss/printing/providers/localspl/jobs.c
reactos/win32ss/printing/providers/localspl/main.c
reactos/win32ss/printing/providers/localspl/monitors.c
reactos/win32ss/printing/providers/localspl/ports.c
reactos/win32ss/printing/providers/localspl/precomp.h
reactos/win32ss/printing/providers/localspl/printers.c
reactos/win32ss/printing/providers/localspl/printprocessors.c

index 47ca6af..b080bf9 100644 (file)
@@ -218,7 +218,7 @@ LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcb
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
-    if (pHandle->HandleType != Printer)
+    if (pHandle->HandleType != HandleType_Printer)
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
@@ -579,7 +579,7 @@ LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
-    if (pHandle->HandleType != Printer)
+    if (pHandle->HandleType != HandleType_Printer)
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
@@ -853,7 +853,7 @@ LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Com
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
-    if (pHandle->HandleType != Printer)
+    if (pHandle->HandleType != HandleType_Printer)
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
@@ -918,7 +918,7 @@ LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
-    if (pHandle->HandleType != Printer)
+    if (pHandle->HandleType != HandleType_Printer)
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
@@ -1015,7 +1015,7 @@ LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID)
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
-    if (pHandle->HandleType != Printer)
+    if (pHandle->HandleType != HandleType_Printer)
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
index 2e62069..ae0b16e 100644 (file)
@@ -146,6 +146,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             _GetSpoolDirectory();
 
             return InitializePrintMonitorList() &&
             _GetSpoolDirectory();
 
             return InitializePrintMonitorList() &&
+                   InitializePortList() &&
                    InitializePrintProcessorList() &&
                    InitializePrinterList() &&
                    InitializeGlobalJobList();
                    InitializePrintProcessorList() &&
                    InitializePrinterList() &&
                    InitializeGlobalJobList();
index 0dd2b70..3d1fc27 100644 (file)
@@ -7,9 +7,27 @@
 
 #include "precomp.h"
 
 
 #include "precomp.h"
 
-// Local Variables
+// Global Variables
 LIST_ENTRY PrintMonitorList;
 
 LIST_ENTRY PrintMonitorList;
 
+
+PLOCAL_PRINT_MONITOR
+FindPrintMonitor(PCWSTR pwszName)
+{
+    PLIST_ENTRY pEntry;
+    PLOCAL_PRINT_MONITOR pPrintMonitor;
+
+    for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+    {
+        pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+        if (_wcsicmp(pPrintMonitor->pwszName, pwszName) == 0)
+            return pPrintMonitor;
+    }
+
+    return NULL;
+}
+
 BOOL
 InitializePrintMonitorList()
 {
 BOOL
 InitializePrintMonitorList()
 {
index 6748368..1c5ed38 100644 (file)
@@ -7,6 +7,128 @@
 
 #include "precomp.h"
 
 
 #include "precomp.h"
 
+// Local Variables
+static LIST_ENTRY _PortList;
+
+
+PLOCAL_PRINT_MONITOR
+FindPrintMonitorByPort(PCWSTR pwszName)
+{
+    PLIST_ENTRY pEntry;
+    PLOCAL_PORT pPort;
+
+    for (pEntry = _PortList.Flink; pEntry != &_PortList; pEntry = pEntry->Flink)
+    {
+        pPort = CONTAINING_RECORD(pEntry, LOCAL_PORT, Entry);
+
+        if (_wcsicmp(pPort->pwszName, pwszName) == 0)
+            return pPort->pPrintMonitor;
+    }
+
+    return NULL;
+}
+
+BOOL
+InitializePortList()
+{
+    BOOL bReturnValue;
+    DWORD cbNeeded;
+    DWORD cbPortName;
+    DWORD dwErrorCode;
+    DWORD dwReturned;
+    DWORD i;
+    PLOCAL_PORT pPort;
+    PLOCAL_PRINT_MONITOR pPrintMonitor;
+    PLIST_ENTRY pEntry;
+    PPORT_INFO_1W p;
+    PPORT_INFO_1W pPortInfo1 = NULL;
+
+    // Initialize an empty list for our Ports.
+    InitializeListHead(&_PortList);
+
+    // Loop through all Print Monitors.
+    for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+    {
+        // Cleanup from the previous run.
+        if (pPortInfo1)
+        {
+            DllFreeSplMem(pPortInfo1);
+            pPortInfo1 = NULL;
+        }
+
+        pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+        // Determine the required buffer size for EnumPorts.
+        if (pPrintMonitor->bIsLevel2)
+            bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
+        else
+            bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
+
+        // Check the returned error code.
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
+            continue;
+        }
+
+        // Allocate a buffer large enough.
+        pPortInfo1 = DllAllocSplMem(cbNeeded);
+        if (!pPortInfo1)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+            goto Cleanup;
+        }
+
+        // Get the ports handled by this monitor.
+        if (pPrintMonitor->bIsLevel2)
+            bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
+        else
+            bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
+
+        // Check the return value.
+        if (!bReturnValue)
+        {
+            ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
+            continue;
+        }
+
+        // Loop through all returned ports.
+        p = pPortInfo1;
+
+        for (i = 0; i < dwReturned; i++)
+        {
+            cbPortName = (wcslen(p->pName) + 1) * sizeof(WCHAR);
+
+            // Create a new LOCAL_PORT structure for it.
+            pPort = DllAllocSplMem(sizeof(LOCAL_PORT) + cbPortName);
+            if (!pPort)
+            {
+                dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+                ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+                goto Cleanup;
+            }
+
+            pPort->pPrintMonitor = pPrintMonitor;
+            pPort->pwszName = (PWSTR)((PBYTE)pPort + sizeof(LOCAL_PORT));
+            CopyMemory(pPort->pwszName, p->pName, cbPortName);
+
+            // Insert it into the list and advance to the next port.
+            InsertTailList(&_PortList, &pPort->Entry);
+            p++;
+        }
+    }
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    // Inside the loop
+    if (pPortInfo1)
+        DllFreeSplMem(pPortInfo1);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
 
 BOOL WINAPI
 LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 
 BOOL WINAPI
 LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
index 1153081..65b65d3 100644 (file)
@@ -139,7 +139,12 @@ LOCAL_PRINTER_HANDLE, *PLOCAL_PRINTER_HANDLE;
  */
 typedef struct _LOCAL_HANDLE
 {
  */
 typedef struct _LOCAL_HANDLE
 {
-    enum { Printer, Monitor, Port } HandleType;
+    enum {
+        HandleType_Port,
+        HandleType_Printer,
+        HandleType_Xcv
+    }
+    HandleType;
     PVOID pSpecificHandle;
 }
 LOCAL_HANDLE, *PLOCAL_HANDLE;
     PVOID pSpecificHandle;
 }
 LOCAL_HANDLE, *PLOCAL_HANDLE;
@@ -159,6 +164,17 @@ typedef struct _LOCAL_PRINT_MONITOR
 }
 LOCAL_PRINT_MONITOR, *PLOCAL_PRINT_MONITOR;
 
 }
 LOCAL_PRINT_MONITOR, *PLOCAL_PRINT_MONITOR;
 
+/**
+ * Describes a Port handled by a Print Monitor.
+ */
+typedef struct _LOCAL_PORT
+{
+    LIST_ENTRY Entry;
+    PWSTR pwszName;                         /** The name of the port (including the trailing colon). */
+    PLOCAL_PRINT_MONITOR pPrintMonitor;     /** The Print Monitor handling this port. */
+}
+LOCAL_PORT, *PLOCAL_PORT;
+
 /**
  * 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
@@ -221,10 +237,13 @@ extern DWORD cchSpoolDirectory;
 
 // monitors.c
 extern LIST_ENTRY PrintMonitorList;
 
 // monitors.c
 extern LIST_ENTRY PrintMonitorList;
+PLOCAL_PRINT_MONITOR FindPrintMonitor(PCWSTR pwszName);
 BOOL InitializePrintMonitorList();
 BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
 
 // ports.c
 BOOL InitializePrintMonitorList();
 BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
 
 // ports.c
+PLOCAL_PRINT_MONITOR FindPrintMonitorByPort(PCWSTR pwszName);
+BOOL InitializePortList();
 BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
 
 // printers.c
 BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
 
 // printers.c
@@ -240,8 +259,8 @@ BOOL WINAPI LocalEndDocPrinter(HANDLE hPrinter);
 BOOL WINAPI LocalClosePrinter(HANDLE hPrinter);
 
 // printprocessors.c
 BOOL WINAPI LocalClosePrinter(HANDLE hPrinter);
 
 // printprocessors.c
-BOOL FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype);
-PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PWSTR pwszName);
+BOOL FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype);
+PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PCWSTR pwszName);
 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 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);
index 0540735..cf3f36c 100644 (file)
@@ -477,18 +477,25 @@ Cleanup:
 BOOL WINAPI
 LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault)
 {
 BOOL WINAPI
 LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault)
 {
+    BOOL bReturnValue;
     DWORD cchComputerName;
     DWORD cchComputerName;
-    DWORD cchPrinterName;
+    DWORD cchFirstParameter;
     DWORD dwErrorCode;
     DWORD dwJobID;
     DWORD dwErrorCode;
     DWORD dwJobID;
+    HANDLE hExternalHandle;
     PWSTR p = lpPrinterName;
     PWSTR p = lpPrinterName;
-    PWSTR pwszPrinterName = NULL;
+    PWSTR pwszFirstParameter = NULL;
+    PWSTR pwszSecondParameter = NULL;
     PLOCAL_JOB pJob;
     PLOCAL_JOB pJob;
-    PLOCAL_HANDLE pHandle;
+    PLOCAL_HANDLE pHandle = NULL;
+    PLOCAL_PRINT_MONITOR pPrintMonitor;
     PLOCAL_PRINTER pPrinter;
     PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
     WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
 
     PLOCAL_PRINTER pPrinter;
     PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
     WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
 
+    // TODO: lpPrinterName == NULL is supported and means access to the local printer server.
+    // Not sure yet if that is passed down to localspl.dll or processed in advance.
+
     // Sanity checks
     if (!lpPrinterName || !phPrinter)
     {
     // Sanity checks
     if (!lpPrinterName || !phPrinter)
     {
@@ -496,6 +503,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
+    // Skip any server name in the first parameter.
     // Does lpPrinterName begin with two backslashes to indicate a server name?
     if (lpPrinterName[0] == L'\\' && lpPrinterName[1] == L'\\')
     {
     // Does lpPrinterName begin with two backslashes to indicate a server name?
     if (lpPrinterName[0] == L'\\' && lpPrinterName[1] == L'\\')
     {
@@ -511,9 +519,6 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
             goto Cleanup;
         }
 
             goto Cleanup;
         }
 
-        // Null-terminate the string here to enable comparison.
-        *p = 0;
-
         // Get the local computer name for comparison.
         cchComputerName = _countof(wszComputerName);
         if (!GetComputerNameW(wszComputerName, &cchComputerName))
         // Get the local computer name for comparison.
         cchComputerName = _countof(wszComputerName);
         if (!GetComputerNameW(wszComputerName, &cchComputerName))
@@ -523,8 +528,10 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
             goto Cleanup;
         }
 
             goto Cleanup;
         }
 
-        // Now compare this with the local computer name and reject if it doesn't match, because this print provider only supports local printers.
-        if (wcsicmp(lpPrinterName, wszComputerName) != 0)
+        // Now compare this string excerpt with the local computer name.
+        // The input parameter may not be writable, so we can't null-terminate the input string at this point.
+        // This print provider only supports local printers, so both strings have to match.
+        if (p - lpPrinterName != cchComputerName || _wcsnicmp(lpPrinterName, wszComputerName, cchComputerName) != 0)
         {
             dwErrorCode = ERROR_INVALID_PRINTER_NAME;
             goto Cleanup;
         {
             dwErrorCode = ERROR_INVALID_PRINTER_NAME;
             goto Cleanup;
@@ -534,30 +541,155 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
         lpPrinterName = p + 1;
     }
 
         lpPrinterName = p + 1;
     }
 
-    // Look for a comma. If it exists, it indicates the end of the printer name.
-    p = wcschr(lpPrinterName, L',');
-    if (p)
-        cchPrinterName = p - lpPrinterName;
+    // Look for a comma. If it exists, it indicates the end of the first parameter.
+    pwszSecondParameter = wcschr(lpPrinterName, L',');
+    if (pwszSecondParameter)
+        cchFirstParameter = pwszSecondParameter - p;
     else
     else
-        cchPrinterName = wcslen(lpPrinterName);
+        cchFirstParameter = wcslen(lpPrinterName);
 
 
-    // No printer name and no comma? This is invalid!
-    if (!cchPrinterName && !p)
+    // We must have at least one parameter.
+    if (!cchFirstParameter && !pwszSecondParameter)
     {
         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
         goto Cleanup;
     }
 
     {
         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
         goto Cleanup;
     }
 
-    // Do we have a printer name?
-    if (cchPrinterName)
+    // Do we have a first parameter?
+    if (cchFirstParameter)
     {
         // Yes, extract it.
     {
         // Yes, extract it.
-        pwszPrinterName = DllAllocSplMem((cchPrinterName + 1) * sizeof(WCHAR));
-        CopyMemory(pwszPrinterName, lpPrinterName, cchPrinterName * sizeof(WCHAR));
-        pwszPrinterName[cchPrinterName] = 0;
+        pwszFirstParameter = DllAllocSplMem((cchFirstParameter + 1) * sizeof(WCHAR));
+        CopyMemory(pwszFirstParameter, lpPrinterName, cchFirstParameter * sizeof(WCHAR));
+        pwszFirstParameter[cchFirstParameter] = 0;
+    }
+
+    // Do we have a second parameter?
+    if (pwszSecondParameter)
+    {
+        // Yes, skip the comma at the beginning.
+        ++pwszSecondParameter;
+
+        // Skip whitespace as well.
+        while (*pwszSecondParameter == L' ')
+            ++pwszSecondParameter;
+    }
+
+    // Create a new handle.
+    pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+        ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Now we can finally check the type of handle actually requested.
+    if (pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Port", 4) == 0)
+    {
+        // The caller wants a port handle and provided a string like:
+        //    "LPT1:, Port"
+        //    "\\COMPUTERNAME\LPT1:, Port"
+        
+        // Look for this port in our Print Monitor Port list.
+        pPrintMonitor = FindPrintMonitorByPort(pwszFirstParameter);
+        if (!pPrintMonitor)
+        {
+            // The supplied port is unknown to all our Print Monitors.
+            dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+            goto Cleanup;
+        }
+
+        // Call the monitor's OpenPort function.
+        if (pPrintMonitor->bIsLevel2)
+            bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnOpenPort(pPrintMonitor->hMonitor, pwszFirstParameter, &hExternalHandle);
+        else
+            bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnOpenPort(pwszFirstParameter, &hExternalHandle);
+
+        if (!bReturnValue)
+        {
+            // The OpenPort function failed. Return its last error.
+            dwErrorCode = GetLastError();
+            goto Cleanup;
+        }
+
+        // Return the Port handle through our general handle.
+        pHandle->HandleType = HandleType_Port;
+        pHandle->pSpecificHandle = hExternalHandle;
+    }
+    else if (!pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Xcv", 3) == 0)
+    {
+        // The caller wants an Xcv handle and provided a string like:
+        //    ", XcvMonitor Local Port"
+        //    "\\COMPUTERNAME\, XcvMonitor Local Port"
+        //    ", XcvPort LPT1:"
+        //    "\\COMPUTERNAME\, XcvPort LPT1:"
+
+        // Skip the "Xcv" string.
+        pwszSecondParameter += 3;
+
+        // Is XcvMonitor or XcvPort requested?
+        if (wcsncmp(pwszSecondParameter, L"Monitor ", 8) == 0)
+        {
+            // Skip the "Monitor " string.
+            pwszSecondParameter += 8;
+
+            // Look for this monitor in our Print Monitor list.
+            pPrintMonitor = FindPrintMonitor(pwszSecondParameter);
+            if (!pPrintMonitor)
+            {
+                // The caller supplied a non-existing Monitor name.
+                dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+                goto Cleanup;
+            }
+        }
+        else if (wcsncmp(pwszSecondParameter, L"Port ", 5) == 0)
+        {
+            // Skip the "Port " string.
+            pwszSecondParameter += 5;
+
+            // Look for this port in our Print Monitor Port list.
+            pPrintMonitor = FindPrintMonitorByPort(pwszSecondParameter);
+            if (!pPrintMonitor)
+            {
+                // The supplied port is unknown to all our Print Monitors.
+                dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+                goto Cleanup;
+            }
+        }
+        else
+        {
+            dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+            goto Cleanup;
+        }
 
 
-        // Retrieve the associated printer from the list.
-        pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
+        // Call the monitor's XcvOpenPort function.
+        if (pPrintMonitor->bIsLevel2)
+            bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnXcvOpenPort(pPrintMonitor->hMonitor, pwszSecondParameter, SERVER_EXECUTE, &hExternalHandle);
+        else
+            bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnXcvOpenPort(pwszSecondParameter, SERVER_EXECUTE, &hExternalHandle);
+
+        if (!bReturnValue)
+        {
+            // The XcvOpenPort function failed. Return its last error.
+            dwErrorCode = GetLastError();
+            goto Cleanup;
+        }
+
+        // Return the Xcv handle through our general handle.
+        pHandle->HandleType = HandleType_Xcv;
+        pHandle->pSpecificHandle = hExternalHandle;
+    }
+    else
+    {
+        // The caller wants a Printer or Printer Job handle and provided a string like:
+        //    "HP DeskJet"
+        //    "\\COMPUTERNAME\HP DeskJet"
+        //    "HP DeskJet, Job 5"
+        //    "\\COMPUTERNAME\HP DeskJet, Job 5"
+
+        // Retrieve the printer from the list.
+        pPrinter = LookupElementSkiplist(&PrinterList, &pwszFirstParameter, NULL);
         if (!pPrinter)
         {
             // The printer does not exist.
         if (!pPrinter)
         {
             // The printer does not exist.
@@ -567,6 +699,13 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
 
         // Create a new printer handle.
         pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
 
         // Create a new printer handle.
         pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
+        if (!pPrinterHandle)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+            goto Cleanup;
+        }
+
         pPrinterHandle->pPrinter = pPrinter;
 
         // Check if a datatype was given.
         pPrinterHandle->pPrinter = pPrinter;
 
         // Check if a datatype was given.
@@ -593,34 +732,25 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
         else
             pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode);
 
         else
             pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode);
 
-        // Did we have a comma? Then the user may want a handle to an existing job instead of creating a new job.
-        if (p)
+        // Check if the caller wants a handle to an existing job.
+        if (pwszSecondParameter)
         {
         {
-            ++p;
-            
-            // Skip whitespace.
-            do
-            {
-                ++p;
-            }
-            while (*p == ' ');
-
             // The "Job " string has to follow now.
             // The "Job " string has to follow now.
-            if (wcscmp(p, L"Job ") != 0)
+            if (wcsncmp(pwszSecondParameter, L"Job ", 4) != 0)
             {
                 dwErrorCode = ERROR_INVALID_PRINTER_NAME;
                 goto Cleanup;
             }
 
             // Skip the "Job " string. 
             {
                 dwErrorCode = ERROR_INVALID_PRINTER_NAME;
                 goto Cleanup;
             }
 
             // Skip the "Job " string. 
-            p += sizeof("Job ") - 1;
+            pwszSecondParameter += 4;
 
             // Skip even more whitespace.
 
             // Skip even more whitespace.
-            while (*p == ' ')
-                ++p;
+            while (*pwszSecondParameter == ' ')
+                ++pwszSecondParameter;
 
             // Finally extract the desired Job ID.
 
             // Finally extract the desired Job ID.
-            dwJobID = wcstoul(p, NULL, 10);
+            dwJobID = wcstoul(pwszSecondParameter, NULL, 10);
             if (!IS_VALID_JOB_ID(dwJobID))
             {
                 // The user supplied an invalid Job ID.
             if (!IS_VALID_JOB_ID(dwJobID))
             {
                 // The user supplied an invalid Job ID.
@@ -640,70 +770,36 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
             pPrinterHandle->pStartedJob = pJob;
         }
 
             pPrinterHandle->pStartedJob = pJob;
         }
 
-        // Create a new handle that references a printer.
-        pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
-        pHandle->HandleType = Printer;
+        // Return the Printer handle through our general handle.
+        pHandle->HandleType = HandleType_Printer;
         pHandle->pSpecificHandle = pPrinterHandle;
     }
         pHandle->pSpecificHandle = pPrinterHandle;
     }
-    else
-    {
-        // No printer name, but we have a comma!
-        // This may be a request to a XcvMonitor or XcvPort handle.
-        ++p;
-
-        // Skip whitespace.
-        do
-        {
-            ++p;
-        }
-        while (*p == ' ');
-
-        // Check if this is a request to a XcvMonitor.
-        if (wcscmp(p, L"XcvMonitor ") == 0)
-        {
-            // Skip the "XcvMonitor " string. 
-            p += sizeof("XcvMonitor ") - 1;
-
-            ///////////// TODO /////////////////////
-            pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
-            pHandle->HandleType = Monitor;
-            //pHandle->pSpecificHandle = pMonitorHandle;
-        }
-        else if (wcscmp(p, L"XcvPort ") == 0)
-        {
-            // Skip the "XcvPort " string. 
-            p += sizeof("XcvPort ") - 1;
-
-            //////////// TODO //////////////////////
-            pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
-            pHandle->HandleType = Port;
-            //pHandle->pSpecificHandle = pPortHandle;
-        }
-        else
-        {
-            dwErrorCode = ERROR_INVALID_PRINTER_NAME;
-            goto Cleanup;
-        }
-    }
 
 
+    // We were successful! Return the handle.
     *phPrinter = (HANDLE)pHandle;
     dwErrorCode = ERROR_SUCCESS;
 
     // Don't let the cleanup routines free this.
     *phPrinter = (HANDLE)pHandle;
     dwErrorCode = ERROR_SUCCESS;
 
     // Don't let the cleanup routines free this.
+    pHandle = NULL;
     pPrinterHandle = NULL;
     pPrinterHandle = NULL;
-    pwszPrinterName = NULL;
 
 Cleanup:
 
 Cleanup:
+    if (pHandle)
+        DllFreeSplMem(pHandle);
+
     if (pPrinterHandle)
     {
         if (pPrinterHandle->pwszDatatype)
             DllFreeSplStr(pPrinterHandle->pwszDatatype);
 
     if (pPrinterHandle)
     {
         if (pPrinterHandle->pwszDatatype)
             DllFreeSplStr(pPrinterHandle->pwszDatatype);
 
+        if (pPrinterHandle->pDevMode)
+            DllFreeSplMem(pPrinterHandle->pDevMode);
+
         DllFreeSplMem(pPrinterHandle);
     }
 
         DllFreeSplMem(pPrinterHandle);
     }
 
-    if (pwszPrinterName)
-        DllFreeSplMem(pwszPrinterName);
+    if (pwszFirstParameter)
+        DllFreeSplMem(pwszFirstParameter);
 
     SetLastError(dwErrorCode);
     return (dwErrorCode == ERROR_SUCCESS);
 
     SetLastError(dwErrorCode);
     return (dwErrorCode == ERROR_SUCCESS);
@@ -734,7 +830,7 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
 
     // Check if this is a printer handle.
     pHandle = (PLOCAL_HANDLE)hPrinter;
-    if (pHandle->HandleType != Printer)
+    if (pHandle->HandleType != HandleType_Printer)
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
index e4bd6b3..5d6c178 100644 (file)
@@ -73,7 +73,7 @@ Cleanup:
 }
 
 BOOL
 }
 
 BOOL
-FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype)
+FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
 {
     DWORD i;
     PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1;
 {
     DWORD i;
     PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1;
@@ -90,7 +90,7 @@ FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype)
 }
 
 PLOCAL_PRINT_PROCESSOR
 }
 
 PLOCAL_PRINT_PROCESSOR
-FindPrintProcessor(PWSTR pwszName)
+FindPrintProcessor(PCWSTR pwszName)
 {
     PLIST_ENTRY pEntry;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor;
 {
     PLIST_ENTRY pEntry;
     PLOCAL_PRINT_PROCESSOR pPrintProcessor;