localspl/tests: Extend test for XcvDataPort_MonitorUI.
[wine] / dlls / localspl / localmon.c
1 /*
2  * Implementation of the Local Printmonitor
3  *
4  * Copyright 2006 Detlef Riekenberg
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "winver.h"
32 #include "winnls.h"
33
34 #include "winspool.h"
35 #include "ddk/winsplp.h"
36 #include "localspl_private.h"
37
38 #include "wine/debug.h"
39
40
41 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
42
43 /*****************************************************/
44
45 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
46                                         'M','i','c','r','o','s','o','f','t','\\',
47                                         'W','i','n','d','o','w','s',' ','N','T','\\',
48                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
49                                         'P','o','r','t','s',0};
50
51 /******************************************************************
52  * display the Dialog "Nothing to configure"
53  * 
54  */
55
56 static void dlg_nothingtoconfig(HWND hWnd)
57 {
58     WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
59     WCHAR res_nothingW[IDS_NOTHINGTOCONFIG_MAXLEN];
60
61     res_PortW[0] = '\0';
62     res_nothingW[0] = '\0';
63     LoadStringW(LOCALSPL_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);  
64     LoadStringW(LOCALSPL_hInstance, IDS_NOTHINGTOCONFIG, res_nothingW, IDS_NOTHINGTOCONFIG_MAXLEN);  
65
66     MessageBoxW(hWnd, res_nothingW, res_PortW, MB_OK | MB_ICONINFORMATION);
67 }
68
69 /******************************************************************
70  * enumerate the local Ports from the Registry (internal)  
71  *
72  * See localmon_EnumPortsW.
73  *
74  * NOTES
75  *  returns the needed size (in bytes) for pPorts
76  *  and *lpreturned is set to number of entries returned in pPorts
77  *
78  */
79
80 static DWORD get_ports_from_reg(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
81 {
82     HKEY    hroot = 0;
83     LPWSTR  ptr;
84     LPPORT_INFO_2W out;
85     WCHAR   portname[MAX_PATH];
86     WCHAR   res_PortW[IDS_LOCALPORT_MAXLEN];
87     WCHAR   res_MonitorW[IDS_LOCALMONITOR_MAXLEN];
88     INT     reslen_PortW;
89     INT     reslen_MonitorW;
90     DWORD   len;
91     DWORD   res;
92     DWORD   needed = 0;
93     DWORD   numentries;
94     DWORD   entrysize;
95     DWORD   id = 0;
96
97     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
98
99     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
100
101     numentries = *lpreturned;           /* this is 0, when we scan the registry */
102     needed = entrysize * numentries;
103     ptr = (LPWSTR) &pPorts[needed];
104
105     if (needed > cbBuf) pPorts = NULL;  /* No buffer for the structs */
106
107     numentries = 0;
108     needed = 0;
109
110     /* we do not check more parameters as done in windows */
111     if ((level < 1) || (level > 2)) {
112         goto getports_cleanup;
113     }
114
115     /* "+1" for '\0' */
116     reslen_MonitorW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALMONITOR, res_MonitorW, IDS_LOCALMONITOR_MAXLEN) + 1;  
117     reslen_PortW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN) + 1;  
118
119     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
120     if (res == ERROR_SUCCESS) {
121
122         /* Scan all Port-Names */
123         while (res == ERROR_SUCCESS) {
124             len = MAX_PATH;
125             portname[0] = '\0';
126             res = RegEnumValueW(hroot, id, portname, &len, NULL, NULL, NULL, NULL);
127
128             if ((res == ERROR_SUCCESS) && (portname[0])) {
129                 numentries++;
130                 /* calsulate the required size */
131                 needed += entrysize;
132                 needed += (len + 1) * sizeof(WCHAR);
133                 if (level > 1) {
134                     needed += (reslen_MonitorW + reslen_PortW) * sizeof(WCHAR);
135                 }
136
137                 /* Now fill the user-buffer, if available */
138                 if (pPorts && (cbBuf >= needed)){
139                     out = (LPPORT_INFO_2W) pPorts;
140                     pPorts += entrysize;
141                     TRACE("%p: writing PORT_INFO_%dW #%d (%s)\n", out, level, numentries, debugstr_w(portname));
142                     out->pPortName = ptr;
143                     lstrcpyW(ptr, portname);            /* Name of the Port */
144                     ptr += (len + 1);
145                     if (level > 1) {
146                         out->pMonitorName = ptr;
147                         lstrcpyW(ptr, res_MonitorW);    /* Name of the Monitor */
148                         ptr += reslen_MonitorW;
149
150                         out->pDescription = ptr;
151                         lstrcpyW(ptr, res_PortW);       /* Port Description */
152                         ptr += reslen_PortW;
153
154                         out->fPortType = PORT_TYPE_WRITE;
155                         out->Reserved = 0;
156                     }
157                 }
158                 id++;
159             }
160         }
161         RegCloseKey(hroot);
162     }
163     else
164     {
165         ERR("failed with %d for %s\n", res, debugstr_w(WinNT_CV_PortsW));
166         SetLastError(res);
167     }
168
169 getports_cleanup:
170     *lpreturned = numentries;
171     TRACE("need %d byte for %d entries (%d)\n", needed, numentries, GetLastError());
172     return needed;
173 }
174
175 /*****************************************************
176  *   localmon_ConfigurePortW [exported through MONITOREX]
177  *
178  * Display the Configuration-Dialog for a specific Port
179  *
180  * PARAMS
181  *  pName     [I] Servername or NULL (local Computer)
182  *  hWnd      [I] Handle to parent Window for the Dialog-Box
183  *  pPortName [I] Name of the Port, that should be configured
184  *
185  * RETURNS
186  *  Success: TRUE
187  *  Failure: FALSE
188  *
189  */
190 BOOL WINAPI localmon_ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
191 {
192     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
193     /* ToDo: Dialogs by Portname ("LPTx:", "COMx:") */
194
195     dlg_nothingtoconfig(hWnd);
196     return ROUTER_SUCCESS;
197 }
198
199 /*****************************************************
200  *   localmon_DeletePortW [exported through MONITOREX]
201  *
202  * Delete a specific Port
203  *
204  * PARAMS
205  *  pName     [I] Servername or NULL (local Computer)
206  *  hWnd      [I] Handle to parent Window
207  *  pPortName [I] Name of the Port, that should be deleted
208  *
209  * RETURNS
210  *  Success: TRUE
211  *  Failure: FALSE
212  *
213  */
214 BOOL WINAPI localmon_DeletePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
215 {
216     DWORD   res;
217     HKEY    hroot;
218
219     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
220
221     if ((!pPortName) || (!pPortName[0])) return FALSE;
222
223     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
224     if (res == ERROR_SUCCESS) {
225         res = RegDeleteValueW(hroot, pPortName);
226         RegCloseKey(hroot);
227     }
228     TRACE("=> %d\n", (res == ERROR_SUCCESS));
229     return (res == ERROR_SUCCESS);
230 }
231
232 /*****************************************************
233  *   localmon_EnumPortsW [exported through MONITOREX]
234  *
235  * Enumerate all local Ports
236  *
237  * PARAMS
238  *  pName       [I] Servername (ignored)
239  *  level       [I] Structure-Level (1 or 2)
240  *  pPorts      [O] PTR to Buffer that receives the Result
241  *  cbBuf       [I] Size of Buffer at pPorts
242  *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
243  *  pcReturned  [O] PTR to DWORD that receives the number of Ports in pPorts
244  *
245  * RETURNS
246  *  Success: TRUE
247  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
248  *
249  * NOTES
250  *|  Windows ignores pName
251  *|  Windows crash the app, when pPorts, pcbNeeded or pcReturned are NULL
252  *|  Windows >NT4.0 does not check for illegal levels (TRUE is returned)
253  *
254  * ToDo
255  *   "HCU\Software\Wine\Spooler\<portname>" - redirection
256  *
257  */
258 BOOL WINAPI localmon_EnumPortsW(LPWSTR pName, DWORD level, LPBYTE pPorts,
259                             DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
260 {
261     BOOL    res = FALSE;
262     DWORD   needed;
263     DWORD   numentries;
264
265     TRACE("(%s, %d, %p, %d, %p, %p)\n",
266           debugstr_w(pName), level, pPorts, cbBuf, pcbNeeded, pcReturned);
267
268     numentries = 0;
269     needed = get_ports_from_reg(level, NULL, 0, &numentries);
270     /* we calculated the needed buffersize. now do the error-checks */
271     if (cbBuf < needed) {
272         SetLastError(ERROR_INSUFFICIENT_BUFFER);
273         goto cleanup;
274     }
275
276     /* fill the buffer with the Port-Names */
277     needed = get_ports_from_reg(level, pPorts, cbBuf, &numentries);
278     res = TRUE;
279
280     if (pcReturned) *pcReturned = numentries;
281
282 cleanup:
283     if (pcbNeeded)  *pcbNeeded = needed;
284
285     TRACE("returning %d with %d (%d byte for %d entries)\n", 
286             res, GetLastError(), needed, numentries);
287
288     return (res);
289 }
290
291 /*****************************************************
292  *      InitializePrintMonitor  (LOCALSPL.@)
293  *
294  * Initialize the Monitor for the Local Ports
295  *
296  * PARAMS
297  *  regroot [I] Registry-Path, where the settings are stored
298  *
299  * RETURNS
300  *  Success: Pointer to a MONITOREX Structure
301  *  Failure: NULL
302  *
303  * NOTES
304  *  The fixed location "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports"
305  *  is used to store the Ports (IniFileMapping from "win.ini", Section "Ports").
306  *  Native localspl.dll fails, when no valid Port-Entry is present.
307  *
308  */
309
310 LPMONITOREX WINAPI InitializePrintMonitor(LPWSTR regroot)
311 {
312     static MONITOREX mymonitorex =
313     {
314         sizeof(MONITOREX) - sizeof(DWORD),
315         {
316             localmon_EnumPortsW,
317             NULL,       /* localmon_OpenPortW */ 
318             NULL,       /* localmon_OpenPortExW */ 
319             NULL,       /* localmon_StartDocPortW */
320             NULL,       /* localmon_WritePortW */
321             NULL,       /* localmon_ReadPortW */
322             NULL,       /* localmon_EndDocPortW */
323             NULL,       /* localmon_ClosePortW */
324             NULL,       /* localmon_AddPortW */
325             NULL,       /* localmon_AddPortExW */
326             localmon_ConfigurePortW,
327             localmon_DeletePortW
328         }
329     };
330
331     TRACE("(%s)\n", debugstr_w(regroot));
332     /* Parameter "regroot" is ignored on NT4.0 (localmon.dll) */
333     if (!regroot || !regroot[0]) {
334         SetLastError(ERROR_INVALID_PARAMETER);
335         return NULL;
336     }
337     TRACE("=> %p\n", &mymonitorex);
338     /* Native windows returns always the same pointer on success */
339     return &mymonitorex;
340 }