riched20: Fix one more memory leak.
[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  * enumerate the local Ports from the Registry (internal)  
53  *
54  * See localmon_EnumPortsW.
55  *
56  * NOTES
57  *  returns the needed size (in bytes) for pPorts
58  *  and *lpreturned is set to number of entries returned in pPorts
59  *
60  */
61
62 static DWORD get_ports_from_reg(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
63 {
64     HKEY    hroot = 0;
65     LPWSTR  ptr;
66     LPPORT_INFO_2W out;
67     WCHAR   portname[MAX_PATH];
68     WCHAR   res_PortW[32];
69     WCHAR   res_MonitorW[32];
70     INT     reslen_PortW;
71     INT     reslen_MonitorW;
72     DWORD   len;
73     DWORD   res;
74     DWORD   needed = 0;
75     DWORD   numentries;
76     DWORD   entrysize;
77     DWORD   id = 0;
78
79     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
80
81     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
82
83     numentries = *lpreturned;           /* this is 0, when we scan the registry */
84     needed = entrysize * numentries;
85     ptr = (LPWSTR) &pPorts[needed];
86
87     if (needed > cbBuf) pPorts = NULL;  /* No buffer for the structs */
88
89     numentries = 0;
90     needed = 0;
91
92     /* we do not check more parameters as done in windows */
93     if ((level < 1) || (level > 2)) {
94         goto getports_cleanup;
95     }
96
97     /* "+1" for '\0' */
98     reslen_MonitorW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALMONITOR, res_MonitorW, 32) + 1;  
99     reslen_PortW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALPORT, res_PortW, 32) + 1;  
100
101     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
102     if (res == ERROR_SUCCESS) {
103
104         /* Scan all Port-Names */
105         while (res == ERROR_SUCCESS) {
106             len = MAX_PATH;
107             portname[0] = '\0';
108             res = RegEnumValueW(hroot, id, portname, &len, NULL, NULL, NULL, NULL);
109
110             if ((res == ERROR_SUCCESS) && (portname[0])) {
111                 numentries++;
112                 /* calsulate the required size */
113                 needed += entrysize;
114                 needed += (len + 1) * sizeof(WCHAR);
115                 if (level > 1) {
116                     needed += (reslen_MonitorW + reslen_PortW) * sizeof(WCHAR);
117                 }
118
119                 /* Now fill the user-buffer, if available */
120                 if (pPorts && (cbBuf >= needed)){
121                     out = (LPPORT_INFO_2W) pPorts;
122                     pPorts += entrysize;
123                     TRACE("%p: writing PORT_INFO_%dW #%d (%s)\n", out, level, numentries, debugstr_w(portname));
124                     out->pPortName = ptr;
125                     lstrcpyW(ptr, portname);            /* Name of the Port */
126                     ptr += (len + 1);
127                     if (level > 1) {
128                         out->pMonitorName = ptr;
129                         lstrcpyW(ptr, res_MonitorW);    /* Name of the Monitor */
130                         ptr += reslen_MonitorW;
131
132                         out->pDescription = ptr;
133                         lstrcpyW(ptr, res_PortW);       /* Port Description */
134                         ptr += reslen_PortW;
135
136                         out->fPortType = PORT_TYPE_WRITE;
137                         out->Reserved = 0;
138                     }
139                 }
140                 id++;
141             }
142         }
143         RegCloseKey(hroot);
144     }
145     else
146     {
147         ERR("failed with %d for %s\n", res, debugstr_w(WinNT_CV_PortsW));
148         SetLastError(res);
149     }
150
151 getports_cleanup:
152     *lpreturned = numentries;
153     TRACE("need %d byte for %d entries (%d)\n", needed, numentries, GetLastError());
154     return needed;
155 }
156
157 /*****************************************************
158  *   localmon_EnumPortsW [exported through MONITOREX]
159  *
160  * Enumerate all local Ports
161  *
162  * PARAMS
163  *  pName       [I] Servername (ignored)
164  *  level       [I] Structure-Level (1 or 2)
165  *  pPorts      [O] PTR to Buffer that receives the Result
166  *  cbBuf       [I] Size of Buffer at pPorts
167  *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
168  *  pcReturned  [O] PTR to DWORD that receives the number of Ports in pPorts
169  *
170  * RETURNS
171  *  Success: TRUE
172  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
173  *
174  * NOTES
175  *|  Windows ignores pName
176  *|  Windows crash the app, when pPorts, pcbNeeded or pcReturned are NULL
177  *|  Windows >NT4.0 does not check for illegal levels (TRUE is returned)
178  *
179  * ToDo
180  *   "HCU\Software\Wine\Spooler\<portname>" - redirection
181  *
182  */
183 BOOL WINAPI localmon_EnumPortsW(LPWSTR pName, DWORD level, LPBYTE pPorts,
184                             DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
185 {
186     BOOL    res = FALSE;
187     DWORD   needed;
188     DWORD   numentries;
189
190     TRACE("(%s, %d, %p, %d, %p, %p)\n",
191           debugstr_w(pName), level, pPorts, cbBuf, pcbNeeded, pcReturned);
192
193     numentries = 0;
194     needed = get_ports_from_reg(level, NULL, 0, &numentries);
195     /* we calculated the needed buffersize. now do the error-checks */
196     if (cbBuf < needed) {
197         SetLastError(ERROR_INSUFFICIENT_BUFFER);
198         goto cleanup;
199     }
200
201     /* fill the buffer with the Port-Names */
202     needed = get_ports_from_reg(level, pPorts, cbBuf, &numentries);
203     res = TRUE;
204
205     if (pcReturned) *pcReturned = numentries;
206
207 cleanup:
208     if (pcbNeeded)  *pcbNeeded = needed;
209
210     TRACE("returning %d with %d (%d byte for %d entries)\n", 
211             res, GetLastError(), needed, numentries);
212
213     return (res);
214 }
215
216 /*****************************************************
217  *      InitializePrintMonitor  (LOCALSPL.@)
218  *
219  * Initialize the Monitor for the Local Ports
220  *
221  * PARAMS
222  *  regroot [I] Registry-Path, where the settings are stored
223  *
224  * RETURNS
225  *  Success: Pointer to a MONITOREX Structure
226  *  Failure: NULL
227  *
228  * NOTES
229  *  The fixed location "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports"
230  *  is used to store the Ports (IniFileMapping from "win.ini", Section "Ports").
231  *  Native localspl.dll fails, when no valid Port-Entry is present.
232  *
233  */
234
235 LPMONITOREX WINAPI InitializePrintMonitor(LPWSTR regroot)
236 {
237     static MONITOREX mymonitorex =
238     {
239         sizeof(MONITOREX) - sizeof(DWORD),
240         {
241             localmon_EnumPortsW
242         }
243     };
244
245     TRACE("(%s)\n", debugstr_w(regroot));
246     /* Parameter "regroot" is ignored on NT4.0 (localmon.dll) */
247     if (!regroot || !regroot[0]) {
248         SetLastError(ERROR_INVALID_PARAMETER);
249         return NULL;
250     }
251     TRACE("=> %p\n", &mymonitorex);
252     /* Native windows returns always the same pointer on success */
253     return &mymonitorex;
254 }