[LOCALSPL]
[reactos.git] / reactos / win32ss / printing / providers / localspl / ports.c
1 /*
2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions related to Ports of the Print Monitors
5 * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 // Local Variables
11 static LIST_ENTRY _PortList;
12
13
14 PLOCAL_PRINT_MONITOR
15 FindPrintMonitorByPort(PCWSTR pwszName)
16 {
17 PLIST_ENTRY pEntry;
18 PLOCAL_PORT pPort;
19
20 for (pEntry = _PortList.Flink; pEntry != &_PortList; pEntry = pEntry->Flink)
21 {
22 pPort = CONTAINING_RECORD(pEntry, LOCAL_PORT, Entry);
23
24 if (_wcsicmp(pPort->pwszName, pwszName) == 0)
25 return pPort->pPrintMonitor;
26 }
27
28 return NULL;
29 }
30
31 BOOL
32 InitializePortList()
33 {
34 BOOL bReturnValue;
35 DWORD cbNeeded;
36 DWORD cbPortName;
37 DWORD dwErrorCode;
38 DWORD dwReturned;
39 DWORD i;
40 PLOCAL_PORT pPort;
41 PLOCAL_PRINT_MONITOR pPrintMonitor;
42 PLIST_ENTRY pEntry;
43 PPORT_INFO_1W p;
44 PPORT_INFO_1W pPortInfo1 = NULL;
45
46 // Initialize an empty list for our Ports.
47 InitializeListHead(&_PortList);
48
49 // Loop through all Print Monitors.
50 for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
51 {
52 // Cleanup from the previous run.
53 if (pPortInfo1)
54 {
55 DllFreeSplMem(pPortInfo1);
56 pPortInfo1 = NULL;
57 }
58
59 pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
60
61 // Determine the required buffer size for EnumPorts.
62 if (pPrintMonitor->bIsLevel2)
63 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
64 else
65 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
66
67 // Check the returned error code.
68 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
69 {
70 ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
71 continue;
72 }
73
74 // Allocate a buffer large enough.
75 pPortInfo1 = DllAllocSplMem(cbNeeded);
76 if (!pPortInfo1)
77 {
78 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
79 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
80 goto Cleanup;
81 }
82
83 // Get the ports handled by this monitor.
84 if (pPrintMonitor->bIsLevel2)
85 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
86 else
87 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
88
89 // Check the return value.
90 if (!bReturnValue)
91 {
92 ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
93 continue;
94 }
95
96 // Loop through all returned ports.
97 p = pPortInfo1;
98
99 for (i = 0; i < dwReturned; i++)
100 {
101 cbPortName = (wcslen(p->pName) + 1) * sizeof(WCHAR);
102
103 // Create a new LOCAL_PORT structure for it.
104 pPort = DllAllocSplMem(sizeof(LOCAL_PORT) + cbPortName);
105 if (!pPort)
106 {
107 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
108 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
109 goto Cleanup;
110 }
111
112 pPort->pPrintMonitor = pPrintMonitor;
113 pPort->pwszName = (PWSTR)((PBYTE)pPort + sizeof(LOCAL_PORT));
114 CopyMemory(pPort->pwszName, p->pName, cbPortName);
115
116 // Insert it into the list and advance to the next port.
117 InsertTailList(&_PortList, &pPort->Entry);
118 p++;
119 }
120 }
121
122 dwErrorCode = ERROR_SUCCESS;
123
124 Cleanup:
125 // Inside the loop
126 if (pPortInfo1)
127 DllFreeSplMem(pPortInfo1);
128
129 SetLastError(dwErrorCode);
130 return (dwErrorCode == ERROR_SUCCESS);
131 }
132
133 BOOL WINAPI
134 LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
135 {
136 BOOL bReturnValue;
137 DWORD cbCallBuffer;
138 DWORD cbNeeded;
139 DWORD dwReturned;
140 PBYTE pCallBuffer;
141 PLOCAL_PRINT_MONITOR pPrintMonitor;
142 PLIST_ENTRY pEntry;
143
144 // Sanity checks.
145 if ((cbBuf && !pPorts) || !pcbNeeded || !pcReturned)
146 {
147 SetLastError(ERROR_INVALID_PARAMETER);
148 return FALSE;
149 }
150
151 // Begin counting.
152 *pcbNeeded = 0;
153 *pcReturned = 0;
154
155 // At the beginning, we have the full buffer available.
156 cbCallBuffer = cbBuf;
157 pCallBuffer = pPorts;
158
159 // Loop through all Print Monitors.
160 for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
161 {
162 pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
163
164 // Call the EnumPorts function of this Print Monitor.
165 if (pPrintMonitor->bIsLevel2)
166 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
167 else
168 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
169
170 // Add the returned counts to the total values.
171 *pcbNeeded += cbNeeded;
172 *pcReturned += dwReturned;
173
174 // Reduce the available buffer size for the next call without risking an underflow.
175 if (cbNeeded < cbCallBuffer)
176 cbCallBuffer -= cbNeeded;
177 else
178 cbCallBuffer = 0;
179
180 // Advance the buffer if the caller provided it.
181 if (pCallBuffer)
182 pCallBuffer += cbNeeded;
183 }
184
185 return bReturnValue;
186 }