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
23 #define NONAMELESSUNION
32 #include "ddk/winsplp.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(localui);
40 /*****************************************************/
42 static HINSTANCE LOCALUI_hInstance;
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};
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};
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};
63 /*****************************************************/
65 typedef struct tag_addportui_t {
70 /*****************************************************
74 static LPWSTR strdupWW(LPCWSTR pPrefix, LPCWSTR pSuffix)
79 len = lstrlenW(pPrefix) + (pSuffix ? lstrlenW(pSuffix) : 0) + 1;
80 ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
82 lstrcpyW(ptr, pPrefix);
83 if (pSuffix) lstrcatW(ptr, pSuffix);
88 /*****************************************************
89 * dlg_configure_com [internal]
93 static BOOL dlg_configure_com(HANDLE hXcv, HWND hWnd, PCWSTR pPortName)
102 /* strip the colon (pPortName is never empty here) */
103 len = lstrlenW(pPortName);
104 shortname = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
106 memcpy(shortname, pPortName, (len -1) * sizeof(WCHAR));
107 shortname[len-1] = '\0';
109 /* get current settings */
111 status = ERROR_SUCCESS;
112 res = XcvDataW( hXcv, cmd_GetDefaultCommConfigW,
114 (lstrlenW(shortname) +1) * sizeof(WCHAR),
115 (PBYTE) &cfg, len, &len, &status);
117 if (res && (status == ERROR_SUCCESS)) {
118 /* display the Dialog */
119 res = CommConfigDialogW(pPortName, hWnd, &cfg);
121 status = ERROR_SUCCESS;
122 /* set new settings */
123 res = XcvDataW(hXcv, cmd_SetDefaultCommConfigW,
125 (PBYTE) &dummy, 0, &len, &status);
128 HeapFree(GetProcessHeap(), 0, shortname);
134 /******************************************************************
135 * dlg_port_already_exists [internal]
138 static void dlg_port_already_exists(HWND hWnd, LPCWSTR portname)
140 WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
141 WCHAR res_PortExistsW[IDS_PORTEXISTS_MAXLEN];
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);
150 len = lstrlenW(portname) + IDS_PORTEXISTS_MAXLEN + 1;
151 message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
154 snprintfW(message, len, res_PortExistsW, portname);
155 MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
156 HeapFree(GetProcessHeap(), 0, message);
160 /******************************************************************
161 * dlg_invalid_portname [internal]
164 static void dlg_invalid_portname(HWND hWnd, LPCWSTR portname)
166 WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
167 WCHAR res_InvalidNameW[IDS_INVALIDNAME_MAXLEN];
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);
176 len = lstrlenW(portname) + IDS_INVALIDNAME_MAXLEN;
177 message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
180 snprintfW(message, len, res_InvalidNameW, portname);
181 MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
182 HeapFree(GetProcessHeap(), 0, message);
186 /******************************************************************
187 * display the Dialog "Nothing to configure"
191 static void dlg_nothingtoconfig(HWND hWnd)
193 WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
194 WCHAR res_nothingW[IDS_NOTHINGTOCONFIG_MAXLEN];
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);
201 MessageBoxW(hWnd, res_nothingW, res_PortW, MB_OK | MB_ICONINFORMATION);
204 /******************************************************************
205 * dlg_win32error [internal]
208 static void dlg_win32error(HWND hWnd, DWORD lasterror)
210 WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
211 LPWSTR message = NULL;
215 LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
218 res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
219 NULL, lasterror, 0, (LPWSTR) &message, 0, NULL);
222 MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
227 /*****************************************************************************
231 static INT_PTR CALLBACK dlgproc_addport(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
242 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
246 if (wparam == MAKEWPARAM(IDOK, BN_CLICKED))
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));
253 if (!data->portname) {
254 EndDialog(hwnd, FALSE);
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);
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);
271 if (res && (status == ERROR_INVALID_NAME)) {
272 dlg_invalid_portname(hwnd, data->portname);
273 HeapFree(GetProcessHeap(), 0, data->portname);
274 data->portname = NULL;
278 dlg_win32error(hwnd, status);
279 HeapFree(GetProcessHeap(), 0, data->portname);
280 data->portname = NULL;
284 if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED))
286 EndDialog(hwnd, FALSE);
294 /*****************************************************
295 * get_type_from_name (internal)
299 static DWORD get_type_from_name(LPCWSTR name)
303 if (!strncmpiW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1))
306 if (!strncmpiW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1))
309 if (!strcmpiW(name, portname_FILE))
313 return PORT_IS_UNIXNAME;
318 if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1))
321 if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1))
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);
332 if (hfile != INVALID_HANDLE_VALUE) {
334 return PORT_IS_FILENAME;
336 /* We can't use the name. use GetLastError() for the reason */
337 return PORT_IS_UNKNOWN;
340 /*****************************************************
341 * open_monitor_by_name [internal]
344 static BOOL open_monitor_by_name(LPCWSTR pPrefix, LPCWSTR pPort, HANDLE * phandle)
346 PRINTER_DEFAULTSW pd;
351 TRACE("(%s,%s)\n", debugstr_w(pPrefix),debugstr_w(pPort) );
353 fullname = strdupWW(pPrefix, pPort);
356 pd.DesiredAccess = SERVER_ACCESS_ADMINISTER;
358 res = OpenPrinterW(fullname, phandle, &pd);
359 HeapFree(GetProcessHeap(), 0, fullname);
363 /*****************************************************
364 * localui_AddPortUI [exported through MONITORUI]
366 * Display a Dialog to add a local Port
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
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".
384 static BOOL WINAPI localui_AddPortUI(PCWSTR pName, HWND hWnd, PCWSTR pMonitorName, PWSTR *ppPortName)
394 TRACE( "(%s, %p, %s, %p) (*ppPortName: %p)\n", debugstr_w(pName), hWnd,
395 debugstr_w(pMonitorName), ppPortName, ppPortName ? *ppPortName : NULL);
397 if (open_monitor_by_name(XcvMonitorW, pMonitorName, &hXcv)) {
399 ZeroMemory(&data, sizeof(addportui_t));
401 res = DialogBoxParamW(LOCALUI_hInstance, MAKEINTRESOURCEW(ADDPORT_DIALOG), hWnd,
402 dlgproc_addport, (LPARAM) &data);
404 TRACE("got %u with %u for %s\n", res, GetLastError(), debugstr_w(data.portname));
406 if (ppPortName) *ppPortName = NULL;
409 res = XcvDataW(hXcv, cmd_AddPortW, (PBYTE) data.portname,
410 (lstrlenW(data.portname)+1) * sizeof(WCHAR),
411 (PBYTE) &dummy, 0, &needed, &status);
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));
419 lstrcpyW(ptr, data.portname);
420 if (ppPortName) *ppPortName = ptr;
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 */
429 HeapFree(GetProcessHeap(), 0, data.portname);
433 SetLastError(ERROR_CANCELLED);
438 TRACE("=> %u with %u\n", res, GetLastError());
443 /*****************************************************
444 * localui_ConfigurePortUI [exported through MONITORUI]
446 * Display the Configuration-Dialog for a specific Port
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
458 static BOOL WINAPI localui_ConfigurePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
463 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
464 if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
466 res = get_type_from_name(pPortName);
471 res = dlg_configure_com(hXcv, hWnd, pPortName);
475 dlg_nothingtoconfig(hWnd);
476 SetLastError(ERROR_CANCELLED);
487 /*****************************************************
488 * localui_DeletePortUI [exported through MONITORUI]
490 * Delete a specific Port
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
502 * Native localui does not allow to delete a COM / LPT - Port (ERROR_NOT_SUPPORTED)
505 static BOOL WINAPI localui_DeletePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
512 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
514 if ((!pPortName) || (!pPortName[0])) {
515 SetLastError(ERROR_INVALID_PARAMETER);
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)) {
526 if (status != ERROR_SUCCESS) SetLastError(status);
527 return (status == ERROR_SUCCESS);
532 SetLastError(ERROR_UNKNOWN_PORT);
536 /*****************************************************
537 * InitializePrintMonitorUI (LOCALUI.@)
539 * Initialize the User-Interface for the Local Ports
542 * Success: Pointer to a MONITORUI Structure
547 PMONITORUI WINAPI InitializePrintMonitorUI(void)
549 static MONITORUI mymonitorui =
553 localui_ConfigurePortUI,
557 TRACE("=> %p\n", &mymonitorui);
561 /*****************************************************
564 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
566 TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
570 case DLL_WINE_PREATTACH:
571 return FALSE; /* prefer native version */
573 case DLL_PROCESS_ATTACH:
574 DisableThreadLibraryCalls( hinstDLL );
575 LOCALUI_hInstance = hinstDLL;