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
24 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(comm
);
30 HMODULE SERIALUI_hModule
= 0;
32 /***********************************************************************
33 * SERIALUI_LibMain [Internal] Initializes the internal 'SERIALUI.DLL'.
36 * hinstDLL [I] handle to the DLL's instance
38 * lpvReserved [I] reserved, must be NULL
46 SERIALUI_LibMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
48 TRACE("%x,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
51 case DLL_PROCESS_ATTACH
:
52 SERIALUI_hModule
= hinstDLL
;
54 case DLL_PROCESS_DETACH
:
62 /***********************************************************************
63 * SERIALUI_EnumPropPages (SERIALUI.2)
65 * Called by the device manager to add prop sheets in Control Panel ???
66 * Pointed to in Win98 registry by
67 * \System\CurrentControlSet\Services\Class\ports\0000\EnumPropPages =
68 * "serialui.dll,EnumPropPages"
70 typedef LPVOID LPDEVICE_INFO
;
71 typedef LPVOID LPFNADDPROPSHEETPAGE
;
72 BOOL WINAPI
SERIALUI_EnumPropPages(LPDEVICE_INFO pdi
, LPFNADDPROPSHEETPAGE pfnAdd
, LPARAM lParam
)
74 FIXME("(%p %p %lx)\n",pdi
,pfnAdd
,lParam
);
79 * These data structures are convert from values used in fields of a DCB
80 * to strings used in the CommConfigDialog.
82 typedef struct tagPARAM2STRDATA
86 } PARAM2STRDATA
, *LPPARAM2STRDATA
;
88 typedef struct tagPARAM2STR
92 } PARAM2STR
, *LPPARAM2STR
;
93 typedef const LPPARAM2STR LPCPARAM2STR
;
95 #define SERIALUI_TABLESIZE(x) ((sizeof (x))/(sizeof (x[0])))
97 static PARAM2STRDATA SERIALUI_Baud2StrData
[]={
98 {110, "110"}, {300, "300"}, {600, "600"}, {1200, "1200"},
99 {2400, "2400"}, {4800, "4800"}, {9600, "9600"}, {14400, "14400"},
100 {19200, "19200"}, {38400L, "38400"}, {56000L, "56000"}, {57600L, "57600"},
101 {115200L, "115200"}, {128000L, "128000"}, {256000L, "256000"}
103 static PARAM2STR SERIALUI_Baud2Str
={ SERIALUI_TABLESIZE(SERIALUI_Baud2StrData
),SERIALUI_Baud2StrData
};
105 static PARAM2STRDATA SERIALUI_Parity2StrData
[]={
106 {NOPARITY
,"None"}, {ODDPARITY
,"Odd"}, {EVENPARITY
,"Even"}, {MARKPARITY
,"Mark"},
107 {SPACEPARITY
,"Space"}
109 static PARAM2STR SERIALUI_Parity2Str
={ SERIALUI_TABLESIZE(SERIALUI_Parity2StrData
),SERIALUI_Parity2StrData
};
111 static PARAM2STRDATA SERIALUI_Stop2StrData
[]={
112 {ONESTOPBIT
,"1"}, {ONE5STOPBITS
,"1.5"}, {TWOSTOPBITS
,"2"}
114 static PARAM2STR SERIALUI_Stop2Str
={ SERIALUI_TABLESIZE(SERIALUI_Stop2StrData
),SERIALUI_Stop2StrData
};
116 static PARAM2STRDATA SERIALUI_Data2StrData
[]={
117 {5,"5"}, {6,"6"}, {7,"7"}, {8, "8"}, {16,"16"}
119 static PARAM2STR SERIALUI_Data2Str
={ SERIALUI_TABLESIZE(SERIALUI_Data2StrData
),SERIALUI_Data2StrData
};
121 static PARAM2STRDATA SERIALUI_Flow2StrData
[]={
122 {0,"None"}, {1,"Hardware (RTS/CTS)"}, {2,"Software (XON/XOFF)"}
124 static PARAM2STR SERIALUI_Flow2Str
={ SERIALUI_TABLESIZE(SERIALUI_Flow2StrData
),SERIALUI_Flow2StrData
};
127 * Add all the fields to a combo box and highlight the current value
129 static void SERIALUI_AddConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, DWORD dwVal
)
132 HWND hControl
= GetDlgItem(hDlg
,id
);
137 for(i
=0; i
<table
->dwSize
; i
++)
139 n
= SendMessageA(hControl
, CB_ADDSTRING
, 0L, (LPARAM
)table
->data
[i
].name
);
140 if(dwVal
== table
->data
[i
].val
)
142 SendMessageA(hControl
, CB_SETCURSEL
, (WPARAM
)n
, (LPARAM
)0);
148 * Get the current sellection of the given combo box and set a DCB field to
149 * the value matching that selection.
151 static BOOL
SERIALUI_GetConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, LPDWORD lpdwVal
)
155 HWND hControl
= GetDlgItem(hDlg
,id
);
157 if( (!hControl
) || (!lpdwVal
))
159 TRACE("Couldn't get window handle for item %lx\n",id
);
163 if(!GetWindowTextA(hControl
, &lpEntry
[0], sizeof lpEntry
))
165 TRACE("Couldn't get window text for item %lx\n",id
);
168 /* TRACE("%ld contains %s\n",id, lpEntry); */
170 for(i
=0; i
<table
->dwSize
; i
++)
172 if(!lstrcmpA(table
->data
[i
].name
,lpEntry
))
174 *lpdwVal
= table
->data
[i
].val
;
183 * Both the enumerated values CBR_XXXX and integer baud rates are valid
184 * dcb.BaudRate. This code is to convert back and forth between CBR_ style
185 * and integers. The dialog box uses integer values.
187 static DWORD SERIALUI_BaudConvertTable
[] = {
188 CBR_110
, 110, CBR_300
, 300, CBR_600
, 600, CBR_1200
, 1200,
189 CBR_2400
, 2400, CBR_4800
, 4800, CBR_9600
, 9600, CBR_14400
, 14400,
190 CBR_19200
, 19200, CBR_38400
, 38400, CBR_56000
, 56000, CBR_57600
, 57600,
191 CBR_115200
, 115200, CBR_128000
, 128000, CBR_256000
, 256000
194 static BOOL
SERIALUI_MakeBaudDword(LPDWORD lpdwBaudRate
)
198 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
200 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
])
202 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
+1];
209 static BOOL
SERIALUI_MakeBaudEnum(LPDWORD lpdwBaudRate
)
213 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
215 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
+1])
217 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
];
224 typedef struct tagSERIALUI_DialogInfo
227 LPCOMMCONFIG lpCommConfig
;
228 BOOL bConvert
; /* baud rate was converted to a DWORD */
229 DWORD dwFlowControl
; /* old flow control */
230 } SERIALUI_DialogInfo
;
232 static void SERIALUI_DCBToDialogInfo(HWND hDlg
, SERIALUI_DialogInfo
*info
)
234 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
235 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
237 /* pass integer pointers to SERIALUI_ dialog config fns */
238 dwBaudRate
= lpdcb
->BaudRate
;
239 dwStopBits
= lpdcb
->StopBits
;
240 dwParity
= lpdcb
->Parity
;
241 dwByteSize
= lpdcb
->ByteSize
;
243 /* map flow control state, if it looks normal */
244 if((lpdcb
->fRtsControl
== RTS_CONTROL_HANDSHAKE
) ||
245 (lpdcb
->fOutxCtsFlow
== TRUE
)) {
247 } else if(lpdcb
->fOutX
|| lpdcb
->fInX
) {
253 info
->bConvert
= SERIALUI_MakeBaudDword(&dwBaudRate
);
255 SERIALUI_AddConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
,dwBaudRate
);
256 SERIALUI_AddConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
,dwStopBits
);
257 SERIALUI_AddConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
,dwParity
);
258 SERIALUI_AddConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
,dwByteSize
);
259 SERIALUI_AddConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, dwFlowControl
);
261 info
->dwFlowControl
= dwFlowControl
;
264 static void SERIALUI_DialogInfoToDCB(HWND hDlg
, SERIALUI_DialogInfo
*info
)
266 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
267 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
269 SERIALUI_GetConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
, &dwBaudRate
);
270 SERIALUI_GetConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
, &dwStopBits
);
271 SERIALUI_GetConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
, &dwParity
);
272 SERIALUI_GetConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
, &dwByteSize
);
273 SERIALUI_GetConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, &dwFlowControl
);
275 TRACE("baud=%ld stop=%ld parity=%ld data=%ld flow=%ld\n",
276 dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
);
278 lpdcb
->BaudRate
= dwBaudRate
;
279 lpdcb
->StopBits
= dwStopBits
;
280 lpdcb
->Parity
= dwParity
;
281 lpdcb
->ByteSize
= dwByteSize
;
283 /* try not to change flow control if the user didn't change it */
284 if(info
->dwFlowControl
!= dwFlowControl
)
286 switch(dwFlowControl
)
289 lpdcb
->fOutxCtsFlow
= FALSE
;
290 lpdcb
->fOutxDsrFlow
= FALSE
;
291 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
292 lpdcb
->fOutX
= FALSE
;
294 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
296 case 1: /* CTS/RTS */
297 lpdcb
->fOutxCtsFlow
= TRUE
;
298 lpdcb
->fOutxDsrFlow
= FALSE
;
299 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
300 lpdcb
->fOutX
= FALSE
;
302 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
305 lpdcb
->fOutxCtsFlow
= FALSE
;
306 lpdcb
->fOutxDsrFlow
= FALSE
;
307 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
310 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
316 SERIALUI_MakeBaudEnum(&lpdcb
->BaudRate
);
319 /***********************************************************************
320 * SERIALUI_ConfigDialogProc
322 * Shows a dialog for configuring a COMM port
324 BOOL WINAPI
SERIALUI_ConfigDialogProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
327 SERIALUI_DialogInfo
*info
;
332 info
= (SERIALUI_DialogInfo
*) lParam
;
335 SetWindowLongA(hWnd
, DWL_USER
, lParam
);
336 snprintf(szTitle
, sizeof szTitle
, "Settings for %s", info
->lpszDevice
);
337 SetWindowTextA(hWnd
, szTitle
);
338 SERIALUI_DCBToDialogInfo(hWnd
, info
);
343 WORD wID
= LOWORD(wParam
);
345 info
= (SERIALUI_DialogInfo
*) GetWindowLongA(hWnd
, DWL_USER
);
351 SERIALUI_DialogInfoToDCB(hWnd
,info
);
357 /* test code for Get/SetDefaultCommConfig begins */
360 DWORD r
,dwConfSize
= sizeof (COMMCONFIG
);
361 r
= GetDefaultCommConfigA(info
->lpszDevice
,
362 info
->lpCommConfig
, &dwConfSize
);
364 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
366 SERIALUI_DCBToDialogInfo(hWnd
, info
);
371 SERIALUI_DialogInfoToDCB(hWnd
,info
);
372 r
= SetDefaultCommConfigA(info
->lpszDevice
,
373 info
->lpCommConfig
, sizeof (COMMCONFIG
));
375 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
378 /* test code for Get/SetDefaultCommConfig ends */
386 /***********************************************************************
387 * SERIALUI_CommConfigDialog (SERIALUI.3)
389 * Used by Win9x KERNEL to show a dialog for configuring a COMM port.
391 BOOL WINAPI
SERIALUI_CommConfigDialog(
394 LPCOMMCONFIG lpCommConfig
396 SERIALUI_DialogInfo info
;
398 info
.lpCommConfig
= lpCommConfig
;
399 info
.lpszDevice
= lpszName
;
400 info
.bConvert
= FALSE
;
401 info
.dwFlowControl
= 0;
406 return DialogBoxParamA(SERIALUI_hModule
,
407 MAKEINTRESOURCEA(IDD_SERIALUICONFIG
),
409 (DLGPROC
) SERIALUI_ConfigDialogProc
,
413 static LPCSTR lpszCommKey
= "System\\CurrentControlSet\\Services\\Class\\Ports";
414 static LPCSTR lpszDCB
= "DCB";
416 /***********************************************************************
417 * SERIALUI_SetDefaultCommConfig (SERIALUI.4)
419 * Used by Win98 KERNEL to set the default config for a COMM port
420 * FIXME: uses the wrong registry key... should use a digit, not
421 * the comm port name.
423 BOOL WINAPI
SERIALUI_SetDefaultCommConfig(
425 LPCOMMCONFIG lpCommConfig
,
428 HKEY hKeyReg
=0, hKeyPort
=0;
432 TRACE("%p %p %lx\n",lpszDevice
,lpCommConfig
,dwSize
);
437 if(dwSize
< sizeof (COMMCONFIG
))
440 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
441 if(r
!= ERROR_SUCCESS
)
444 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
445 r
= RegCreateKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
446 if(r
== ERROR_SUCCESS
)
448 dwDCBSize
= sizeof (DCB
);
449 r
= RegSetValueExA( hKeyPort
, lpszDCB
, 0, REG_BINARY
,
450 (LPSTR
)&lpCommConfig
->dcb
,dwDCBSize
);
451 TRACE("write key r=%ld\n",r
);
452 RegCloseKey(hKeyPort
);
455 RegCloseKey(hKeyReg
);
457 return (r
==ERROR_SUCCESS
);
460 /***********************************************************************
461 * SERIALUI_GetDefaultCommConfig (SERIALUI.5)
463 * Used by Win9x KERNEL to get the default config for a COMM port
464 * FIXME: uses the wrong registry key... should use a digit, not
465 * the comm port name.
467 BOOL WINAPI
SERIALUI_GetDefaultCommConfig(
469 LPCOMMCONFIG lpCommConfig
,
472 HKEY hKeyReg
, hKeyPort
;
474 DWORD r
,dwSize
,dwType
;
476 TRACE("%p %p %p\n",lpszDevice
,lpCommConfig
,lpdwSize
);
484 if(*lpdwSize
< sizeof (COMMCONFIG
))
487 *lpdwSize
= sizeof (COMMCONFIG
);
488 memset(lpCommConfig
, 0 , sizeof (COMMCONFIG
));
489 lpCommConfig
->dwSize
= sizeof (COMMCONFIG
);
490 lpCommConfig
->wVersion
= 1;
492 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
493 if(r
!= ERROR_SUCCESS
)
496 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
497 r
= RegOpenKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
498 if(r
== ERROR_SUCCESS
)
500 dwSize
= sizeof (DCB
);
502 r
= RegQueryValueExA( hKeyPort
, lpszDCB
, NULL
,
503 &dwType
, (LPSTR
)&lpCommConfig
->dcb
,&dwSize
);
504 if ((r
==ERROR_SUCCESS
) && (dwType
!= REG_BINARY
))
506 if ((r
==ERROR_SUCCESS
) && (dwSize
!= sizeof(DCB
)))
509 RegCloseKey(hKeyPort
);
513 /* FIXME: default to a hardcoded commconfig */
515 lpCommConfig
->dcb
.DCBlength
= sizeof(DCB
);
516 lpCommConfig
->dcb
.BaudRate
= 9600;
517 lpCommConfig
->dcb
.fBinary
= TRUE
;
518 lpCommConfig
->dcb
.fParity
= FALSE
;
519 lpCommConfig
->dcb
.ByteSize
= 8;
520 lpCommConfig
->dcb
.Parity
= NOPARITY
;
521 lpCommConfig
->dcb
.StopBits
= ONESTOPBIT
;
525 RegCloseKey(hKeyReg
);
527 return (r
==ERROR_SUCCESS
);