localui: Implement ConfigurePortUI for COMx.
[wine] / dlls / localui / localui.c
1 /*
2  * Implementation of the Local Printmonitor User Interface
3  *
4  * Copyright 2007 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 NONAMELESSUNION
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winreg.h"
29 #include "winuser.h"
30
31 #include "winspool.h"
32 #include "ddk/winsplp.h"
33
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "localui.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(localui);
39
40 /*****************************************************/
41
42 static HINSTANCE LOCALUI_hInstance;
43
44 static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
45 static const WCHAR cmd_GetDefaultCommConfigW[] = {'G','e','t',
46                                     'D','e','f','a','u','l','t',
47                                     'C','o','m','m','C','o','n','f','i','g',0};
48 static const WCHAR cmd_SetDefaultCommConfigW[] = {'S','e','t',
49                                     'D','e','f','a','u','l','t',
50                                     'C','o','m','m','C','o','n','f','i','g',0};
51
52 static const WCHAR portname_LPT[]  = {'L','P','T',0};
53 static const WCHAR portname_COM[]  = {'C','O','M',0};
54 static const WCHAR portname_FILE[] = {'F','I','L','E',':',0};
55 static const WCHAR portname_CUPS[] = {'C','U','P','S',':',0};
56 static const WCHAR portname_LPR[]  = {'L','P','R',':',0};
57
58 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
59
60
61 /*****************************************************
62  *   strdupWW [internal]
63  */
64
65 static LPWSTR strdupWW(LPCWSTR pPrefix, LPCWSTR pSuffix)
66 {
67     LPWSTR  ptr;
68     DWORD   len;
69
70     len = lstrlenW(pPrefix) + (pSuffix ? lstrlenW(pSuffix) : 0) + 1;
71     ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
72     if (ptr) {
73         lstrcpyW(ptr, pPrefix);
74         if (pSuffix) lstrcatW(ptr, pSuffix);
75     }
76     return ptr;
77 }
78
79 /*****************************************************
80  *   dlg_configure_com [internal]
81  *
82  */
83
84 static BOOL dlg_configure_com(HANDLE hXcv, HWND hWnd, PCWSTR pPortName)
85 {
86     COMMCONFIG cfg;
87     LPWSTR shortname;
88     DWORD status;
89     DWORD dummy;
90     DWORD len;
91     BOOL  res;
92
93     /* strip the colon (pPortName is never empty here) */
94     len = lstrlenW(pPortName);
95     shortname = HeapAlloc(GetProcessHeap(), 0, len  * sizeof(WCHAR));
96     if (shortname) {
97         memcpy(shortname, pPortName, (len -1) * sizeof(WCHAR));
98         shortname[len-1] = '\0';
99
100         /* get current settings */
101         len = sizeof(cfg);
102         status = ERROR_SUCCESS;
103         res = XcvDataW( hXcv, cmd_GetDefaultCommConfigW,
104                         (PBYTE) shortname,
105                         (lstrlenW(shortname) +1) * sizeof(WCHAR),
106                         (PBYTE) &cfg, len, &len, &status);
107
108         if (res && (status == ERROR_SUCCESS)) {
109             /* display the Dialog */
110             res = CommConfigDialogW(pPortName, hWnd, &cfg);
111             if (res) {
112                 status = ERROR_SUCCESS;
113                 /* set new settings */
114                 res = XcvDataW(hXcv, cmd_SetDefaultCommConfigW,
115                                (PBYTE) &cfg, len,
116                                (PBYTE) &dummy, 0, &len, &status);
117             }
118         }
119         HeapFree(GetProcessHeap(), 0, shortname);
120         return res;
121     }
122     return FALSE;
123 }
124
125 /******************************************************************
126  * display the Dialog "Nothing to configure"
127  *
128  */
129
130 static void dlg_nothingtoconfig(HWND hWnd)
131 {
132     WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
133     WCHAR res_nothingW[IDS_NOTHINGTOCONFIG_MAXLEN];
134
135     res_PortW[0] = '\0';
136     res_nothingW[0] = '\0';
137     LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
138     LoadStringW(LOCALUI_hInstance, IDS_NOTHINGTOCONFIG, res_nothingW, IDS_NOTHINGTOCONFIG_MAXLEN);
139
140     MessageBoxW(hWnd, res_nothingW, res_PortW, MB_OK | MB_ICONINFORMATION);
141 }
142
143 /*****************************************************
144  * get_type_from_name (internal)
145  *
146  */
147
148 static DWORD get_type_from_name(LPCWSTR name)
149 {
150     HANDLE  hfile;
151
152     if (!strncmpiW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1))
153         return PORT_IS_LPT;
154
155     if (!strncmpiW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1))
156         return PORT_IS_COM;
157
158     if (!strcmpiW(name, portname_FILE))
159         return PORT_IS_FILE;
160
161     if (name[0] == '/')
162         return PORT_IS_UNIXNAME;
163
164     if (name[0] == '|')
165         return PORT_IS_PIPE;
166
167     if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1))
168         return PORT_IS_CUPS;
169
170     if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1))
171         return PORT_IS_LPR;
172
173     /* Must be a file or a directory. Does the file exist ? */
174     hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
175     TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name));
176     if (hfile == INVALID_HANDLE_VALUE) {
177         /* Can we create the file? */
178         hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
179         TRACE("%p for OPEN_ALWAYS\n", hfile);
180     }
181     if (hfile != INVALID_HANDLE_VALUE) {
182         CloseHandle(hfile);
183         return PORT_IS_FILENAME;
184     }
185     /* We can't use the name. use GetLastError() for the reason */
186     return PORT_IS_UNKNOWN;
187 }
188
189 /*****************************************************
190  *   open_monitor_by_name [internal]
191  *
192  */
193 static BOOL open_monitor_by_name(LPCWSTR pPrefix, LPCWSTR pPort, HANDLE * phandle)
194 {
195     PRINTER_DEFAULTSW pd;
196     LPWSTR  fullname;
197     BOOL    res;
198
199     * phandle = 0;
200     TRACE("(%s,%s)\n", debugstr_w(pPrefix),debugstr_w(pPort) );
201
202     fullname = strdupWW(pPrefix, pPort);
203     pd.pDatatype = NULL;
204     pd.pDevMode  = NULL;
205     pd.DesiredAccess = SERVER_ACCESS_ADMINISTER;
206
207     res = OpenPrinterW(fullname, phandle, &pd);
208     HeapFree(GetProcessHeap(), 0, fullname);
209     return res;
210 }
211
212 /*****************************************************
213  *   localui_AddPortUI [exported through MONITORUI]
214  *
215  * Display a Dialog to add a local Port
216  *
217  * PARAMS
218  *  pName       [I] Servername or NULL (local Computer)
219  *  hWnd        [I] Handle to parent Window for the Dialog-Box or NULL
220  *  pMonitorName[I] Name of the Monitor, that should be used to add a Port or NULL
221  *  ppPortName  [O] PTR to PTR of a buffer, that receive the Name of the new Port or NULL
222  *
223  * RETURNS
224  *  Success: TRUE
225  *  Failure: FALSE
226  *
227  */
228 static BOOL WINAPI localui_AddPortUI(PCWSTR pName, HWND hWnd, PCWSTR pMonitorName, PWSTR *ppPortName)
229 {
230     FIXME("(%s, %p, %s, %p) stub\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName), ppPortName);
231     return TRUE;
232 }
233
234
235 /*****************************************************
236  *   localui_ConfigurePortUI [exported through MONITORUI]
237  *
238  * Display the Configuration-Dialog for a specific Port
239  *
240  * PARAMS
241  *  pName     [I] Servername or NULL (local Computer)
242  *  hWnd      [I] Handle to parent Window for the Dialog-Box or NULL
243  *  pPortName [I] Name of the Port, that should be configured
244  *
245  * RETURNS
246  *  Success: TRUE
247  *  Failure: FALSE
248  *
249  */
250 static BOOL WINAPI localui_ConfigurePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
251 {
252     HANDLE  hXcv;
253     DWORD   res;
254
255     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
256     if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
257
258         res = get_type_from_name(pPortName);
259         switch(res)
260         {
261
262         case PORT_IS_COM:
263             res = dlg_configure_com(hXcv, hWnd, pPortName);
264             break;
265
266         default:
267             dlg_nothingtoconfig(hWnd);
268             SetLastError(ERROR_CANCELLED);
269             res = FALSE;
270         }
271
272         ClosePrinter(hXcv);
273         return res;
274     }
275     return FALSE;
276
277 }
278
279 /*****************************************************
280  *   localui_DeletePortUI [exported through MONITORUI]
281  *
282  * Delete a specific Port
283  *
284  * PARAMS
285  *  pName     [I] Servername or NULL (local Computer)
286  *  hWnd      [I] Handle to parent Window
287  *  pPortName [I] Name of the Port, that should be deleted
288  *
289  * RETURNS
290  *  Success: TRUE
291  *  Failure: FALSE
292  *
293  * NOTES
294  *  Native localui does not allow to delete a COM / LPT - Port (ERROR_NOT_SUPPORTED)
295  *
296  */
297 static BOOL WINAPI localui_DeletePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
298 {
299     HANDLE  hXcv;
300     DWORD   dummy;
301     DWORD   needed;
302     DWORD   status;
303
304     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
305
306     if ((!pPortName) || (!pPortName[0])) {
307         SetLastError(ERROR_INVALID_PARAMETER);
308         return FALSE;
309     }
310
311     if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
312         /* native localui tests here for LPT / COM - Ports and failed with
313            ERROR_NOT_SUPPORTED. */
314         if (XcvDataW(hXcv, cmd_DeletePortW, (LPBYTE) pPortName,
315             (lstrlenW(pPortName)+1) * sizeof(WCHAR), (LPBYTE) &dummy, 0, &needed, &status)) {
316
317             ClosePrinter(hXcv);
318             if (status != ERROR_SUCCESS) SetLastError(status);
319             return (status == ERROR_SUCCESS);
320         }
321         ClosePrinter(hXcv);
322         return FALSE;
323     }
324     SetLastError(ERROR_UNKNOWN_PORT);
325     return FALSE;
326 }
327
328 /*****************************************************
329  *      InitializePrintMonitorUI  (LOCALUI.@)
330  *
331  * Initialize the User-Interface for the Local Ports
332  *
333  * RETURNS
334  *  Success: Pointer to a MONITORUI Structure
335  *  Failure: NULL
336  *
337  */
338
339 PMONITORUI WINAPI InitializePrintMonitorUI(void)
340 {
341     static MONITORUI mymonitorui =
342     {
343         sizeof(MONITORUI),
344         localui_AddPortUI,
345         localui_ConfigurePortUI,
346         localui_DeletePortUI
347     };
348
349     TRACE("=> %p\n", &mymonitorui);
350     return &mymonitorui;
351 }
352
353 /*****************************************************
354  *      DllMain
355  */
356 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
357 {
358     TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
359
360     switch(fdwReason)
361     {
362         case DLL_WINE_PREATTACH:
363             return FALSE;           /* prefer native version */
364
365         case DLL_PROCESS_ATTACH:
366             DisableThreadLibraryCalls( hinstDLL );
367             LOCALUI_hInstance = hinstDLL;
368             break;
369     }
370     return TRUE;
371 }