1 /*
2  * PROJECT:     ReactOS Spooler API
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions related to Print Monitors
5  * COPYRIGHT:   Copyright 2015-2018 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 #include <marshalling/monitors.h>
10 
11 BOOL WINAPI
12 AddMonitorA(PSTR pName, DWORD Level, PBYTE pMonitors)
13 {
14     LPWSTR  nameW = NULL;
15     INT     len;
16     BOOL    res;
17     LPMONITOR_INFO_2A mi2a;
18     MONITOR_INFO_2W mi2w;
19 
20     mi2a = (LPMONITOR_INFO_2A) pMonitors;
21     FIXME("AddMonitorA(%s, %d, %p) :  %s %s %s\n", debugstr_a(pName), Level, pMonitors,
22           debugstr_a(mi2a ? mi2a->pName : NULL),
23           debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
24           debugstr_a(mi2a ? mi2a->pDLLName : NULL));
25 
26     if  (Level != 2)
27     {
28         ERR("Level = %d, unsupported!\n", Level);
29         SetLastError(ERROR_INVALID_LEVEL);
30         return FALSE;
31     }
32 
33     /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
34     if (mi2a == NULL)
35     {
36         return FALSE;
37     }
38 
39     if (pName)
40     {
41         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
42         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
43         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
44     }
45 
46     memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
47     if (mi2a->pName)
48     {
49         len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
50         mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
51         MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
52     }
53     if (mi2a->pEnvironment)
54     {
55         len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
56         mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
57         MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
58     }
59     if (mi2a->pDLLName)
60     {
61         len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
62         mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
63         MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
64     }
65 
66     res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
67 
68     if (mi2w.pName) HeapFree(GetProcessHeap(), 0, mi2w.pName);
69     if (mi2w.pEnvironment) HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
70     if (mi2w.pDLLName) HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
71     if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
72 
73     return (res);
74 }
75 
76 BOOL WINAPI
77 AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors)
78 {
79     DWORD dwErrorCode;
80     WINSPOOL_MONITOR_CONTAINER MonitorInfoContainer;
81 
82     FIXME("AddMonitorW(%S, %lu, %p)\n", pName, Level, pMonitors);
83 
84     if (Level != 2)
85     {
86         ERR("Level = %d, unsupported!\n", Level);
87         SetLastError(ERROR_INVALID_LEVEL);
88         return FALSE;
89     }
90 
91     MonitorInfoContainer.MonitorInfo.pMonitorInfo2 = (WINSPOOL_MONITOR_INFO_2*)pMonitors;
92     MonitorInfoContainer.Level = Level;
93 
94     // Do the RPC call
95     RpcTryExcept
96     {
97         dwErrorCode = _RpcAddMonitor(pName, &MonitorInfoContainer);
98     }
99     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
100     {
101         dwErrorCode = RpcExceptionCode();
102         ERR("_RpcAddMonitor failed with exception code %lu!\n", dwErrorCode);
103     }
104     RpcEndExcept;
105 FIXME("AddMonitorW Error Code %lu\n", dwErrorCode);
106     SetLastError(dwErrorCode);
107     return (dwErrorCode == ERROR_SUCCESS);
108 }
109 
110 BOOL WINAPI
111 DeleteMonitorA(PSTR pName, PSTR pEnvironment, PSTR pMonitorName)
112 {
113     LPWSTR  nameW = NULL;
114     LPWSTR  EnvironmentW = NULL;
115     LPWSTR  MonitorNameW = NULL;
116     BOOL    res;
117     INT     len;
118 
119     TRACE("DeleteMonitorA(%s, %s, %s)\n", pName, pEnvironment, pMonitorName);
120 
121     if (pName) {
122         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
123         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
124         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
125     }
126 
127     if (pEnvironment) {
128         len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
129         EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
130         MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
131     }
132     if (pMonitorName) {
133         len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
134         MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
135         MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
136     }
137 
138     res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
139 
140     if (MonitorNameW) HeapFree(GetProcessHeap(), 0, MonitorNameW);
141     if (EnvironmentW) HeapFree(GetProcessHeap(), 0, EnvironmentW);
142     if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
143 
144     return (res);
145 }
146 
147 BOOL WINAPI
148 DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
149 {
150     DWORD dwErrorCode;
151 
152     FIXME("DeleteMonitorW(%S, %S, %S)\n", pName, pEnvironment, pMonitorName);
153 
154     // Do the RPC call
155     RpcTryExcept
156     {
157         dwErrorCode = _RpcDeleteMonitor(pName, pEnvironment, pMonitorName);
158     }
159     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
160     {
161         dwErrorCode = RpcExceptionCode();
162         ERR("_RpcDeleteMonitor failed with exception code %lu!\n", dwErrorCode);
163     }
164     RpcEndExcept;
165 
166     SetLastError(dwErrorCode);
167     return (dwErrorCode == ERROR_SUCCESS);
168 
169 }
170 
171 BOOL WINAPI
172 EnumMonitorsA(PSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
173 {
174     BOOL    res;
175     LPBYTE  bufferW = NULL;
176     LPWSTR  nameW = NULL;
177     DWORD   needed = 0;
178     DWORD   numentries = 0;
179     INT     len;
180 
181     FIXME("EnumMonitorsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
182 
183     if ( Level < 1 || Level > 2 )
184     {
185         ERR("Level = %d, unsupported!\n", Level);
186         SetLastError( ERROR_INVALID_LEVEL );
187         return FALSE;
188     }
189 
190     /* convert servername to unicode */
191     if (pName)
192     {
193         len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
194         nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
195         MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
196     }
197     /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
198     needed = cbBuf * sizeof(WCHAR);
199     if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
200     res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
201 
202     if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
203     {
204         if (pcbNeeded) needed = *pcbNeeded;
205         /* HeapReAlloc return NULL, when bufferW was NULL */
206         bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
207                               HeapAlloc(GetProcessHeap(), 0, needed);
208 
209         /* Try again with the large Buffer */
210         res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
211     }
212     numentries = pcReturned ? *pcReturned : 0;
213     needed = 0;
214     /*
215        W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
216        We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
217      */
218     if (res)
219     {
220         /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
221         DWORD   entrysize = 0;
222         DWORD   index;
223         LPSTR   ptr;
224         LPMONITOR_INFO_2W mi2w;
225         LPMONITOR_INFO_2A mi2a;
226 
227         /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
228         entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
229 
230         /* First pass: calculate the size for all Entries */
231         mi2w = (LPMONITOR_INFO_2W) bufferW;
232         mi2a = (LPMONITOR_INFO_2A) pMonitors;
233         index = 0;
234         while (index < numentries)
235         {
236             index++;
237             needed += entrysize;    /* MONITOR_INFO_?A */
238             TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
239 
240             needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
241                                             NULL, 0, NULL, NULL);
242             if (Level > 1)
243             {
244                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
245                                                 NULL, 0, NULL, NULL);
246                 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
247                                                 NULL, 0, NULL, NULL);
248             }
249             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
250             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
251             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
252         }
253 
254         /* check for errors and quit on failure */
255         if (cbBuf < needed)
256         {
257             SetLastError(ERROR_INSUFFICIENT_BUFFER);
258             res = FALSE;
259             goto emA_cleanup;
260         }
261         len = entrysize * numentries;       /* room for all MONITOR_INFO_?A */
262         ptr = (LPSTR) &pMonitors[len];      /* room for strings */
263         cbBuf -= len ;                      /* free Bytes in the user-Buffer */
264         mi2w = (LPMONITOR_INFO_2W) bufferW;
265         mi2a = (LPMONITOR_INFO_2A) pMonitors;
266         index = 0;
267         /* Second Pass: Fill the User Buffer (if we have one) */
268         while ((index < numentries) && pMonitors)
269         {
270             index++;
271             TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
272             mi2a->pName = ptr;
273             len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
274                                             ptr, cbBuf , NULL, NULL);
275             ptr += len;
276             cbBuf -= len;
277             if (Level > 1)
278             {
279                 mi2a->pEnvironment = ptr;
280                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
281                                             ptr, cbBuf, NULL, NULL);
282                 ptr += len;
283                 cbBuf -= len;
284 
285                 mi2a->pDLLName = ptr;
286                 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
287                                             ptr, cbBuf, NULL, NULL);
288                 ptr += len;
289                 cbBuf -= len;
290             }
291             /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
292             mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
293             mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
294         }
295     }
296 emA_cleanup:
297     if (pcbNeeded)  *pcbNeeded = needed;
298     if (pcReturned) *pcReturned = (res) ? numentries : 0;
299 
300     if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
301     if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
302 
303     FIXME("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries);
304 
305     return (res);
306 
307 }
308 
309 BOOL WINAPI
310 EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
311 {
312     DWORD dwErrorCode;
313 
314     FIXME("EnumMonitorsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
315 
316     if ( Level < 1 || Level > 2 )
317     {
318         ERR("Level = %d, unsupported!\n", Level);
319         SetLastError( ERROR_INVALID_LEVEL );
320         return FALSE;
321     }
322 
323     // Do the RPC call
324     RpcTryExcept
325     {
326         dwErrorCode = _RpcEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
327     }
328     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
329     {
330         dwErrorCode = RpcExceptionCode();
331         ERR("_RpcEnumMonitors failed with exception code %lu!\n", dwErrorCode);
332     }
333     RpcEndExcept;
334 
335     if (dwErrorCode == ERROR_SUCCESS)
336     {
337         // Replace relative offset addresses in the output by absolute pointers.
338         ASSERT(Level >= 1 && Level <= 2);
339         MarshallUpStructuresArray(cbBuf, pMonitors, *pcReturned, pMonitorInfoMarshalling[Level]->pInfo, pMonitorInfoMarshalling[Level]->cbStructureSize, TRUE);
340     }
341 
342     SetLastError(dwErrorCode);
343     return (dwErrorCode == ERROR_SUCCESS);
344 }
345