2 * This DLL contains the user interface for the serial driver.
3 * a dialog box to configure the specified COMM port
4 * an interface to the control panel (??)
5 * functions to load and save default configuration
7 * Eventually the 32 bit comm port driver could be moved into here
8 * and interfaced to KERNEL32 using the WIN95 or WINNT comm driver interface.
9 * This way, different driver DLLS could be written to support other
10 * serial interfaces, such as X.25, etc.
12 * Basic structure copied from COMCTL32 code.
14 * Copyright 2000 Mike McCormack
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/port.h"
41 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
47 HMODULE SERIALUI_hModule
= 0;
49 /***********************************************************************
50 * SERIALUI_LibMain [Internal] Initializes the internal 'SERIALUI.DLL'.
53 * hinstDLL [I] handle to the DLL's instance
55 * lpvReserved [I] reserved, must be NULL
63 SERIALUI_LibMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
65 TRACE("%x,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
68 case DLL_PROCESS_ATTACH
:
69 SERIALUI_hModule
= hinstDLL
;
71 case DLL_PROCESS_DETACH
:
79 /***********************************************************************
80 * EnumPropPages (SERIALUI.2)
82 * Called by the device manager to add prop sheets in Control Panel ???
83 * Pointed to in Win98 registry by
84 * \System\CurrentControlSet\Services\Class\ports\0000\EnumPropPages =
85 * "serialui.dll,EnumPropPages"
87 typedef LPVOID LPDEVICE_INFO
;
88 typedef LPVOID LPFNADDPROPSHEETPAGE
;
89 BOOL WINAPI
SERIALUI_EnumPropPages(LPDEVICE_INFO pdi
, LPFNADDPROPSHEETPAGE pfnAdd
, LPARAM lParam
)
91 FIXME("(%p %p %lx)\n",pdi
,pfnAdd
,lParam
);
96 * These data structures are convert from values used in fields of a DCB
97 * to strings used in the CommConfigDialog.
99 typedef struct tagPARAM2STRDATA
103 } PARAM2STRDATA
, *LPPARAM2STRDATA
;
105 typedef struct tagPARAM2STR
108 LPPARAM2STRDATA data
;
109 } PARAM2STR
, *LPPARAM2STR
;
110 typedef const LPPARAM2STR LPCPARAM2STR
;
112 #define SERIALUI_TABLESIZE(x) ((sizeof (x))/(sizeof (x[0])))
114 static PARAM2STRDATA SERIALUI_Baud2StrData
[]={
115 {110, "110"}, {300, "300"}, {600, "600"}, {1200, "1200"},
116 {2400, "2400"}, {4800, "4800"}, {9600, "9600"}, {14400, "14400"},
117 {19200, "19200"}, {38400L, "38400"}, {56000L, "56000"}, {57600L, "57600"},
118 {115200L, "115200"}, {128000L, "128000"}, {256000L, "256000"}
120 static PARAM2STR SERIALUI_Baud2Str
={ SERIALUI_TABLESIZE(SERIALUI_Baud2StrData
),SERIALUI_Baud2StrData
};
122 static PARAM2STRDATA SERIALUI_Parity2StrData
[]={
123 {NOPARITY
,"None"}, {ODDPARITY
,"Odd"}, {EVENPARITY
,"Even"}, {MARKPARITY
,"Mark"},
124 {SPACEPARITY
,"Space"}
126 static PARAM2STR SERIALUI_Parity2Str
={ SERIALUI_TABLESIZE(SERIALUI_Parity2StrData
),SERIALUI_Parity2StrData
};
128 static PARAM2STRDATA SERIALUI_Stop2StrData
[]={
129 {ONESTOPBIT
,"1"}, {ONE5STOPBITS
,"1.5"}, {TWOSTOPBITS
,"2"}
131 static PARAM2STR SERIALUI_Stop2Str
={ SERIALUI_TABLESIZE(SERIALUI_Stop2StrData
),SERIALUI_Stop2StrData
};
133 static PARAM2STRDATA SERIALUI_Data2StrData
[]={
134 {5,"5"}, {6,"6"}, {7,"7"}, {8, "8"}, {16,"16"}
136 static PARAM2STR SERIALUI_Data2Str
={ SERIALUI_TABLESIZE(SERIALUI_Data2StrData
),SERIALUI_Data2StrData
};
138 static PARAM2STRDATA SERIALUI_Flow2StrData
[]={
139 {0,"None"}, {1,"Hardware (RTS/CTS)"}, {2,"Software (XON/XOFF)"}
141 static PARAM2STR SERIALUI_Flow2Str
={ SERIALUI_TABLESIZE(SERIALUI_Flow2StrData
),SERIALUI_Flow2StrData
};
144 * Add all the fields to a combo box and highlight the current value
146 static void SERIALUI_AddConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, DWORD dwVal
)
149 HWND hControl
= GetDlgItem(hDlg
,id
);
154 for(i
=0; i
<table
->dwSize
; i
++)
156 n
= SendMessageA(hControl
, CB_ADDSTRING
, 0L, (LPARAM
)table
->data
[i
].name
);
157 if(dwVal
== table
->data
[i
].val
)
159 SendMessageA(hControl
, CB_SETCURSEL
, (WPARAM
)n
, (LPARAM
)0);
165 * Get the current sellection of the given combo box and set a DCB field to
166 * the value matching that selection.
168 static BOOL
SERIALUI_GetConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, LPDWORD lpdwVal
)
172 HWND hControl
= GetDlgItem(hDlg
,id
);
174 if( (!hControl
) || (!lpdwVal
))
176 TRACE("Couldn't get window handle for item %lx\n",id
);
180 if(!GetWindowTextA(hControl
, &lpEntry
[0], sizeof lpEntry
))
182 TRACE("Couldn't get window text for item %lx\n",id
);
185 /* TRACE("%ld contains %s\n",id, lpEntry); */
187 for(i
=0; i
<table
->dwSize
; i
++)
189 if(!lstrcmpA(table
->data
[i
].name
,lpEntry
))
191 *lpdwVal
= table
->data
[i
].val
;
200 * Both the enumerated values CBR_XXXX and integer baud rates are valid
201 * dcb.BaudRate. This code is to convert back and forth between CBR_ style
202 * and integers. The dialog box uses integer values.
204 static DWORD SERIALUI_BaudConvertTable
[] = {
205 CBR_110
, 110, CBR_300
, 300, CBR_600
, 600, CBR_1200
, 1200,
206 CBR_2400
, 2400, CBR_4800
, 4800, CBR_9600
, 9600, CBR_14400
, 14400,
207 CBR_19200
, 19200, CBR_38400
, 38400, CBR_56000
, 56000, CBR_57600
, 57600,
208 CBR_115200
, 115200, CBR_128000
, 128000, CBR_256000
, 256000
211 static BOOL
SERIALUI_MakeBaudDword(LPDWORD lpdwBaudRate
)
215 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
217 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
])
219 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
+1];
226 static BOOL
SERIALUI_MakeBaudEnum(LPDWORD lpdwBaudRate
)
230 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
232 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
+1])
234 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
];
241 typedef struct tagSERIALUI_DialogInfo
244 LPCOMMCONFIG lpCommConfig
;
245 BOOL bConvert
; /* baud rate was converted to a DWORD */
246 DWORD dwFlowControl
; /* old flow control */
247 } SERIALUI_DialogInfo
;
249 static void SERIALUI_DCBToDialogInfo(HWND hDlg
, SERIALUI_DialogInfo
*info
)
251 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
252 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
254 /* pass integer pointers to SERIALUI_ dialog config fns */
255 dwBaudRate
= lpdcb
->BaudRate
;
256 dwStopBits
= lpdcb
->StopBits
;
257 dwParity
= lpdcb
->Parity
;
258 dwByteSize
= lpdcb
->ByteSize
;
260 /* map flow control state, if it looks normal */
261 if((lpdcb
->fRtsControl
== RTS_CONTROL_HANDSHAKE
) ||
262 (lpdcb
->fOutxCtsFlow
== TRUE
)) {
264 } else if(lpdcb
->fOutX
|| lpdcb
->fInX
) {
270 info
->bConvert
= SERIALUI_MakeBaudDword(&dwBaudRate
);
272 SERIALUI_AddConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
,dwBaudRate
);
273 SERIALUI_AddConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
,dwStopBits
);
274 SERIALUI_AddConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
,dwParity
);
275 SERIALUI_AddConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
,dwByteSize
);
276 SERIALUI_AddConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, dwFlowControl
);
278 info
->dwFlowControl
= dwFlowControl
;
281 static void SERIALUI_DialogInfoToDCB(HWND hDlg
, SERIALUI_DialogInfo
*info
)
283 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
284 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
286 SERIALUI_GetConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
, &dwBaudRate
);
287 SERIALUI_GetConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
, &dwStopBits
);
288 SERIALUI_GetConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
, &dwParity
);
289 SERIALUI_GetConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
, &dwByteSize
);
290 SERIALUI_GetConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, &dwFlowControl
);
292 TRACE("baud=%ld stop=%ld parity=%ld data=%ld flow=%ld\n",
293 dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
);
295 lpdcb
->BaudRate
= dwBaudRate
;
296 lpdcb
->StopBits
= dwStopBits
;
297 lpdcb
->Parity
= dwParity
;
298 lpdcb
->ByteSize
= dwByteSize
;
300 /* try not to change flow control if the user didn't change it */
301 if(info
->dwFlowControl
!= dwFlowControl
)
303 switch(dwFlowControl
)
306 lpdcb
->fOutxCtsFlow
= FALSE
;
307 lpdcb
->fOutxDsrFlow
= FALSE
;
308 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
309 lpdcb
->fOutX
= FALSE
;
311 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
313 case 1: /* CTS/RTS */
314 lpdcb
->fOutxCtsFlow
= TRUE
;
315 lpdcb
->fOutxDsrFlow
= FALSE
;
316 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
317 lpdcb
->fOutX
= FALSE
;
319 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
322 lpdcb
->fOutxCtsFlow
= FALSE
;
323 lpdcb
->fOutxDsrFlow
= FALSE
;
324 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
327 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
333 SERIALUI_MakeBaudEnum(&lpdcb
->BaudRate
);
336 /***********************************************************************
337 * SERIALUI_ConfigDialogProc
339 * Shows a dialog for configuring a COMM port
341 BOOL WINAPI
SERIALUI_ConfigDialogProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
344 SERIALUI_DialogInfo
*info
;
349 info
= (SERIALUI_DialogInfo
*) lParam
;
352 SetWindowLongA(hWnd
, DWL_USER
, lParam
);
353 snprintf(szTitle
, sizeof szTitle
, "Settings for %s", info
->lpszDevice
);
354 SetWindowTextA(hWnd
, szTitle
);
355 SERIALUI_DCBToDialogInfo(hWnd
, info
);
360 WORD wID
= LOWORD(wParam
);
362 info
= (SERIALUI_DialogInfo
*) GetWindowLongA(hWnd
, DWL_USER
);
368 SERIALUI_DialogInfoToDCB(hWnd
,info
);
374 /* test code for Get/SetDefaultCommConfig begins */
377 DWORD r
,dwConfSize
= sizeof (COMMCONFIG
);
378 r
= GetDefaultCommConfigA(info
->lpszDevice
,
379 info
->lpCommConfig
, &dwConfSize
);
381 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
383 SERIALUI_DCBToDialogInfo(hWnd
, info
);
388 SERIALUI_DialogInfoToDCB(hWnd
,info
);
389 r
= SetDefaultCommConfigA(info
->lpszDevice
,
390 info
->lpCommConfig
, sizeof (COMMCONFIG
));
392 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
395 /* test code for Get/SetDefaultCommConfig ends */
403 /***********************************************************************
404 * drvCommConfigDialog (SERIALUI.3)
406 * Used by Win9x KERNEL to show a dialog for configuring a COMM port.
408 BOOL WINAPI
SERIALUI_CommConfigDialog(
411 LPCOMMCONFIG lpCommConfig
413 SERIALUI_DialogInfo info
;
415 info
.lpCommConfig
= lpCommConfig
;
416 info
.lpszDevice
= lpszName
;
417 info
.bConvert
= FALSE
;
418 info
.dwFlowControl
= 0;
423 return DialogBoxParamA(SERIALUI_hModule
,
424 MAKEINTRESOURCEA(IDD_SERIALUICONFIG
),
426 (DLGPROC
) SERIALUI_ConfigDialogProc
,
430 static LPCSTR lpszCommKey
= "System\\CurrentControlSet\\Services\\Class\\Ports";
431 static LPCSTR lpszDCB
= "DCB";
433 /***********************************************************************
434 * drvSetDefaultCommConfig (SERIALUI.4)
436 * Used by Win98 KERNEL to set the default config for a COMM port
437 * FIXME: uses the wrong registry key... should use a digit, not
438 * the comm port name.
440 BOOL WINAPI
SERIALUI_SetDefaultCommConfig(
442 LPCOMMCONFIG lpCommConfig
,
445 HKEY hKeyReg
=0, hKeyPort
=0;
449 TRACE("%p %p %lx\n",lpszDevice
,lpCommConfig
,dwSize
);
454 if(dwSize
< sizeof (COMMCONFIG
))
457 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
458 if(r
!= ERROR_SUCCESS
)
461 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
462 r
= RegCreateKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
463 if(r
== ERROR_SUCCESS
)
465 dwDCBSize
= sizeof (DCB
);
466 r
= RegSetValueExA( hKeyPort
, lpszDCB
, 0, REG_BINARY
,
467 (LPSTR
)&lpCommConfig
->dcb
,dwDCBSize
);
468 TRACE("write key r=%ld\n",r
);
469 RegCloseKey(hKeyPort
);
472 RegCloseKey(hKeyReg
);
474 return (r
==ERROR_SUCCESS
);
477 /***********************************************************************
478 * drvGetDefaultCommConfig (SERIALUI.5)
480 * Used by Win9x KERNEL to get the default config for a COMM port
481 * FIXME: uses the wrong registry key... should use a digit, not
482 * the comm port name.
484 BOOL WINAPI
SERIALUI_GetDefaultCommConfig(
486 LPCOMMCONFIG lpCommConfig
,
489 HKEY hKeyReg
, hKeyPort
;
491 DWORD r
,dwSize
,dwType
;
493 TRACE("%p %p %p\n",lpszDevice
,lpCommConfig
,lpdwSize
);
501 if(*lpdwSize
< sizeof (COMMCONFIG
))
504 *lpdwSize
= sizeof (COMMCONFIG
);
505 memset(lpCommConfig
, 0 , sizeof (COMMCONFIG
));
506 lpCommConfig
->dwSize
= sizeof (COMMCONFIG
);
507 lpCommConfig
->wVersion
= 1;
509 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
510 if(r
!= ERROR_SUCCESS
)
513 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
514 r
= RegOpenKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
515 if(r
== ERROR_SUCCESS
)
517 dwSize
= sizeof (DCB
);
519 r
= RegQueryValueExA( hKeyPort
, lpszDCB
, NULL
,
520 &dwType
, (LPSTR
)&lpCommConfig
->dcb
,&dwSize
);
521 if ((r
==ERROR_SUCCESS
) && (dwType
!= REG_BINARY
))
523 if ((r
==ERROR_SUCCESS
) && (dwSize
!= sizeof(DCB
)))
526 RegCloseKey(hKeyPort
);
530 /* FIXME: default to a hardcoded commconfig */
532 lpCommConfig
->dcb
.DCBlength
= sizeof(DCB
);
533 lpCommConfig
->dcb
.BaudRate
= 9600;
534 lpCommConfig
->dcb
.fBinary
= TRUE
;
535 lpCommConfig
->dcb
.fParity
= FALSE
;
536 lpCommConfig
->dcb
.ByteSize
= 8;
537 lpCommConfig
->dcb
.Parity
= NOPARITY
;
538 lpCommConfig
->dcb
.StopBits
= ONESTOPBIT
;
542 RegCloseKey(hKeyReg
);
544 return (r
==ERROR_SUCCESS
);