2 * Implementation of the Local Printmonitor User Interface
4 * Copyright 2007 Detlef Riekenberg
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.
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.
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
21 #define WIN32_NO_STATUS
25 #define NONAMELESSUNION
34 #include <ddk/winsplp.h>
36 #include <wine/debug.h>
37 #include <wine/unicode.h>
40 WINE_DEFAULT_DEBUG_CHANNEL(localui
);
42 /*****************************************************/
44 static HINSTANCE LOCALUI_hInstance
;
46 static const WCHAR cmd_AddPortW
[] = {'A','d','d','P','o','r','t',0};
47 static const WCHAR cmd_ConfigureLPTPortCommandOKW
[] = {'C','o','n','f','i','g','u','r','e',
48 'L','P','T','P','o','r','t',
49 'C','o','m','m','a','n','d','O','K',0};
50 static const WCHAR cmd_DeletePortW
[] = {'D','e','l','e','t','e','P','o','r','t',0};
51 static const WCHAR cmd_GetDefaultCommConfigW
[] = {'G','e','t',
52 'D','e','f','a','u','l','t',
53 'C','o','m','m','C','o','n','f','i','g',0};
54 static const WCHAR cmd_GetTransmissionRetryTimeoutW
[] = {'G','e','t',
55 'T','r','a','n','s','m','i','s','s','i','o','n',
56 'R','e','t','r','y','T','i','m','e','o','u','t',0};
57 static const WCHAR cmd_PortIsValidW
[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
58 static const WCHAR cmd_SetDefaultCommConfigW
[] = {'S','e','t',
59 'D','e','f','a','u','l','t',
60 'C','o','m','m','C','o','n','f','i','g',0};
62 static const WCHAR fmt_uW
[] = {'%','u',0};
63 static const WCHAR portname_LPT
[] = {'L','P','T',0};
64 static const WCHAR portname_COM
[] = {'C','O','M',0};
65 static const WCHAR portname_FILE
[] = {'F','I','L','E',':',0};
66 static const WCHAR portname_CUPS
[] = {'C','U','P','S',':',0};
67 static const WCHAR portname_LPR
[] = {'L','P','R',':',0};
69 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
70 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
72 /*****************************************************/
74 typedef struct tag_addportui_t
{
79 typedef struct tag_lptconfig_t
{
85 static INT_PTR CALLBACK
dlgproc_lptconfig(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
);
87 /*****************************************************
91 static LPWSTR
strdupWW(LPCWSTR pPrefix
, LPCWSTR pSuffix
)
96 len
= lstrlenW(pPrefix
) + (pSuffix
? lstrlenW(pSuffix
) : 0) + 1;
97 ptr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
99 lstrcpyW(ptr
, pPrefix
);
100 if (pSuffix
) lstrcatW(ptr
, pSuffix
);
105 /*****************************************************
106 * dlg_configure_com [internal]
110 static BOOL
dlg_configure_com(HANDLE hXcv
, HWND hWnd
, PCWSTR pPortName
)
119 /* strip the colon (pPortName is never empty here) */
120 len
= lstrlenW(pPortName
);
121 shortname
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
123 memcpy(shortname
, pPortName
, (len
-1) * sizeof(WCHAR
));
124 shortname
[len
-1] = '\0';
126 /* get current settings */
127 len
= FIELD_OFFSET(COMMCONFIG
, wcProviderData
[1]);
128 status
= ERROR_SUCCESS
;
129 res
= XcvDataW( hXcv
, cmd_GetDefaultCommConfigW
,
131 (lstrlenW(shortname
) +1) * sizeof(WCHAR
),
132 (PBYTE
) &cfg
, len
, &len
, &status
);
134 if (res
&& (status
== ERROR_SUCCESS
)) {
135 /* display the Dialog */
136 res
= CommConfigDialogW(pPortName
, hWnd
, &cfg
);
138 status
= ERROR_SUCCESS
;
139 /* set new settings */
140 res
= XcvDataW(hXcv
, cmd_SetDefaultCommConfigW
,
142 (PBYTE
) &dummy
, 0, &len
, &status
);
145 HeapFree(GetProcessHeap(), 0, shortname
);
152 /*****************************************************
153 * dlg_configure_lpt [internal]
157 static BOOL
dlg_configure_lpt(HANDLE hXcv
, HWND hWnd
)
165 res
= DialogBoxParamW(LOCALUI_hInstance
, MAKEINTRESOURCEW(LPTCONFIG_DIALOG
), hWnd
,
166 dlgproc_lptconfig
, (LPARAM
) &data
);
168 TRACE("got %u with %u\n", res
, GetLastError());
170 if (!res
) SetLastError(ERROR_CANCELLED
);
174 /******************************************************************
175 * dlg_port_already_exists [internal]
178 static void dlg_port_already_exists(HWND hWnd
, LPCWSTR portname
)
180 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
181 WCHAR res_PortExistsW
[IDS_PORTEXISTS_MAXLEN
];
186 res_PortExistsW
[0] = '\0';
187 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
188 LoadStringW(LOCALUI_hInstance
, IDS_PORTEXISTS
, res_PortExistsW
, IDS_PORTEXISTS_MAXLEN
);
190 len
= lstrlenW(portname
) + IDS_PORTEXISTS_MAXLEN
+ 1;
191 message
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
194 snprintfW(message
, len
, res_PortExistsW
, portname
);
195 MessageBoxW(hWnd
, message
, res_PortW
, MB_OK
| MB_ICONERROR
);
196 HeapFree(GetProcessHeap(), 0, message
);
200 /******************************************************************
201 * dlg_invalid_portname [internal]
204 static void dlg_invalid_portname(HWND hWnd
, LPCWSTR portname
)
206 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
207 WCHAR res_InvalidNameW
[IDS_INVALIDNAME_MAXLEN
];
212 res_InvalidNameW
[0] = '\0';
213 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
214 LoadStringW(LOCALUI_hInstance
, IDS_INVALIDNAME
, res_InvalidNameW
, IDS_INVALIDNAME_MAXLEN
);
216 len
= lstrlenW(portname
) + IDS_INVALIDNAME_MAXLEN
;
217 message
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
220 snprintfW(message
, len
, res_InvalidNameW
, portname
);
221 MessageBoxW(hWnd
, message
, res_PortW
, MB_OK
| MB_ICONERROR
);
222 HeapFree(GetProcessHeap(), 0, message
);
226 /******************************************************************
227 * display the Dialog "Nothing to configure"
231 static void dlg_nothingtoconfig(HWND hWnd
)
233 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
234 WCHAR res_nothingW
[IDS_NOTHINGTOCONFIG_MAXLEN
];
237 res_nothingW
[0] = '\0';
238 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
239 LoadStringW(LOCALUI_hInstance
, IDS_NOTHINGTOCONFIG
, res_nothingW
, IDS_NOTHINGTOCONFIG_MAXLEN
);
241 MessageBoxW(hWnd
, res_nothingW
, res_PortW
, MB_OK
| MB_ICONINFORMATION
);
244 /******************************************************************
245 * dlg_win32error [internal]
248 static void dlg_win32error(HWND hWnd
, DWORD lasterror
)
250 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
251 LPWSTR message
= NULL
;
255 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
258 res
= FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
259 NULL
, lasterror
, 0, (LPWSTR
) &message
, 0, NULL
);
262 MessageBoxW(hWnd
, message
, res_PortW
, MB_OK
| MB_ICONERROR
);
267 /*****************************************************************************
271 static INT_PTR CALLBACK
dlgproc_addport(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
282 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
286 if (wparam
== MAKEWPARAM(IDOK
, BN_CLICKED
))
288 data
= (addportui_t
*) GetWindowLongPtrW(hwnd
, DWLP_USER
);
289 /* length in WCHAR, without the '\0' */
290 len
= SendDlgItemMessageW(hwnd
, ADDPORT_EDIT
, WM_GETTEXTLENGTH
, 0, 0);
291 data
->portname
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
293 if (!data
->portname
) {
294 EndDialog(hwnd
, FALSE
);
297 /* length is in WCHAR, including the '\0' */
298 GetDlgItemTextW(hwnd
, ADDPORT_EDIT
, data
->portname
, len
+ 1);
299 status
= ERROR_SUCCESS
;
300 res
= XcvDataW( data
->hXcv
, cmd_PortIsValidW
, (PBYTE
) data
->portname
,
301 (lstrlenW(data
->portname
) + 1) * sizeof(WCHAR
),
302 (PBYTE
) &dummy
, 0, &len
, &status
);
304 TRACE("got %u with status %u\n", res
, status
);
305 if (res
&& (status
== ERROR_SUCCESS
)) {
306 /* The caller must free data->portname */
307 EndDialog(hwnd
, TRUE
);
311 if (res
&& (status
== ERROR_INVALID_NAME
)) {
312 dlg_invalid_portname(hwnd
, data
->portname
);
313 HeapFree(GetProcessHeap(), 0, data
->portname
);
314 data
->portname
= NULL
;
318 dlg_win32error(hwnd
, status
);
319 HeapFree(GetProcessHeap(), 0, data
->portname
);
320 data
->portname
= NULL
;
324 if (wparam
== MAKEWPARAM(IDCANCEL
, BN_CLICKED
))
326 EndDialog(hwnd
, FALSE
);
334 /*****************************************************************************
335 * dlgproc_lptconfig [internal]
337 * Our message-proc is simple, as the range-check is done only during the
338 * command "OK" and the dialog is set to the start-value at "out of range".
340 * Native localui.dll does the check during keyboard-input and set the dialog
341 * to the previous value.
345 static INT_PTR CALLBACK
dlgproc_lptconfig(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
358 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
359 data
= (lptconfig_t
*) lparam
;
361 /* Get current setting */
363 status
= ERROR_SUCCESS
;
364 res
= XcvDataW( data
->hXcv
, cmd_GetTransmissionRetryTimeoutW
,
366 (PBYTE
) &data
->value
, sizeof(data
->value
), &len
, &status
);
368 TRACE("got %u with status %u\n", res
, status
);
370 /* Set current setting as the initial value in the Dialog */
371 SetDlgItemInt(hwnd
, LPTCONFIG_EDIT
, data
->value
, FALSE
);
375 if (wparam
== MAKEWPARAM(IDOK
, BN_CLICKED
))
377 data
= (lptconfig_t
*) GetWindowLongPtrW(hwnd
, DWLP_USER
);
380 res
= GetDlgItemInt(hwnd
, LPTCONFIG_EDIT
, (BOOL
*) &status
, FALSE
);
381 /* length is in WCHAR, including the '\0' */
382 GetDlgItemTextW(hwnd
, LPTCONFIG_EDIT
, bufferW
, sizeof(bufferW
) / sizeof(bufferW
[0]));
383 TRACE("got %s and %u (translated: %u)\n", debugstr_w(bufferW
), res
, status
);
385 /* native localui.dll use the same limits */
386 if ((res
> 0) && (res
< 1000000) && status
) {
387 sprintfW(bufferW
, fmt_uW
, res
);
388 res
= XcvDataW( data
->hXcv
, cmd_ConfigureLPTPortCommandOKW
,
390 (lstrlenW(bufferW
) +1) * sizeof(WCHAR
),
391 (PBYTE
) &dummy
, 0, &len
, &status
);
393 TRACE("got %u with status %u\n", res
, status
);
394 EndDialog(hwnd
, TRUE
);
398 /* Set initial value and rerun the Dialog */
399 SetDlgItemInt(hwnd
, LPTCONFIG_EDIT
, data
->value
, FALSE
);
403 if (wparam
== MAKEWPARAM(IDCANCEL
, BN_CLICKED
))
405 EndDialog(hwnd
, FALSE
);
414 /*****************************************************
415 * get_type_from_name (internal)
419 static DWORD
get_type_from_name(LPCWSTR name
)
423 if (!strncmpiW(name
, portname_LPT
, sizeof(portname_LPT
) / sizeof(WCHAR
) -1))
426 if (!strncmpiW(name
, portname_COM
, sizeof(portname_COM
) / sizeof(WCHAR
) -1))
429 if (!strcmpiW(name
, portname_FILE
))
433 return PORT_IS_UNIXNAME
;
438 if (!strncmpW(name
, portname_CUPS
, sizeof(portname_CUPS
) / sizeof(WCHAR
) -1))
441 if (!strncmpW(name
, portname_LPR
, sizeof(portname_LPR
) / sizeof(WCHAR
) -1))
444 /* Must be a file or a directory. Does the file exist ? */
445 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
446 TRACE("%p for OPEN_EXISTING on %s\n", hfile
, debugstr_w(name
));
447 if (hfile
== INVALID_HANDLE_VALUE
) {
448 /* Can we create the file? */
449 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_ALWAYS
, FILE_FLAG_DELETE_ON_CLOSE
, NULL
);
450 TRACE("%p for OPEN_ALWAYS\n", hfile
);
452 if (hfile
!= INVALID_HANDLE_VALUE
) {
454 return PORT_IS_FILENAME
;
456 /* We can't use the name. use GetLastError() for the reason */
457 return PORT_IS_UNKNOWN
;
460 /*****************************************************
461 * open_monitor_by_name [internal]
464 static BOOL
open_monitor_by_name(LPCWSTR pPrefix
, LPCWSTR pPort
, HANDLE
* phandle
)
466 PRINTER_DEFAULTSW pd
;
471 TRACE("(%s,%s)\n", debugstr_w(pPrefix
),debugstr_w(pPort
) );
473 fullname
= strdupWW(pPrefix
, pPort
);
476 pd
.DesiredAccess
= SERVER_ACCESS_ADMINISTER
;
478 res
= OpenPrinterW(fullname
, phandle
, &pd
);
479 HeapFree(GetProcessHeap(), 0, fullname
);
483 /*****************************************************
484 * localui_AddPortUI [exported through MONITORUI]
486 * Display a Dialog to add a local Port
489 * pName [I] Servername or NULL (local Computer)
490 * hWnd [I] Handle to parent Window for the Dialog-Box or NULL
491 * pMonitorName[I] Name of the Monitor, that should be used to add a Port or NULL
492 * ppPortName [O] PTR to PTR of a buffer, that receive the Name of the new Port or NULL
499 * The caller must free the buffer (returned in ppPortName) with GlobalFree().
500 * Native localui.dll failed with ERROR_INVALID_PARAMETER, when the user tried
501 * to add a Port, that start with "COM" or "LPT".
504 static BOOL WINAPI
localui_AddPortUI(PCWSTR pName
, HWND hWnd
, PCWSTR pMonitorName
, PWSTR
*ppPortName
)
513 TRACE( "(%s, %p, %s, %p) (*ppPortName: %p)\n", debugstr_w(pName
), hWnd
,
514 debugstr_w(pMonitorName
), ppPortName
, ppPortName
? *ppPortName
: NULL
);
516 if (open_monitor_by_name(XcvMonitorW
, pMonitorName
, &hXcv
)) {
518 ZeroMemory(&data
, sizeof(addportui_t
));
520 res
= DialogBoxParamW(LOCALUI_hInstance
, MAKEINTRESOURCEW(ADDPORT_DIALOG
), hWnd
,
521 dlgproc_addport
, (LPARAM
) &data
);
523 TRACE("got %u with %u for %s\n", res
, GetLastError(), debugstr_w(data
.portname
));
525 if (ppPortName
) *ppPortName
= NULL
;
528 res
= XcvDataW(hXcv
, cmd_AddPortW
, (PBYTE
) data
.portname
,
529 (lstrlenW(data
.portname
)+1) * sizeof(WCHAR
),
530 (PBYTE
) &dummy
, 0, &needed
, &status
);
532 TRACE("got %u with status %u\n", res
, status
);
533 if (res
&& (status
== ERROR_SUCCESS
) && ppPortName
) {
534 /* Native localui uses GlobalAlloc also.
535 The caller must GlobalFree the buffer */
536 *ppPortName
= GlobalAlloc(GPTR
, (lstrlenW(data
.portname
)+1) * sizeof(WCHAR
));
537 if (*ppPortName
) lstrcpyW(*ppPortName
, data
.portname
);
540 if (res
&& (status
== ERROR_ALREADY_EXISTS
)) {
541 dlg_port_already_exists(hWnd
, data
.portname
);
542 /* Native localui also return "TRUE" from AddPortUI in this case */
545 HeapFree(GetProcessHeap(), 0, data
.portname
);
549 SetLastError(ERROR_CANCELLED
);
554 TRACE("=> %u with %u\n", res
, GetLastError());
559 /*****************************************************
560 * localui_ConfigurePortUI [exported through MONITORUI]
562 * Display the Configuration-Dialog for a specific Port
565 * pName [I] Servername or NULL (local Computer)
566 * hWnd [I] Handle to parent Window for the Dialog-Box or NULL
567 * pPortName [I] Name of the Port, that should be configured
574 static BOOL WINAPI
localui_ConfigurePortUI(PCWSTR pName
, HWND hWnd
, PCWSTR pPortName
)
579 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
580 if (open_monitor_by_name(XcvPortW
, pPortName
, &hXcv
)) {
582 res
= get_type_from_name(pPortName
);
587 res
= dlg_configure_com(hXcv
, hWnd
, pPortName
);
591 res
= dlg_configure_lpt(hXcv
, hWnd
);
595 dlg_nothingtoconfig(hWnd
);
596 SetLastError(ERROR_CANCELLED
);
607 /*****************************************************
608 * localui_DeletePortUI [exported through MONITORUI]
610 * Delete a specific Port
613 * pName [I] Servername or NULL (local Computer)
614 * hWnd [I] Handle to parent Window
615 * pPortName [I] Name of the Port, that should be deleted
622 * Native localui does not allow deleting a COM/LPT port (ERROR_NOT_SUPPORTED)
625 static BOOL WINAPI
localui_DeletePortUI(PCWSTR pName
, HWND hWnd
, PCWSTR pPortName
)
632 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
634 if ((!pPortName
) || (!pPortName
[0])) {
635 SetLastError(ERROR_INVALID_PARAMETER
);
639 if (open_monitor_by_name(XcvPortW
, pPortName
, &hXcv
)) {
640 /* native localui tests here for LPT / COM - Ports and failed with
641 ERROR_NOT_SUPPORTED. */
642 if (XcvDataW(hXcv
, cmd_DeletePortW
, (LPBYTE
) pPortName
,
643 (lstrlenW(pPortName
)+1) * sizeof(WCHAR
), (LPBYTE
) &dummy
, 0, &needed
, &status
)) {
646 if (status
!= ERROR_SUCCESS
) SetLastError(status
);
647 return (status
== ERROR_SUCCESS
);
652 SetLastError(ERROR_UNKNOWN_PORT
);
656 /*****************************************************
657 * InitializePrintMonitorUI (LOCALUI.@)
659 * Initialize the User-Interface for the Local Ports
662 * Success: Pointer to a MONITORUI Structure
667 PMONITORUI WINAPI
InitializePrintMonitorUI(void)
669 static MONITORUI mymonitorui
=
673 localui_ConfigurePortUI
,
677 TRACE("=> %p\n", &mymonitorui
);
681 /*****************************************************
684 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
686 TRACE("(%p, %d, %p)\n",hinstDLL
, fdwReason
, lpvReserved
);
690 case DLL_PROCESS_ATTACH
:
691 DisableThreadLibraryCalls( hinstDLL
);
692 LOCALUI_hInstance
= hinstDLL
;