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
30 #include "ddk/winsplp.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(localui
);
37 /*****************************************************/
39 static HINSTANCE LOCALUI_hInstance
;
41 /*****************************************************/
43 typedef struct tag_addportui_t
{
48 typedef struct tag_lptconfig_t
{
54 static INT_PTR CALLBACK
dlgproc_lptconfig(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
);
56 /*****************************************************
60 static LPWSTR
strdupWW(LPCWSTR pPrefix
, LPCWSTR pSuffix
)
65 len
= lstrlenW(pPrefix
) + (pSuffix
? lstrlenW(pSuffix
) : 0) + 1;
66 ptr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
68 lstrcpyW(ptr
, pPrefix
);
69 if (pSuffix
) lstrcatW(ptr
, pSuffix
);
74 /*****************************************************
75 * dlg_configure_com [internal]
79 static BOOL
dlg_configure_com(HANDLE hXcv
, HWND hWnd
, PCWSTR pPortName
)
88 /* strip the colon (pPortName is never empty here) */
89 len
= lstrlenW(pPortName
);
90 shortname
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
92 memcpy(shortname
, pPortName
, (len
-1) * sizeof(WCHAR
));
93 shortname
[len
-1] = '\0';
95 /* get current settings */
96 len
= FIELD_OFFSET(COMMCONFIG
, wcProviderData
[1]);
97 status
= ERROR_SUCCESS
;
98 res
= XcvDataW( hXcv
, L
"GetDefaultCommConfig",
100 (lstrlenW(shortname
) +1) * sizeof(WCHAR
),
101 (PBYTE
) &cfg
, len
, &len
, &status
);
103 if (res
&& (status
== ERROR_SUCCESS
)) {
104 /* display the Dialog */
105 res
= CommConfigDialogW(pPortName
, hWnd
, &cfg
);
107 status
= ERROR_SUCCESS
;
108 /* set new settings */
109 res
= XcvDataW(hXcv
, L
"SetDefaultCommConfig",
111 (PBYTE
) &dummy
, 0, &len
, &status
);
114 HeapFree(GetProcessHeap(), 0, shortname
);
121 /*****************************************************
122 * dlg_configure_lpt [internal]
126 static BOOL
dlg_configure_lpt(HANDLE hXcv
, HWND hWnd
)
134 res
= DialogBoxParamW(LOCALUI_hInstance
, MAKEINTRESOURCEW(LPTCONFIG_DIALOG
), hWnd
,
135 dlgproc_lptconfig
, (LPARAM
) &data
);
137 TRACE("got %u with %u\n", res
, GetLastError());
139 if (!res
) SetLastError(ERROR_CANCELLED
);
143 /******************************************************************
144 * dlg_port_already_exists [internal]
147 static void dlg_port_already_exists(HWND hWnd
, LPCWSTR portname
)
149 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
150 WCHAR res_PortExistsW
[IDS_PORTEXISTS_MAXLEN
];
155 res_PortExistsW
[0] = '\0';
156 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
157 LoadStringW(LOCALUI_hInstance
, IDS_PORTEXISTS
, res_PortExistsW
, IDS_PORTEXISTS_MAXLEN
);
159 len
= lstrlenW(portname
) + IDS_PORTEXISTS_MAXLEN
+ 1;
160 message
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
163 swprintf(message
, len
, res_PortExistsW
, portname
);
164 MessageBoxW(hWnd
, message
, res_PortW
, MB_OK
| MB_ICONERROR
);
165 HeapFree(GetProcessHeap(), 0, message
);
169 /******************************************************************
170 * dlg_invalid_portname [internal]
173 static void dlg_invalid_portname(HWND hWnd
, LPCWSTR portname
)
175 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
176 WCHAR res_InvalidNameW
[IDS_INVALIDNAME_MAXLEN
];
181 res_InvalidNameW
[0] = '\0';
182 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
183 LoadStringW(LOCALUI_hInstance
, IDS_INVALIDNAME
, res_InvalidNameW
, IDS_INVALIDNAME_MAXLEN
);
185 len
= lstrlenW(portname
) + IDS_INVALIDNAME_MAXLEN
;
186 message
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
189 swprintf(message
, len
, res_InvalidNameW
, portname
);
190 MessageBoxW(hWnd
, message
, res_PortW
, MB_OK
| MB_ICONERROR
);
191 HeapFree(GetProcessHeap(), 0, message
);
195 /******************************************************************
196 * display the Dialog "Nothing to configure"
200 static void dlg_nothingtoconfig(HWND hWnd
)
202 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
203 WCHAR res_nothingW
[IDS_NOTHINGTOCONFIG_MAXLEN
];
206 res_nothingW
[0] = '\0';
207 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
208 LoadStringW(LOCALUI_hInstance
, IDS_NOTHINGTOCONFIG
, res_nothingW
, IDS_NOTHINGTOCONFIG_MAXLEN
);
210 MessageBoxW(hWnd
, res_nothingW
, res_PortW
, MB_OK
| MB_ICONINFORMATION
);
213 /******************************************************************
214 * dlg_win32error [internal]
217 static void dlg_win32error(HWND hWnd
, DWORD lasterror
)
219 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
220 LPWSTR message
= NULL
;
224 LoadStringW(LOCALUI_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
);
227 res
= FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
228 NULL
, lasterror
, 0, (LPWSTR
) &message
, 0, NULL
);
231 MessageBoxW(hWnd
, message
, res_PortW
, MB_OK
| MB_ICONERROR
);
236 /*****************************************************************************
240 static INT_PTR CALLBACK
dlgproc_addport(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
251 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
255 if (wparam
== MAKEWPARAM(IDOK
, BN_CLICKED
))
257 data
= (addportui_t
*) GetWindowLongPtrW(hwnd
, DWLP_USER
);
258 /* length in WCHAR, without the '\0' */
259 len
= SendDlgItemMessageW(hwnd
, ADDPORT_EDIT
, WM_GETTEXTLENGTH
, 0, 0);
260 data
->portname
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
262 if (!data
->portname
) {
263 EndDialog(hwnd
, FALSE
);
266 /* length is in WCHAR, including the '\0' */
267 GetDlgItemTextW(hwnd
, ADDPORT_EDIT
, data
->portname
, len
+ 1);
268 status
= ERROR_SUCCESS
;
269 res
= XcvDataW( data
->hXcv
, L
"PortIsValid", (BYTE
*) data
->portname
,
270 (lstrlenW(data
->portname
) + 1) * sizeof(WCHAR
),
271 (PBYTE
) &dummy
, 0, &len
, &status
);
273 TRACE("got %u with status %u\n", res
, status
);
274 if (res
&& (status
== ERROR_SUCCESS
)) {
275 /* The caller must free data->portname */
276 EndDialog(hwnd
, TRUE
);
280 if (res
&& (status
== ERROR_INVALID_NAME
)) {
281 dlg_invalid_portname(hwnd
, data
->portname
);
282 HeapFree(GetProcessHeap(), 0, data
->portname
);
283 data
->portname
= NULL
;
287 dlg_win32error(hwnd
, status
);
288 HeapFree(GetProcessHeap(), 0, data
->portname
);
289 data
->portname
= NULL
;
293 if (wparam
== MAKEWPARAM(IDCANCEL
, BN_CLICKED
))
295 EndDialog(hwnd
, FALSE
);
303 /*****************************************************************************
304 * dlgproc_lptconfig [internal]
306 * Our message-proc is simple, as the range-check is done only during the
307 * command "OK" and the dialog is set to the start-value at "out of range".
309 * Native localui.dll does the check during keyboard-input and set the dialog
310 * to the previous value.
314 static INT_PTR CALLBACK
dlgproc_lptconfig(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
327 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
328 data
= (lptconfig_t
*) lparam
;
330 /* Get current setting */
332 status
= ERROR_SUCCESS
;
333 res
= XcvDataW( data
->hXcv
, L
"GetTransmissionRetryTimeout",
335 (PBYTE
) &data
->value
, sizeof(data
->value
), &len
, &status
);
337 TRACE("got %u with status %u\n", res
, status
);
339 /* Set current setting as the initial value in the Dialog */
340 SetDlgItemInt(hwnd
, LPTCONFIG_EDIT
, data
->value
, FALSE
);
344 if (wparam
== MAKEWPARAM(IDOK
, BN_CLICKED
))
346 data
= (lptconfig_t
*) GetWindowLongPtrW(hwnd
, DWLP_USER
);
349 res
= GetDlgItemInt(hwnd
, LPTCONFIG_EDIT
, (BOOL
*) &status
, FALSE
);
350 /* length is in WCHAR, including the '\0' */
351 GetDlgItemTextW(hwnd
, LPTCONFIG_EDIT
, bufferW
, ARRAY_SIZE(bufferW
));
352 TRACE("got %s and %u (translated: %u)\n", debugstr_w(bufferW
), res
, status
);
354 /* native localui.dll use the same limits */
355 if ((res
> 0) && (res
< 1000000) && status
) {
356 swprintf(bufferW
, ARRAY_SIZE(bufferW
), L
"%u", res
);
357 res
= XcvDataW( data
->hXcv
, L
"ConfigureLPTPortCommandOK",
359 (lstrlenW(bufferW
) +1) * sizeof(WCHAR
),
360 (PBYTE
) &dummy
, 0, &len
, &status
);
362 TRACE("got %u with status %u\n", res
, status
);
363 EndDialog(hwnd
, TRUE
);
367 /* Set initial value and rerun the Dialog */
368 SetDlgItemInt(hwnd
, LPTCONFIG_EDIT
, data
->value
, FALSE
);
372 if (wparam
== MAKEWPARAM(IDCANCEL
, BN_CLICKED
))
374 EndDialog(hwnd
, FALSE
);
383 /*****************************************************
384 * get_type_from_name (internal)
388 static DWORD
get_type_from_name(LPCWSTR name
)
392 if (!wcsnicmp(name
, L
"LPT", ARRAY_SIZE(L
"LPT") -1))
395 if (!wcsnicmp(name
, L
"COM", ARRAY_SIZE(L
"COM") -1))
398 if (!wcsicmp(name
, L
"FILE:"))
402 return PORT_IS_UNIXNAME
;
407 if (!wcsncmp(name
, L
"CUPS:", ARRAY_SIZE(L
"CUPS:") -1))
410 if (!wcsncmp(name
, L
"LPR:", ARRAY_SIZE(L
"LPR:") -1))
413 /* Must be a file or a directory. Does the file exist ? */
414 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
415 TRACE("%p for OPEN_EXISTING on %s\n", hfile
, debugstr_w(name
));
416 if (hfile
== INVALID_HANDLE_VALUE
) {
417 /* Can we create the file? */
418 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_ALWAYS
, FILE_FLAG_DELETE_ON_CLOSE
, NULL
);
419 TRACE("%p for OPEN_ALWAYS\n", hfile
);
421 if (hfile
!= INVALID_HANDLE_VALUE
) {
423 return PORT_IS_FILENAME
;
425 /* We can't use the name. use GetLastError() for the reason */
426 return PORT_IS_UNKNOWN
;
429 /*****************************************************
430 * open_monitor_by_name [internal]
433 static BOOL
open_monitor_by_name(LPCWSTR pPrefix
, LPCWSTR pPort
, HANDLE
* phandle
)
435 PRINTER_DEFAULTSW pd
;
440 TRACE("(%s,%s)\n", debugstr_w(pPrefix
),debugstr_w(pPort
) );
442 fullname
= strdupWW(pPrefix
, pPort
);
445 pd
.DesiredAccess
= SERVER_ACCESS_ADMINISTER
;
447 res
= OpenPrinterW(fullname
, phandle
, &pd
);
448 HeapFree(GetProcessHeap(), 0, fullname
);
452 /*****************************************************
453 * localui_AddPortUI [exported through MONITORUI]
455 * Display a Dialog to add a local Port
458 * pName [I] Servername or NULL (local Computer)
459 * hWnd [I] Handle to parent Window for the Dialog-Box or NULL
460 * pMonitorName[I] Name of the Monitor, that should be used to add a Port or NULL
461 * ppPortName [O] PTR to PTR of a buffer, that receive the Name of the new Port or NULL
468 * The caller must free the buffer (returned in ppPortName) with GlobalFree().
469 * Native localui.dll failed with ERROR_INVALID_PARAMETER, when the user tried
470 * to add a Port, that start with "COM" or "LPT".
473 static BOOL WINAPI
localui_AddPortUI(PCWSTR pName
, HWND hWnd
, PCWSTR pMonitorName
, PWSTR
*ppPortName
)
482 TRACE( "(%s, %p, %s, %p) (*ppPortName: %p)\n", debugstr_w(pName
), hWnd
,
483 debugstr_w(pMonitorName
), ppPortName
, ppPortName
? *ppPortName
: NULL
);
485 if (open_monitor_by_name(L
",XcvMonitor ", pMonitorName
, &hXcv
)) {
487 ZeroMemory(&data
, sizeof(addportui_t
));
489 res
= DialogBoxParamW(LOCALUI_hInstance
, MAKEINTRESOURCEW(ADDPORT_DIALOG
), hWnd
,
490 dlgproc_addport
, (LPARAM
) &data
);
492 TRACE("got %u with %u for %s\n", res
, GetLastError(), debugstr_w(data
.portname
));
494 if (ppPortName
) *ppPortName
= NULL
;
497 res
= XcvDataW(hXcv
, L
"AddPort", (BYTE
*) data
.portname
,
498 (lstrlenW(data
.portname
)+1) * sizeof(WCHAR
),
499 (PBYTE
) &dummy
, 0, &needed
, &status
);
501 TRACE("got %u with status %u\n", res
, status
);
502 if (res
&& (status
== ERROR_SUCCESS
) && ppPortName
) {
503 /* Native localui uses GlobalAlloc also.
504 The caller must GlobalFree the buffer */
505 *ppPortName
= GlobalAlloc(GPTR
, (lstrlenW(data
.portname
)+1) * sizeof(WCHAR
));
506 if (*ppPortName
) lstrcpyW(*ppPortName
, data
.portname
);
509 if (res
&& (status
== ERROR_ALREADY_EXISTS
)) {
510 dlg_port_already_exists(hWnd
, data
.portname
);
511 /* Native localui also return "TRUE" from AddPortUI in this case */
514 HeapFree(GetProcessHeap(), 0, data
.portname
);
518 SetLastError(ERROR_CANCELLED
);
523 TRACE("=> %u with %u\n", res
, GetLastError());
528 /*****************************************************
529 * localui_ConfigurePortUI [exported through MONITORUI]
531 * Display the Configuration-Dialog for a specific Port
534 * pName [I] Servername or NULL (local Computer)
535 * hWnd [I] Handle to parent Window for the Dialog-Box or NULL
536 * pPortName [I] Name of the Port, that should be configured
543 static BOOL WINAPI
localui_ConfigurePortUI(PCWSTR pName
, HWND hWnd
, PCWSTR pPortName
)
548 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
549 if (open_monitor_by_name(L
",XcvPort ", pPortName
, &hXcv
)) {
551 res
= get_type_from_name(pPortName
);
556 res
= dlg_configure_com(hXcv
, hWnd
, pPortName
);
560 res
= dlg_configure_lpt(hXcv
, hWnd
);
564 dlg_nothingtoconfig(hWnd
);
565 SetLastError(ERROR_CANCELLED
);
576 /*****************************************************
577 * localui_DeletePortUI [exported through MONITORUI]
579 * Delete a specific Port
582 * pName [I] Servername or NULL (local Computer)
583 * hWnd [I] Handle to parent Window
584 * pPortName [I] Name of the Port, that should be deleted
591 * Native localui does not allow deleting a COM/LPT port (ERROR_NOT_SUPPORTED)
594 static BOOL WINAPI
localui_DeletePortUI(PCWSTR pName
, HWND hWnd
, PCWSTR pPortName
)
601 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
603 if ((!pPortName
) || (!pPortName
[0])) {
604 SetLastError(ERROR_INVALID_PARAMETER
);
608 if (open_monitor_by_name(L
",XcvPort ", pPortName
, &hXcv
)) {
609 /* native localui tests here for LPT / COM - Ports and failed with
610 ERROR_NOT_SUPPORTED. */
611 if (XcvDataW(hXcv
, L
"DeletePort", (BYTE
*) pPortName
,
612 (lstrlenW(pPortName
)+1) * sizeof(WCHAR
), (LPBYTE
) &dummy
, 0, &needed
, &status
)) {
615 if (status
!= ERROR_SUCCESS
) SetLastError(status
);
616 return (status
== ERROR_SUCCESS
);
621 SetLastError(ERROR_UNKNOWN_PORT
);
625 /*****************************************************
626 * InitializePrintMonitorUI (LOCALUI.@)
628 * Initialize the User-Interface for the Local Ports
631 * Success: Pointer to a MONITORUI Structure
636 PMONITORUI WINAPI
InitializePrintMonitorUI(void)
638 static MONITORUI mymonitorui
=
642 localui_ConfigurePortUI
,
646 TRACE("=> %p\n", &mymonitorui
);
650 /*****************************************************
653 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
655 TRACE("(%p, %d, %p)\n",hinstDLL
, fdwReason
, lpvReserved
);
659 case DLL_PROCESS_ATTACH
:
660 DisableThreadLibraryCalls( hinstDLL
);
661 LOCALUI_hInstance
= hinstDLL
;