|  | /* | 
|  | * Implementation of the Local Printmonitor User Interface | 
|  | * | 
|  | * Copyright 2007 Detlef Riekenberg | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #define NONAMELESSUNION | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winreg.h" | 
|  | #include "winuser.h" | 
|  |  | 
|  | #include "winspool.h" | 
|  | #include "ddk/winsplp.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "localui.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(localui); | 
|  |  | 
|  | /*****************************************************/ | 
|  |  | 
|  | static HINSTANCE LOCALUI_hInstance; | 
|  |  | 
|  | static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0}; | 
|  | static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e', | 
|  | 'L','P','T','P','o','r','t', | 
|  | 'C','o','m','m','a','n','d','O','K',0}; | 
|  | static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0}; | 
|  | static const WCHAR cmd_GetDefaultCommConfigW[] = {'G','e','t', | 
|  | 'D','e','f','a','u','l','t', | 
|  | 'C','o','m','m','C','o','n','f','i','g',0}; | 
|  | static const WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t', | 
|  | 'T','r','a','n','s','m','i','s','s','i','o','n', | 
|  | 'R','e','t','r','y','T','i','m','e','o','u','t',0}; | 
|  | static const WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0}; | 
|  | static const WCHAR cmd_SetDefaultCommConfigW[] = {'S','e','t', | 
|  | 'D','e','f','a','u','l','t', | 
|  | 'C','o','m','m','C','o','n','f','i','g',0}; | 
|  |  | 
|  | static const WCHAR fmt_uW[]  = {'%','u',0}; | 
|  | static const WCHAR portname_LPT[]  = {'L','P','T',0}; | 
|  | static const WCHAR portname_COM[]  = {'C','O','M',0}; | 
|  | static const WCHAR portname_FILE[] = {'F','I','L','E',':',0}; | 
|  | static const WCHAR portname_CUPS[] = {'C','U','P','S',':',0}; | 
|  | static const WCHAR portname_LPR[]  = {'L','P','R',':',0}; | 
|  |  | 
|  | static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0}; | 
|  | static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0}; | 
|  |  | 
|  | /*****************************************************/ | 
|  |  | 
|  | typedef struct tag_addportui_t { | 
|  | LPWSTR  portname; | 
|  | HANDLE  hXcv; | 
|  | } addportui_t; | 
|  |  | 
|  | typedef struct tag_lptconfig_t { | 
|  | HANDLE  hXcv; | 
|  | DWORD   value; | 
|  | } lptconfig_t; | 
|  |  | 
|  |  | 
|  | static INT_PTR CALLBACK dlgproc_lptconfig(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); | 
|  |  | 
|  | /***************************************************** | 
|  | *   strdupWW [internal] | 
|  | */ | 
|  |  | 
|  | static LPWSTR strdupWW(LPCWSTR pPrefix, LPCWSTR pSuffix) | 
|  | { | 
|  | LPWSTR  ptr; | 
|  | DWORD   len; | 
|  |  | 
|  | len = lstrlenW(pPrefix) + (pSuffix ? lstrlenW(pSuffix) : 0) + 1; | 
|  | ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | if (ptr) { | 
|  | lstrcpyW(ptr, pPrefix); | 
|  | if (pSuffix) lstrcatW(ptr, pSuffix); | 
|  | } | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /***************************************************** | 
|  | *   dlg_configure_com [internal] | 
|  | * | 
|  | */ | 
|  |  | 
|  | static BOOL dlg_configure_com(HANDLE hXcv, HWND hWnd, PCWSTR pPortName) | 
|  | { | 
|  | COMMCONFIG cfg; | 
|  | LPWSTR shortname; | 
|  | DWORD status; | 
|  | DWORD dummy; | 
|  | DWORD len; | 
|  | BOOL  res; | 
|  |  | 
|  | /* strip the colon (pPortName is never empty here) */ | 
|  | len = lstrlenW(pPortName); | 
|  | shortname = HeapAlloc(GetProcessHeap(), 0, len  * sizeof(WCHAR)); | 
|  | if (shortname) { | 
|  | memcpy(shortname, pPortName, (len -1) * sizeof(WCHAR)); | 
|  | shortname[len-1] = '\0'; | 
|  |  | 
|  | /* get current settings */ | 
|  | len = sizeof(cfg); | 
|  | status = ERROR_SUCCESS; | 
|  | res = XcvDataW( hXcv, cmd_GetDefaultCommConfigW, | 
|  | (PBYTE) shortname, | 
|  | (lstrlenW(shortname) +1) * sizeof(WCHAR), | 
|  | (PBYTE) &cfg, len, &len, &status); | 
|  |  | 
|  | if (res && (status == ERROR_SUCCESS)) { | 
|  | /* display the Dialog */ | 
|  | res = CommConfigDialogW(pPortName, hWnd, &cfg); | 
|  | if (res) { | 
|  | status = ERROR_SUCCESS; | 
|  | /* set new settings */ | 
|  | res = XcvDataW(hXcv, cmd_SetDefaultCommConfigW, | 
|  | (PBYTE) &cfg, len, | 
|  | (PBYTE) &dummy, 0, &len, &status); | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, shortname); | 
|  | return res; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /***************************************************** | 
|  | *   dlg_configure_lpt [internal] | 
|  | * | 
|  | */ | 
|  |  | 
|  | static BOOL dlg_configure_lpt(HANDLE hXcv, HWND hWnd) | 
|  | { | 
|  | lptconfig_t data; | 
|  | BOOL  res; | 
|  |  | 
|  |  | 
|  | data.hXcv = hXcv; | 
|  |  | 
|  | res = DialogBoxParamW(LOCALUI_hInstance, MAKEINTRESOURCEW(LPTCONFIG_DIALOG), hWnd, | 
|  | dlgproc_lptconfig, (LPARAM) &data); | 
|  |  | 
|  | TRACE("got %u with %u\n", res, GetLastError()); | 
|  |  | 
|  | if (!res) SetLastError(ERROR_CANCELLED); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /****************************************************************** | 
|  | *  dlg_port_already_exists [internal] | 
|  | */ | 
|  |  | 
|  | static void dlg_port_already_exists(HWND hWnd, LPCWSTR portname) | 
|  | { | 
|  | WCHAR res_PortW[IDS_LOCALPORT_MAXLEN]; | 
|  | WCHAR res_PortExistsW[IDS_PORTEXISTS_MAXLEN]; | 
|  | LPWSTR  message; | 
|  | DWORD   len; | 
|  |  | 
|  | res_PortW[0] = '\0'; | 
|  | res_PortExistsW[0] = '\0'; | 
|  | LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN); | 
|  | LoadStringW(LOCALUI_hInstance, IDS_PORTEXISTS, res_PortExistsW, IDS_PORTEXISTS_MAXLEN); | 
|  |  | 
|  | len = lstrlenW(portname) + IDS_PORTEXISTS_MAXLEN + 1; | 
|  | message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | if (message) { | 
|  | message[0] = '\0'; | 
|  | snprintfW(message, len, res_PortExistsW, portname); | 
|  | MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR); | 
|  | HeapFree(GetProcessHeap(), 0, message); | 
|  | } | 
|  | } | 
|  |  | 
|  | /****************************************************************** | 
|  | *  dlg_invalid_portname [internal] | 
|  | */ | 
|  |  | 
|  | static void dlg_invalid_portname(HWND hWnd, LPCWSTR portname) | 
|  | { | 
|  | WCHAR res_PortW[IDS_LOCALPORT_MAXLEN]; | 
|  | WCHAR res_InvalidNameW[IDS_INVALIDNAME_MAXLEN]; | 
|  | LPWSTR  message; | 
|  | DWORD   len; | 
|  |  | 
|  | res_PortW[0] = '\0'; | 
|  | res_InvalidNameW[0] = '\0'; | 
|  | LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN); | 
|  | LoadStringW(LOCALUI_hInstance, IDS_INVALIDNAME, res_InvalidNameW, IDS_INVALIDNAME_MAXLEN); | 
|  |  | 
|  | len = lstrlenW(portname) + IDS_INVALIDNAME_MAXLEN; | 
|  | message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | if (message) { | 
|  | message[0] = '\0'; | 
|  | snprintfW(message, len, res_InvalidNameW, portname); | 
|  | MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR); | 
|  | HeapFree(GetProcessHeap(), 0, message); | 
|  | } | 
|  | } | 
|  |  | 
|  | /****************************************************************** | 
|  | * display the Dialog "Nothing to configure" | 
|  | * | 
|  | */ | 
|  |  | 
|  | static void dlg_nothingtoconfig(HWND hWnd) | 
|  | { | 
|  | WCHAR res_PortW[IDS_LOCALPORT_MAXLEN]; | 
|  | WCHAR res_nothingW[IDS_NOTHINGTOCONFIG_MAXLEN]; | 
|  |  | 
|  | res_PortW[0] = '\0'; | 
|  | res_nothingW[0] = '\0'; | 
|  | LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN); | 
|  | LoadStringW(LOCALUI_hInstance, IDS_NOTHINGTOCONFIG, res_nothingW, IDS_NOTHINGTOCONFIG_MAXLEN); | 
|  |  | 
|  | MessageBoxW(hWnd, res_nothingW, res_PortW, MB_OK | MB_ICONINFORMATION); | 
|  | } | 
|  |  | 
|  | /****************************************************************** | 
|  | *  dlg_win32error [internal] | 
|  | */ | 
|  |  | 
|  | static void dlg_win32error(HWND hWnd, DWORD lasterror) | 
|  | { | 
|  | WCHAR res_PortW[IDS_LOCALPORT_MAXLEN]; | 
|  | LPWSTR  message = NULL; | 
|  | DWORD   res; | 
|  |  | 
|  | res_PortW[0] = '\0'; | 
|  | LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN); | 
|  |  | 
|  |  | 
|  | res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, | 
|  | NULL, lasterror, 0, (LPWSTR) &message, 0, NULL); | 
|  |  | 
|  | if (res > 0) { | 
|  | MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR); | 
|  | LocalFree(message); | 
|  | } | 
|  | } | 
|  |  | 
|  | /***************************************************************************** | 
|  | * | 
|  | */ | 
|  |  | 
|  | static INT_PTR CALLBACK dlgproc_addport(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | addportui_t * data; | 
|  | DWORD   status; | 
|  | DWORD   dummy; | 
|  | DWORD   len; | 
|  | DWORD   res; | 
|  |  | 
|  | switch(msg) | 
|  | { | 
|  | case WM_INITDIALOG: | 
|  | SetWindowLongPtrW(hwnd, DWLP_USER, lparam); | 
|  | return TRUE; | 
|  |  | 
|  | case WM_COMMAND: | 
|  | if (wparam == MAKEWPARAM(IDOK, BN_CLICKED)) | 
|  | { | 
|  | data = (addportui_t *) GetWindowLongPtrW(hwnd, DWLP_USER); | 
|  | /* length in WCHAR, without the '\0' */ | 
|  | len = SendDlgItemMessageW(hwnd, ADDPORT_EDIT, WM_GETTEXTLENGTH, 0, 0); | 
|  | data->portname = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); | 
|  |  | 
|  | if (!data->portname) { | 
|  | EndDialog(hwnd, FALSE); | 
|  | return TRUE; | 
|  | } | 
|  | /* length is in WCHAR, including the '\0' */ | 
|  | GetDlgItemTextW(hwnd, ADDPORT_EDIT, data->portname, len + 1); | 
|  | status = ERROR_SUCCESS; | 
|  | res = XcvDataW( data->hXcv, cmd_PortIsValidW, (PBYTE) data->portname, | 
|  | (lstrlenW(data->portname) + 1) * sizeof(WCHAR), | 
|  | (PBYTE) &dummy, 0, &len, &status); | 
|  |  | 
|  | TRACE("got %u with status %u\n", res, status); | 
|  | if (res && (status == ERROR_SUCCESS)) { | 
|  | /* The caller must free data->portname */ | 
|  | EndDialog(hwnd, TRUE); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | if (res && (status == ERROR_INVALID_NAME)) { | 
|  | dlg_invalid_portname(hwnd, data->portname); | 
|  | HeapFree(GetProcessHeap(), 0, data->portname); | 
|  | data->portname = NULL; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | dlg_win32error(hwnd, status); | 
|  | HeapFree(GetProcessHeap(), 0, data->portname); | 
|  | data->portname = NULL; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED)) | 
|  | { | 
|  | EndDialog(hwnd, FALSE); | 
|  | return TRUE; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /***************************************************************************** | 
|  | *   dlgproc_lptconfig  [internal] | 
|  | * | 
|  | * Our message-proc is simple, as the range-check is done only during the | 
|  | * command "OK" and the dialog is set to the start-value at "out of range". | 
|  | * | 
|  | * Native localui.dll does the check during keyboard-input and set the dialog | 
|  | * to the previous value. | 
|  | * | 
|  | */ | 
|  |  | 
|  | static INT_PTR CALLBACK dlgproc_lptconfig(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | lptconfig_t * data; | 
|  | WCHAR   bufferW[16]; | 
|  | DWORD   status; | 
|  | DWORD   dummy; | 
|  | DWORD   len; | 
|  | DWORD   res; | 
|  |  | 
|  |  | 
|  | switch(msg) | 
|  | { | 
|  | case WM_INITDIALOG: | 
|  | SetWindowLongPtrW(hwnd, DWLP_USER, lparam); | 
|  | data = (lptconfig_t *) lparam; | 
|  |  | 
|  | /* Get current setting */ | 
|  | data->value = 45; | 
|  | status = ERROR_SUCCESS; | 
|  | res = XcvDataW( data->hXcv, cmd_GetTransmissionRetryTimeoutW, | 
|  | (PBYTE) &dummy, 0, | 
|  | (PBYTE) &data->value, sizeof(data->value), &len, &status); | 
|  |  | 
|  | TRACE("got %u with status %u\n", res, status); | 
|  |  | 
|  | /* Set current setting as the initial value in the Dialog */ | 
|  | SetDlgItemInt(hwnd, LPTCONFIG_EDIT, data->value, FALSE); | 
|  | return TRUE; | 
|  |  | 
|  | case WM_COMMAND: | 
|  | if (wparam == MAKEWPARAM(IDOK, BN_CLICKED)) | 
|  | { | 
|  | data = (lptconfig_t *) GetWindowLongPtrW(hwnd, DWLP_USER); | 
|  |  | 
|  | status = FALSE; | 
|  | res = GetDlgItemInt(hwnd, LPTCONFIG_EDIT, (BOOL *) &status, FALSE); | 
|  | /* length is in WCHAR, including the '\0' */ | 
|  | GetDlgItemTextW(hwnd, LPTCONFIG_EDIT, bufferW, sizeof(bufferW) / sizeof(bufferW[0])); | 
|  | TRACE("got %s and %u (translated: %u)\n", debugstr_w(bufferW), res, status); | 
|  |  | 
|  | /* native localui.dll use the same limits */ | 
|  | if ((res > 0) && (res < 1000000) && status) { | 
|  | sprintfW(bufferW, fmt_uW, res); | 
|  | res = XcvDataW( data->hXcv, cmd_ConfigureLPTPortCommandOKW, | 
|  | (PBYTE) bufferW, | 
|  | (lstrlenW(bufferW) +1) * sizeof(WCHAR), | 
|  | (PBYTE) &dummy, 0, &len, &status); | 
|  |  | 
|  | TRACE("got %u with status %u\n", res, status); | 
|  | EndDialog(hwnd, TRUE); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /* Set initial value and rerun the Dialog */ | 
|  | SetDlgItemInt(hwnd, LPTCONFIG_EDIT, data->value, FALSE); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED)) | 
|  | { | 
|  | EndDialog(hwnd, FALSE); | 
|  | return TRUE; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /***************************************************** | 
|  | * get_type_from_name (internal) | 
|  | * | 
|  | */ | 
|  |  | 
|  | static DWORD get_type_from_name(LPCWSTR name) | 
|  | { | 
|  | HANDLE  hfile; | 
|  |  | 
|  | if (!strncmpiW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1)) | 
|  | return PORT_IS_LPT; | 
|  |  | 
|  | if (!strncmpiW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1)) | 
|  | return PORT_IS_COM; | 
|  |  | 
|  | if (!strcmpiW(name, portname_FILE)) | 
|  | return PORT_IS_FILE; | 
|  |  | 
|  | if (name[0] == '/') | 
|  | return PORT_IS_UNIXNAME; | 
|  |  | 
|  | if (name[0] == '|') | 
|  | return PORT_IS_PIPE; | 
|  |  | 
|  | if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1)) | 
|  | return PORT_IS_CUPS; | 
|  |  | 
|  | if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1)) | 
|  | return PORT_IS_LPR; | 
|  |  | 
|  | /* Must be a file or a directory. Does the file exist ? */ | 
|  | hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | 
|  | TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name)); | 
|  | if (hfile == INVALID_HANDLE_VALUE) { | 
|  | /* Can we create the file? */ | 
|  | hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); | 
|  | TRACE("%p for OPEN_ALWAYS\n", hfile); | 
|  | } | 
|  | if (hfile != INVALID_HANDLE_VALUE) { | 
|  | CloseHandle(hfile); | 
|  | return PORT_IS_FILENAME; | 
|  | } | 
|  | /* We can't use the name. use GetLastError() for the reason */ | 
|  | return PORT_IS_UNKNOWN; | 
|  | } | 
|  |  | 
|  | /***************************************************** | 
|  | *   open_monitor_by_name [internal] | 
|  | * | 
|  | */ | 
|  | static BOOL open_monitor_by_name(LPCWSTR pPrefix, LPCWSTR pPort, HANDLE * phandle) | 
|  | { | 
|  | PRINTER_DEFAULTSW pd; | 
|  | LPWSTR  fullname; | 
|  | BOOL    res; | 
|  |  | 
|  | * phandle = 0; | 
|  | TRACE("(%s,%s)\n", debugstr_w(pPrefix),debugstr_w(pPort) ); | 
|  |  | 
|  | fullname = strdupWW(pPrefix, pPort); | 
|  | pd.pDatatype = NULL; | 
|  | pd.pDevMode  = NULL; | 
|  | pd.DesiredAccess = SERVER_ACCESS_ADMINISTER; | 
|  |  | 
|  | res = OpenPrinterW(fullname, phandle, &pd); | 
|  | HeapFree(GetProcessHeap(), 0, fullname); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /***************************************************** | 
|  | *   localui_AddPortUI [exported through MONITORUI] | 
|  | * | 
|  | * Display a Dialog to add a local Port | 
|  | * | 
|  | * PARAMS | 
|  | *  pName       [I] Servername or NULL (local Computer) | 
|  | *  hWnd        [I] Handle to parent Window for the Dialog-Box or NULL | 
|  | *  pMonitorName[I] Name of the Monitor, that should be used to add a Port or NULL | 
|  | *  ppPortName  [O] PTR to PTR of a buffer, that receive the Name of the new Port or NULL | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: TRUE | 
|  | *  Failure: FALSE | 
|  | * | 
|  | * NOTES | 
|  | * The caller must free the buffer (returned in ppPortName) with GlobalFree(). | 
|  | * Native localui.dll failed with ERROR_INVALID_PARAMETER, when the user tried | 
|  | * to add a Port, that start with "COM" or "LPT". | 
|  | * | 
|  | */ | 
|  | static BOOL WINAPI localui_AddPortUI(PCWSTR pName, HWND hWnd, PCWSTR pMonitorName, PWSTR *ppPortName) | 
|  | { | 
|  | addportui_t data; | 
|  | HANDLE  hXcv; | 
|  | LPWSTR  ptr = NULL; | 
|  | DWORD   needed; | 
|  | DWORD   dummy; | 
|  | DWORD   status; | 
|  | DWORD   res = FALSE; | 
|  |  | 
|  | TRACE(  "(%s, %p, %s, %p) (*ppPortName: %p)\n", debugstr_w(pName), hWnd, | 
|  | debugstr_w(pMonitorName), ppPortName, ppPortName ? *ppPortName : NULL); | 
|  |  | 
|  | if (open_monitor_by_name(XcvMonitorW, pMonitorName, &hXcv)) { | 
|  |  | 
|  | ZeroMemory(&data, sizeof(addportui_t)); | 
|  | data.hXcv = hXcv; | 
|  | res = DialogBoxParamW(LOCALUI_hInstance, MAKEINTRESOURCEW(ADDPORT_DIALOG), hWnd, | 
|  | dlgproc_addport, (LPARAM) &data); | 
|  |  | 
|  | TRACE("got %u with %u for %s\n", res, GetLastError(), debugstr_w(data.portname)); | 
|  |  | 
|  | if (ppPortName) *ppPortName = NULL; | 
|  |  | 
|  | if (res) { | 
|  | res = XcvDataW(hXcv, cmd_AddPortW, (PBYTE) data.portname, | 
|  | (lstrlenW(data.portname)+1) * sizeof(WCHAR), | 
|  | (PBYTE) &dummy, 0, &needed, &status); | 
|  |  | 
|  | TRACE("got %u with status %u\n", res, status); | 
|  | if (res && (status == ERROR_SUCCESS)) { | 
|  | /* Native localui uses GlobalAlloc also. | 
|  | The caller must GlobalFree the buffer */ | 
|  | ptr = GlobalAlloc(GPTR, (lstrlenW(data.portname)+1) * sizeof(WCHAR)); | 
|  | if (ptr) { | 
|  | lstrcpyW(ptr, data.portname); | 
|  | if (ppPortName) *ppPortName = ptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (res && (status == ERROR_ALREADY_EXISTS)) { | 
|  | dlg_port_already_exists(hWnd, data.portname); | 
|  | /* Native localui also return "TRUE" from AddPortUI in this case */ | 
|  | } | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, data.portname); | 
|  | } | 
|  | else | 
|  | { | 
|  | SetLastError(ERROR_CANCELLED); | 
|  | } | 
|  | ClosePrinter(hXcv); | 
|  | } | 
|  |  | 
|  | TRACE("=> %u with %u\n", res, GetLastError()); | 
|  | return res; | 
|  | } | 
|  |  | 
|  |  | 
|  | /***************************************************** | 
|  | *   localui_ConfigurePortUI [exported through MONITORUI] | 
|  | * | 
|  | * Display the Configuration-Dialog for a specific Port | 
|  | * | 
|  | * PARAMS | 
|  | *  pName     [I] Servername or NULL (local Computer) | 
|  | *  hWnd      [I] Handle to parent Window for the Dialog-Box or NULL | 
|  | *  pPortName [I] Name of the Port, that should be configured | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: TRUE | 
|  | *  Failure: FALSE | 
|  | * | 
|  | */ | 
|  | static BOOL WINAPI localui_ConfigurePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName) | 
|  | { | 
|  | HANDLE  hXcv; | 
|  | DWORD   res; | 
|  |  | 
|  | TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName)); | 
|  | if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) { | 
|  |  | 
|  | res = get_type_from_name(pPortName); | 
|  | switch(res) | 
|  | { | 
|  |  | 
|  | case PORT_IS_COM: | 
|  | res = dlg_configure_com(hXcv, hWnd, pPortName); | 
|  | break; | 
|  |  | 
|  | case PORT_IS_LPT: | 
|  | res = dlg_configure_lpt(hXcv, hWnd); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | dlg_nothingtoconfig(hWnd); | 
|  | SetLastError(ERROR_CANCELLED); | 
|  | res = FALSE; | 
|  | } | 
|  |  | 
|  | ClosePrinter(hXcv); | 
|  | return res; | 
|  | } | 
|  | return FALSE; | 
|  |  | 
|  | } | 
|  |  | 
|  | /***************************************************** | 
|  | *   localui_DeletePortUI [exported through MONITORUI] | 
|  | * | 
|  | * Delete a specific Port | 
|  | * | 
|  | * PARAMS | 
|  | *  pName     [I] Servername or NULL (local Computer) | 
|  | *  hWnd      [I] Handle to parent Window | 
|  | *  pPortName [I] Name of the Port, that should be deleted | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: TRUE | 
|  | *  Failure: FALSE | 
|  | * | 
|  | * NOTES | 
|  | *  Native localui does not allow to delete a COM / LPT - Port (ERROR_NOT_SUPPORTED) | 
|  | * | 
|  | */ | 
|  | static BOOL WINAPI localui_DeletePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName) | 
|  | { | 
|  | HANDLE  hXcv; | 
|  | DWORD   dummy; | 
|  | DWORD   needed; | 
|  | DWORD   status; | 
|  |  | 
|  | TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName)); | 
|  |  | 
|  | if ((!pPortName) || (!pPortName[0])) { | 
|  | SetLastError(ERROR_INVALID_PARAMETER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) { | 
|  | /* native localui tests here for LPT / COM - Ports and failed with | 
|  | ERROR_NOT_SUPPORTED. */ | 
|  | if (XcvDataW(hXcv, cmd_DeletePortW, (LPBYTE) pPortName, | 
|  | (lstrlenW(pPortName)+1) * sizeof(WCHAR), (LPBYTE) &dummy, 0, &needed, &status)) { | 
|  |  | 
|  | ClosePrinter(hXcv); | 
|  | if (status != ERROR_SUCCESS) SetLastError(status); | 
|  | return (status == ERROR_SUCCESS); | 
|  | } | 
|  | ClosePrinter(hXcv); | 
|  | return FALSE; | 
|  | } | 
|  | SetLastError(ERROR_UNKNOWN_PORT); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /***************************************************** | 
|  | *      InitializePrintMonitorUI  (LOCALUI.@) | 
|  | * | 
|  | * Initialize the User-Interface for the Local Ports | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: Pointer to a MONITORUI Structure | 
|  | *  Failure: NULL | 
|  | * | 
|  | */ | 
|  |  | 
|  | PMONITORUI WINAPI InitializePrintMonitorUI(void) | 
|  | { | 
|  | static MONITORUI mymonitorui = | 
|  | { | 
|  | sizeof(MONITORUI), | 
|  | localui_AddPortUI, | 
|  | localui_ConfigurePortUI, | 
|  | localui_DeletePortUI | 
|  | }; | 
|  |  | 
|  | TRACE("=> %p\n", &mymonitorui); | 
|  | return &mymonitorui; | 
|  | } | 
|  |  | 
|  | /***************************************************** | 
|  | *      DllMain | 
|  | */ | 
|  | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) | 
|  | { | 
|  | TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved); | 
|  |  | 
|  | switch(fdwReason) | 
|  | { | 
|  | case DLL_PROCESS_ATTACH: | 
|  | DisableThreadLibraryCalls( hinstDLL ); | 
|  | LOCALUI_hInstance = hinstDLL; | 
|  | break; | 
|  | } | 
|  | return TRUE; | 
|  | } |