wintrust: Implement WintrustLoadFunctionPointers.
[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_AddPortW[] = {'A','d','d','P','o','r','t',0};
45 static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
46 static const WCHAR cmd_GetDefaultCommConfigW[] = {'G','e','t',
47                                     'D','e','f','a','u','l','t',
48                                     'C','o','m','m','C','o','n','f','i','g',0};
49 static const WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
50 static const WCHAR cmd_SetDefaultCommConfigW[] = {'S','e','t',
51                                     'D','e','f','a','u','l','t',
52                                     'C','o','m','m','C','o','n','f','i','g',0};
53
54 static const WCHAR portname_LPT[]  = {'L','P','T',0};
55 static const WCHAR portname_COM[]  = {'C','O','M',0};
56 static const WCHAR portname_FILE[] = {'F','I','L','E',':',0};
57 static const WCHAR portname_CUPS[] = {'C','U','P','S',':',0};
58 static const WCHAR portname_LPR[]  = {'L','P','R',':',0};
59
60 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
61 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
62
63 /*****************************************************/
64
65 typedef struct tag_addportui_t {
66     LPWSTR  portname;
67     HANDLE  hXcv;
68 } addportui_t;
69
70 /*****************************************************
71  *   strdupWW [internal]
72  */
73
74 static LPWSTR strdupWW(LPCWSTR pPrefix, LPCWSTR pSuffix)
75 {
76     LPWSTR  ptr;
77     DWORD   len;
78
79     len = lstrlenW(pPrefix) + (pSuffix ? lstrlenW(pSuffix) : 0) + 1;
80     ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
81     if (ptr) {
82         lstrcpyW(ptr, pPrefix);
83         if (pSuffix) lstrcatW(ptr, pSuffix);
84     }
85     return ptr;
86 }
87
88 /*****************************************************
89  *   dlg_configure_com [internal]
90  *
91  */
92
93 static BOOL dlg_configure_com(HANDLE hXcv, HWND hWnd, PCWSTR pPortName)
94 {
95     COMMCONFIG cfg;
96     LPWSTR shortname;
97     DWORD status;
98     DWORD dummy;
99     DWORD len;
100     BOOL  res;
101
102     /* strip the colon (pPortName is never empty here) */
103     len = lstrlenW(pPortName);
104     shortname = HeapAlloc(GetProcessHeap(), 0, len  * sizeof(WCHAR));
105     if (shortname) {
106         memcpy(shortname, pPortName, (len -1) * sizeof(WCHAR));
107         shortname[len-1] = '\0';
108
109         /* get current settings */
110         len = sizeof(cfg);
111         status = ERROR_SUCCESS;
112         res = XcvDataW( hXcv, cmd_GetDefaultCommConfigW,
113                         (PBYTE) shortname,
114                         (lstrlenW(shortname) +1) * sizeof(WCHAR),
115                         (PBYTE) &cfg, len, &len, &status);
116
117         if (res && (status == ERROR_SUCCESS)) {
118             /* display the Dialog */
119             res = CommConfigDialogW(pPortName, hWnd, &cfg);
120             if (res) {
121                 status = ERROR_SUCCESS;
122                 /* set new settings */
123                 res = XcvDataW(hXcv, cmd_SetDefaultCommConfigW,
124                                (PBYTE) &cfg, len,
125                                (PBYTE) &dummy, 0, &len, &status);
126             }
127         }
128         HeapFree(GetProcessHeap(), 0, shortname);
129         return res;
130     }
131     return FALSE;
132 }
133
134 /******************************************************************
135  *  dlg_port_already_exists [internal]
136  */
137
138 static void dlg_port_already_exists(HWND hWnd, LPCWSTR portname)
139 {
140     WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
141     WCHAR res_PortExistsW[IDS_PORTEXISTS_MAXLEN];
142     LPWSTR  message;
143     DWORD   len;
144
145     res_PortW[0] = '\0';
146     res_PortExistsW[0] = '\0';
147     LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
148     LoadStringW(LOCALUI_hInstance, IDS_PORTEXISTS, res_PortExistsW, IDS_PORTEXISTS_MAXLEN);
149
150     len = lstrlenW(portname) + IDS_PORTEXISTS_MAXLEN + 1;
151     message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
152     if (message) {
153         message[0] = '\0';
154         snprintfW(message, len, res_PortExistsW, portname);
155         MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
156         HeapFree(GetProcessHeap(), 0, message);
157     }
158 }
159
160 /******************************************************************
161  *  dlg_invalid_portname [internal]
162  */
163
164 static void dlg_invalid_portname(HWND hWnd, LPCWSTR portname)
165 {
166     WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
167     WCHAR res_InvalidNameW[IDS_INVALIDNAME_MAXLEN];
168     LPWSTR  message;
169     DWORD   len;
170
171     res_PortW[0] = '\0';
172     res_InvalidNameW[0] = '\0';
173     LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
174     LoadStringW(LOCALUI_hInstance, IDS_INVALIDNAME, res_InvalidNameW, IDS_INVALIDNAME_MAXLEN);
175
176     len = lstrlenW(portname) + IDS_INVALIDNAME_MAXLEN;
177     message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
178     if (message) {
179         message[0] = '\0';
180         snprintfW(message, len, res_InvalidNameW, portname);
181         MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
182         HeapFree(GetProcessHeap(), 0, message);
183     }
184 }
185
186 /******************************************************************
187  * display the Dialog "Nothing to configure"
188  *
189  */
190
191 static void dlg_nothingtoconfig(HWND hWnd)
192 {
193     WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
194     WCHAR res_nothingW[IDS_NOTHINGTOCONFIG_MAXLEN];
195
196     res_PortW[0] = '\0';
197     res_nothingW[0] = '\0';
198     LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
199     LoadStringW(LOCALUI_hInstance, IDS_NOTHINGTOCONFIG, res_nothingW, IDS_NOTHINGTOCONFIG_MAXLEN);
200
201     MessageBoxW(hWnd, res_nothingW, res_PortW, MB_OK | MB_ICONINFORMATION);
202 }
203
204 /******************************************************************
205  *  dlg_win32error [internal]
206  */
207
208 static void dlg_win32error(HWND hWnd, DWORD lasterror)
209 {
210     WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
211     LPWSTR  message = NULL;
212     DWORD   res;
213
214     res_PortW[0] = '\0';
215     LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
216
217
218     res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
219                         NULL, lasterror, 0, (LPWSTR) &message, 0, NULL);
220
221     if (res > 0) {
222         MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
223         LocalFree(message);
224     }
225 }
226
227 /*****************************************************************************
228  *
229  */
230
231 static INT_PTR CALLBACK dlgproc_addport(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
232 {
233     addportui_t * data;
234     DWORD   status;
235     DWORD   dummy;
236     DWORD   len;
237     DWORD   res;
238
239     switch(msg)
240     {
241     case WM_INITDIALOG:
242         SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
243         return TRUE;
244
245     case WM_COMMAND:
246         if (wparam == MAKEWPARAM(IDOK, BN_CLICKED))
247         {
248             data = (addportui_t *) GetWindowLongPtrW(hwnd, DWLP_USER);
249             /* length in WCHAR, without the '\0' */
250             len = SendDlgItemMessageW(hwnd, ADDPORT_EDIT, WM_GETTEXTLENGTH, 0, 0);
251             data->portname = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
252
253             if (!data->portname) {
254                 EndDialog(hwnd, FALSE);
255                 return TRUE;
256             }
257             /* length is in WCHAR, including the '\0' */
258             GetDlgItemTextW(hwnd, ADDPORT_EDIT, data->portname, len + 1);
259             status = ERROR_SUCCESS;
260             res = XcvDataW( data->hXcv, cmd_PortIsValidW, (PBYTE) data->portname,
261                             (lstrlenW(data->portname) + 1) * sizeof(WCHAR),
262                             (PBYTE) &dummy, 0, &len, &status);
263
264             TRACE("got %u with status %u\n", res, status);
265             if (res && (status == ERROR_SUCCESS)) {
266                 /* The caller must free data->portname */
267                 EndDialog(hwnd, TRUE);
268                 return TRUE;
269             }
270
271             if (res && (status == ERROR_INVALID_NAME)) {
272                 dlg_invalid_portname(hwnd, data->portname);
273                 HeapFree(GetProcessHeap(), 0, data->portname);
274                 data->portname = NULL;
275                 return TRUE;
276             }
277
278             dlg_win32error(hwnd, status);
279             HeapFree(GetProcessHeap(), 0, data->portname);
280             data->portname = NULL;
281             return TRUE;
282         }
283
284         if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED))
285         {
286             EndDialog(hwnd, FALSE);
287             return TRUE;
288         }
289         return FALSE;
290     }
291     return FALSE;
292 }
293
294 /*****************************************************
295  * get_type_from_name (internal)
296  *
297  */
298
299 static DWORD get_type_from_name(LPCWSTR name)
300 {
301     HANDLE  hfile;
302
303     if (!strncmpiW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1))
304         return PORT_IS_LPT;
305
306     if (!strncmpiW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1))
307         return PORT_IS_COM;
308
309     if (!strcmpiW(name, portname_FILE))
310         return PORT_IS_FILE;
311
312     if (name[0] == '/')
313         return PORT_IS_UNIXNAME;
314
315     if (name[0] == '|')
316         return PORT_IS_PIPE;
317
318     if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1))
319         return PORT_IS_CUPS;
320
321     if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1))
322         return PORT_IS_LPR;
323
324     /* Must be a file or a directory. Does the file exist ? */
325     hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
326     TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name));
327     if (hfile == INVALID_HANDLE_VALUE) {
328         /* Can we create the file? */
329         hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
330         TRACE("%p for OPEN_ALWAYS\n", hfile);
331     }
332     if (hfile != INVALID_HANDLE_VALUE) {
333         CloseHandle(hfile);
334         return PORT_IS_FILENAME;
335     }
336     /* We can't use the name. use GetLastError() for the reason */
337     return PORT_IS_UNKNOWN;
338 }
339
340 /*****************************************************
341  *   open_monitor_by_name [internal]
342  *
343  */
344 static BOOL open_monitor_by_name(LPCWSTR pPrefix, LPCWSTR pPort, HANDLE * phandle)
345 {
346     PRINTER_DEFAULTSW pd;
347     LPWSTR  fullname;
348     BOOL    res;
349
350     * phandle = 0;
351     TRACE("(%s,%s)\n", debugstr_w(pPrefix),debugstr_w(pPort) );
352
353     fullname = strdupWW(pPrefix, pPort);
354     pd.pDatatype = NULL;
355     pd.pDevMode  = NULL;
356     pd.DesiredAccess = SERVER_ACCESS_ADMINISTER;
357
358     res = OpenPrinterW(fullname, phandle, &pd);
359     HeapFree(GetProcessHeap(), 0, fullname);
360     return res;
361 }
362
363 /*****************************************************
364  *   localui_AddPortUI [exported through MONITORUI]
365  *
366  * Display a Dialog to add a local Port
367  *
368  * PARAMS
369  *  pName       [I] Servername or NULL (local Computer)
370  *  hWnd        [I] Handle to parent Window for the Dialog-Box or NULL
371  *  pMonitorName[I] Name of the Monitor, that should be used to add a Port or NULL
372  *  ppPortName  [O] PTR to PTR of a buffer, that receive the Name of the new Port or NULL
373  *
374  * RETURNS
375  *  Success: TRUE
376  *  Failure: FALSE
377  *
378  * NOTES
379  * The caller must free the buffer (returned in ppPortName) with GlobalFree().
380  * Native localui.dll failed with ERROR_INVALID_PARAMETER, when the user tried
381  * to add a Port, that start with "COM" or "LPT".
382  *
383  */
384 static BOOL WINAPI localui_AddPortUI(PCWSTR pName, HWND hWnd, PCWSTR pMonitorName, PWSTR *ppPortName)
385 {
386     addportui_t data;
387     HANDLE  hXcv;
388     LPWSTR  ptr = NULL;
389     DWORD   needed;
390     DWORD   dummy;
391     DWORD   status;
392     DWORD   res = FALSE;
393
394     TRACE(  "(%s, %p, %s, %p) (*ppPortName: %p)\n", debugstr_w(pName), hWnd,
395             debugstr_w(pMonitorName), ppPortName, ppPortName ? *ppPortName : NULL);
396
397     if (open_monitor_by_name(XcvMonitorW, pMonitorName, &hXcv)) {
398
399         ZeroMemory(&data, sizeof(addportui_t));
400         data.hXcv = hXcv;
401         res = DialogBoxParamW(LOCALUI_hInstance, MAKEINTRESOURCEW(ADDPORT_DIALOG), hWnd,
402                                dlgproc_addport, (LPARAM) &data);
403
404         TRACE("got %u with %u for %s\n", res, GetLastError(), debugstr_w(data.portname));
405
406         if (ppPortName) *ppPortName = NULL;
407
408         if (res) {
409             res = XcvDataW(hXcv, cmd_AddPortW, (PBYTE) data.portname,
410                             (lstrlenW(data.portname)+1) * sizeof(WCHAR),
411                             (PBYTE) &dummy, 0, &needed, &status);
412
413             TRACE("got %u with status %u\n", res, status);
414             if (res && (status == ERROR_SUCCESS)) {
415                 /* Native localui uses GlobalAlloc also.
416                    The caller must GlobalFree the buffer */
417                 ptr = GlobalAlloc(GPTR, (lstrlenW(data.portname)+1) * sizeof(WCHAR));
418                 if (ptr) {
419                     lstrcpyW(ptr, data.portname);
420                     if (ppPortName) *ppPortName = ptr;
421                 }
422             }
423
424             if (res && (status == ERROR_ALREADY_EXISTS)) {
425                 dlg_port_already_exists(hWnd, data.portname);
426                 /* Native localui also return "TRUE" from AddPortUI in this case */
427             }
428
429             HeapFree(GetProcessHeap(), 0, data.portname);
430         }
431         else
432         {
433             SetLastError(ERROR_CANCELLED);
434         }
435         ClosePrinter(hXcv);
436     }
437
438     TRACE("=> %u with %u\n", res, GetLastError());
439     return res;
440 }
441
442
443 /*****************************************************
444  *   localui_ConfigurePortUI [exported through MONITORUI]
445  *
446  * Display the Configuration-Dialog for a specific Port
447  *
448  * PARAMS
449  *  pName     [I] Servername or NULL (local Computer)
450  *  hWnd      [I] Handle to parent Window for the Dialog-Box or NULL
451  *  pPortName [I] Name of the Port, that should be configured
452  *
453  * RETURNS
454  *  Success: TRUE
455  *  Failure: FALSE
456  *
457  */
458 static BOOL WINAPI localui_ConfigurePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
459 {
460     HANDLE  hXcv;
461     DWORD   res;
462
463     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
464     if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
465
466         res = get_type_from_name(pPortName);
467         switch(res)
468         {
469
470         case PORT_IS_COM:
471             res = dlg_configure_com(hXcv, hWnd, pPortName);
472             break;
473
474         default:
475             dlg_nothingtoconfig(hWnd);
476             SetLastError(ERROR_CANCELLED);
477             res = FALSE;
478         }
479
480         ClosePrinter(hXcv);
481         return res;
482     }
483     return FALSE;
484
485 }
486
487 /*****************************************************
488  *   localui_DeletePortUI [exported through MONITORUI]
489  *
490  * Delete a specific Port
491  *
492  * PARAMS
493  *  pName     [I] Servername or NULL (local Computer)
494  *  hWnd      [I] Handle to parent Window
495  *  pPortName [I] Name of the Port, that should be deleted
496  *
497  * RETURNS
498  *  Success: TRUE
499  *  Failure: FALSE
500  *
501  * NOTES
502  *  Native localui does not allow to delete a COM / LPT - Port (ERROR_NOT_SUPPORTED)
503  *
504  */
505 static BOOL WINAPI localui_DeletePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
506 {
507     HANDLE  hXcv;
508     DWORD   dummy;
509     DWORD   needed;
510     DWORD   status;
511
512     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
513
514     if ((!pPortName) || (!pPortName[0])) {
515         SetLastError(ERROR_INVALID_PARAMETER);
516         return FALSE;
517     }
518
519     if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
520         /* native localui tests here for LPT / COM - Ports and failed with
521            ERROR_NOT_SUPPORTED. */
522         if (XcvDataW(hXcv, cmd_DeletePortW, (LPBYTE) pPortName,
523             (lstrlenW(pPortName)+1) * sizeof(WCHAR), (LPBYTE) &dummy, 0, &needed, &status)) {
524
525             ClosePrinter(hXcv);
526             if (status != ERROR_SUCCESS) SetLastError(status);
527             return (status == ERROR_SUCCESS);
528         }
529         ClosePrinter(hXcv);
530         return FALSE;
531     }
532     SetLastError(ERROR_UNKNOWN_PORT);
533     return FALSE;
534 }
535
536 /*****************************************************
537  *      InitializePrintMonitorUI  (LOCALUI.@)
538  *
539  * Initialize the User-Interface for the Local Ports
540  *
541  * RETURNS
542  *  Success: Pointer to a MONITORUI Structure
543  *  Failure: NULL
544  *
545  */
546
547 PMONITORUI WINAPI InitializePrintMonitorUI(void)
548 {
549     static MONITORUI mymonitorui =
550     {
551         sizeof(MONITORUI),
552         localui_AddPortUI,
553         localui_ConfigurePortUI,
554         localui_DeletePortUI
555     };
556
557     TRACE("=> %p\n", &mymonitorui);
558     return &mymonitorui;
559 }
560
561 /*****************************************************
562  *      DllMain
563  */
564 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
565 {
566     TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
567
568     switch(fdwReason)
569     {
570         case DLL_WINE_PREATTACH:
571             return FALSE;           /* prefer native version */
572
573         case DLL_PROCESS_ATTACH:
574             DisableThreadLibraryCalls( hinstDLL );
575             LOCALUI_hInstance = hinstDLL;
576             break;
577     }
578     return TRUE;
579 }