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;
31 DWORD SERIALUI_dwProcessesAttached
= 0;
33 /***********************************************************************
34 * SERIALUI_LibMain [Internal] Initializes the internal 'SERIALUI.DLL'.
37 * hinstDLL [I] handle to the DLL's instance
39 * lpvReserved [I] reserved, must be NULL
47 SERIALUI_LibMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
49 TRACE("%x,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
52 case DLL_PROCESS_ATTACH
:
53 if (SERIALUI_dwProcessesAttached
== 0) {
55 /* This will be wrong for any other process attching in this address-space! */
56 SERIALUI_hModule
= (HMODULE
)hinstDLL
;
59 SERIALUI_dwProcessesAttached
++;
62 case DLL_PROCESS_DETACH
:
63 SERIALUI_dwProcessesAttached
--;
64 if (SERIALUI_dwProcessesAttached
== 0) {
65 TRACE("Last Process detached\n");
74 /***********************************************************************
75 * SERIALUI_EnumPropPages (SERIALUI.2)
77 * Called by the device manager to add prop sheets in Control Panel ???
78 * Pointed to in Win98 registry by
79 * \System\CurrentControlSet\Services\Class\ports\0000\EnumPropPages =
80 * "serialui.dll,EnumPropPages"
82 typedef LPVOID LPDEVICE_INFO
;
83 typedef LPVOID LPFNADDPROPSHEETPAGE
;
84 BOOL WINAPI
SERIALUI_EnumPropPages(LPDEVICE_INFO pdi
, LPFNADDPROPSHEETPAGE pfnAdd
, LPARAM lParam
)
86 FIXME("(%p %p %lx)\n",pdi
,pfnAdd
,lParam
);
91 * These data structures are convert from values used in fields of a DCB
92 * to strings used in the CommConfigDialog.
94 typedef struct tagPARAM2STRDATA
98 } PARAM2STRDATA
, *LPPARAM2STRDATA
;
100 typedef struct tagPARAM2STR
103 LPPARAM2STRDATA data
;
104 } PARAM2STR
, *LPPARAM2STR
;
105 typedef const LPPARAM2STR LPCPARAM2STR
;
107 #define SERIALUI_TABLESIZE(x) ((sizeof (x))/(sizeof (x[0])))
109 static PARAM2STRDATA SERIALUI_Baud2StrData
[]={
110 {110, "110"}, {300, "300"}, {600, "600"}, {1200, "1200"},
111 {2400, "2400"}, {4800, "4800"}, {9600, "9600"}, {14400, "14400"},
112 {19200, "19200"}, {38400L, "38400"}, {56000L, "56000"}, {57600L, "57600"},
113 {115200L, "115200"}, {128000L, "128000"}, {256000L, "256000"}
115 static PARAM2STR SERIALUI_Baud2Str
={ SERIALUI_TABLESIZE(SERIALUI_Baud2StrData
),SERIALUI_Baud2StrData
};
117 static PARAM2STRDATA SERIALUI_Parity2StrData
[]={
118 {NOPARITY
,"None"}, {ODDPARITY
,"Odd"}, {EVENPARITY
,"Even"}, {MARKPARITY
,"Mark"},
119 {SPACEPARITY
,"Space"}
121 static PARAM2STR SERIALUI_Parity2Str
={ SERIALUI_TABLESIZE(SERIALUI_Parity2StrData
),SERIALUI_Parity2StrData
};
123 static PARAM2STRDATA SERIALUI_Stop2StrData
[]={
124 {ONESTOPBIT
,"1"}, {ONE5STOPBITS
,"1.5"}, {TWOSTOPBITS
,"2"}
126 static PARAM2STR SERIALUI_Stop2Str
={ SERIALUI_TABLESIZE(SERIALUI_Stop2StrData
),SERIALUI_Stop2StrData
};
128 static PARAM2STRDATA SERIALUI_Data2StrData
[]={
129 {5,"5"}, {6,"6"}, {7,"7"}, {8, "8"}, {16,"16"}
131 static PARAM2STR SERIALUI_Data2Str
={ SERIALUI_TABLESIZE(SERIALUI_Data2StrData
),SERIALUI_Data2StrData
};
133 static PARAM2STRDATA SERIALUI_Flow2StrData
[]={
134 {0,"None"}, {1,"Hardware (RTS/CTS)"}, {2,"Software (XON/XOFF)"}
136 static PARAM2STR SERIALUI_Flow2Str
={ SERIALUI_TABLESIZE(SERIALUI_Flow2StrData
),SERIALUI_Flow2StrData
};
139 * Add all the fields to a combo box and highlight the current value
141 static void SERIALUI_AddConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, DWORD dwVal
)
144 HWND hControl
= GetDlgItem(hDlg
,id
);
149 for(i
=0; i
<table
->dwSize
; i
++)
151 n
= SendMessageA(hControl
, CB_ADDSTRING
, 0L, (LPARAM
)table
->data
[i
].name
);
152 if(dwVal
== table
->data
[i
].val
)
154 SendMessageA(hControl
, CB_SETCURSEL
, (WPARAM
)n
, (LPARAM
)0);
160 * Get the current sellection of the given combo box and set a DCB field to
161 * the value matching that selection.
163 static BOOL
SERIALUI_GetConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, LPDWORD lpdwVal
)
167 HWND hControl
= GetDlgItem(hDlg
,id
);
169 if( (!hControl
) || (!lpdwVal
))
171 TRACE("Couldn't get window handle for item %lx\n",id
);
175 if(!GetWindowTextA(hControl
, &lpEntry
[0], sizeof lpEntry
))
177 TRACE("Couldn't get window text for item %lx\n",id
);
180 /* TRACE("%ld contains %s\n",id, lpEntry); */
182 for(i
=0; i
<table
->dwSize
; i
++)
184 if(!lstrcmpA(table
->data
[i
].name
,lpEntry
))
186 *lpdwVal
= table
->data
[i
].val
;
195 * Both the enumerated values CBR_XXXX and integer baud rates are valid
196 * dcb.BaudRate. This code is to convert back and forth between CBR_ style
197 * and integers. The dialog box uses integer values.
199 static DWORD SERIALUI_BaudConvertTable
[] = {
200 CBR_110
, 110, CBR_300
, 300, CBR_600
, 600, CBR_1200
, 1200,
201 CBR_2400
, 2400, CBR_4800
, 4800, CBR_9600
, 9600, CBR_14400
, 14400,
202 CBR_19200
, 19200, CBR_38400
, 38400, CBR_56000
, 56000, CBR_57600
, 57600,
203 CBR_115200
, 115200, CBR_128000
, 128000, CBR_256000
, 256000
206 static BOOL
SERIALUI_MakeBaudDword(LPDWORD lpdwBaudRate
)
210 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
212 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
])
214 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
+1];
221 static BOOL
SERIALUI_MakeBaudEnum(LPDWORD lpdwBaudRate
)
225 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
227 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
+1])
229 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
];
236 typedef struct tagSERIALUI_DialogInfo
239 LPCOMMCONFIG lpCommConfig
;
240 BOOL bConvert
; /* baud rate was converted to a DWORD */
241 DWORD dwFlowControl
; /* old flow control */
242 } SERIALUI_DialogInfo
;
244 static void SERIALUI_DCBToDialogInfo(HWND hDlg
, SERIALUI_DialogInfo
*info
)
246 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
247 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
249 /* pass integer pointers to SERIALUI_ dialog config fns */
250 dwBaudRate
= lpdcb
->BaudRate
;
251 dwStopBits
= lpdcb
->StopBits
;
252 dwParity
= lpdcb
->Parity
;
253 dwByteSize
= lpdcb
->ByteSize
;
255 /* map flow control state, if it looks normal */
256 if((lpdcb
->fRtsControl
== RTS_CONTROL_HANDSHAKE
) ||
257 (lpdcb
->fOutxCtsFlow
== TRUE
)) {
259 } else if(lpdcb
->fOutX
|| lpdcb
->fInX
) {
265 info
->bConvert
= SERIALUI_MakeBaudDword(&dwBaudRate
);
267 SERIALUI_AddConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
,dwBaudRate
);
268 SERIALUI_AddConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
,dwStopBits
);
269 SERIALUI_AddConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
,dwParity
);
270 SERIALUI_AddConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
,dwByteSize
);
271 SERIALUI_AddConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, dwFlowControl
);
273 info
->dwFlowControl
= dwFlowControl
;
276 static void SERIALUI_DialogInfoToDCB(HWND hDlg
, SERIALUI_DialogInfo
*info
)
278 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
279 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
281 SERIALUI_GetConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
, &dwBaudRate
);
282 SERIALUI_GetConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
, &dwStopBits
);
283 SERIALUI_GetConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
, &dwParity
);
284 SERIALUI_GetConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
, &dwByteSize
);
285 SERIALUI_GetConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, &dwFlowControl
);
287 TRACE("baud=%ld stop=%ld parity=%ld data=%ld flow=%ld\n",
288 dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
);
290 lpdcb
->BaudRate
= dwBaudRate
;
291 lpdcb
->StopBits
= dwStopBits
;
292 lpdcb
->Parity
= dwParity
;
293 lpdcb
->ByteSize
= dwByteSize
;
295 /* try not to change flow control if the user didn't change it */
296 if(info
->dwFlowControl
!= dwFlowControl
)
298 switch(dwFlowControl
)
301 lpdcb
->fOutxCtsFlow
= FALSE
;
302 lpdcb
->fOutxDsrFlow
= FALSE
;
303 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
304 lpdcb
->fOutX
= FALSE
;
306 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
308 case 1: /* CTS/RTS */
309 lpdcb
->fOutxCtsFlow
= TRUE
;
310 lpdcb
->fOutxDsrFlow
= FALSE
;
311 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
312 lpdcb
->fOutX
= FALSE
;
314 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
317 lpdcb
->fOutxCtsFlow
= FALSE
;
318 lpdcb
->fOutxDsrFlow
= FALSE
;
319 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
322 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
328 SERIALUI_MakeBaudEnum(&lpdcb
->BaudRate
);
331 /***********************************************************************
332 * SERIALUI_ConfigDialogProc
334 * Shows a dialog for configuring a COMM port
336 BOOL WINAPI
SERIALUI_ConfigDialogProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
339 SERIALUI_DialogInfo
*info
;
344 info
= (SERIALUI_DialogInfo
*) lParam
;
347 SetWindowLongA(hWnd
, DWL_USER
, lParam
);
348 snprintf(szTitle
, sizeof szTitle
, "Settings for %s", info
->lpszDevice
);
349 SetWindowTextA(hWnd
, szTitle
);
350 SERIALUI_DCBToDialogInfo(hWnd
, info
);
355 WORD wID
= LOWORD(wParam
);
357 info
= (SERIALUI_DialogInfo
*) GetWindowLongA(hWnd
, DWL_USER
);
363 SERIALUI_DialogInfoToDCB(hWnd
,info
);
369 /* test code for Get/SetDefaultCommConfig begins */
372 DWORD r
,dwConfSize
= sizeof (COMMCONFIG
);
373 r
= GetDefaultCommConfigA(info
->lpszDevice
,
374 info
->lpCommConfig
, &dwConfSize
);
376 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
378 SERIALUI_DCBToDialogInfo(hWnd
, info
);
383 SERIALUI_DialogInfoToDCB(hWnd
,info
);
384 r
= SetDefaultCommConfigA(info
->lpszDevice
,
385 info
->lpCommConfig
, sizeof (COMMCONFIG
));
387 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
390 /* test code for Get/SetDefaultCommConfig ends */
398 /***********************************************************************
399 * SERIALUI_CommConfigDialog (SERIALUI.3)
401 * Used by Win9x KERNEL to show a dialog for configuring a COMM port.
403 BOOL WINAPI
SERIALUI_CommConfigDialog(
406 LPCOMMCONFIG lpCommConfig
408 SERIALUI_DialogInfo info
;
410 info
.lpCommConfig
= lpCommConfig
;
411 info
.lpszDevice
= lpszName
;
412 info
.bConvert
= FALSE
;
413 info
.dwFlowControl
= 0;
418 return DialogBoxParamA(SERIALUI_hModule
,
419 MAKEINTRESOURCEA(IDD_SERIALUICONFIG
),
421 (DLGPROC
) SERIALUI_ConfigDialogProc
,
425 static LPCSTR lpszCommKey
= "System\\CurrentControlSet\\Services\\Class\\Ports";
426 static LPCSTR lpszDCB
= "DCB";
428 /***********************************************************************
429 * SERIALUI_SetDefaultCommConfig (SERIALUI.4)
431 * Used by Win98 KERNEL to set the default config for a COMM port
432 * FIXME: uses the wrong registry key... should use a digit, not
433 * the comm port name.
435 BOOL WINAPI
SERIALUI_SetDefaultCommConfig(
437 LPCOMMCONFIG lpCommConfig
,
440 HKEY hKeyReg
=0, hKeyPort
=0;
444 TRACE("%p %p %lx\n",lpszDevice
,lpCommConfig
,dwSize
);
449 if(dwSize
< sizeof (COMMCONFIG
))
452 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
453 if(r
!= ERROR_SUCCESS
)
456 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
457 r
= RegCreateKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
458 if(r
== ERROR_SUCCESS
)
460 dwDCBSize
= sizeof (DCB
);
461 r
= RegSetValueExA( hKeyPort
, lpszDCB
, NULL
, REG_BINARY
,
462 (LPSTR
)&lpCommConfig
->dcb
,dwDCBSize
);
463 TRACE("write key r=%ld\n",r
);
464 RegCloseKey(hKeyPort
);
467 RegCloseKey(hKeyReg
);
469 return (r
==ERROR_SUCCESS
);
472 /***********************************************************************
473 * SERIALUI_GetDefaultCommConfig (SERIALUI.5)
475 * Used by Win9x KERNEL to get the default config for a COMM port
476 * FIXME: uses the wrong registry key... should use a digit, not
477 * the comm port name.
479 BOOL WINAPI
SERIALUI_GetDefaultCommConfig(
481 LPCOMMCONFIG lpCommConfig
,
484 HKEY hKeyReg
, hKeyPort
;
486 DWORD r
,dwSize
,dwType
;
488 TRACE("%p %p %p\n",lpszDevice
,lpCommConfig
,lpdwSize
);
496 if(*lpdwSize
< sizeof (COMMCONFIG
))
499 *lpdwSize
= sizeof (COMMCONFIG
);
500 memset(lpCommConfig
, 0 , sizeof (COMMCONFIG
));
501 lpCommConfig
->dwSize
= sizeof (COMMCONFIG
);
502 lpCommConfig
->wVersion
= 1;
504 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
505 if(r
!= ERROR_SUCCESS
)
508 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
509 r
= RegOpenKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
510 if(r
== ERROR_SUCCESS
)
512 dwSize
= sizeof (DCB
);
514 r
= RegQueryValueExA( hKeyPort
, lpszDCB
, NULL
,
515 &dwType
, (LPSTR
)&lpCommConfig
->dcb
,&dwSize
);
516 if ((r
==ERROR_SUCCESS
) && (dwType
!= REG_BINARY
))
518 if ((r
==ERROR_SUCCESS
) && (dwSize
!= sizeof(DCB
)))
521 RegCloseKey(hKeyPort
);
525 /* FIXME: default to a hardcoded commconfig */
527 lpCommConfig
->dcb
.DCBlength
= sizeof(DCB
);
528 lpCommConfig
->dcb
.BaudRate
= 9600;
529 lpCommConfig
->dcb
.fBinary
= TRUE
;
530 lpCommConfig
->dcb
.fParity
= FALSE
;
531 lpCommConfig
->dcb
.ByteSize
= 8;
532 lpCommConfig
->dcb
.Parity
= NOPARITY
;
533 lpCommConfig
->dcb
.StopBits
= ONESTOPBIT
;
537 RegCloseKey(hKeyReg
);
539 return (r
==ERROR_SUCCESS
);