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