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