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"
43 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
49 HMODULE SERIALUI_hModule
= 0;
51 /***********************************************************************
52 * DllMain [Internal] Initializes the internal 'SERIALUI.DLL'.
55 * hinstDLL [I] handle to the DLL's instance
57 * lpvReserved [I] reserved, must be NULL
64 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
66 TRACE("%p,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
69 case DLL_PROCESS_ATTACH
:
70 DisableThreadLibraryCalls(hinstDLL
);
71 SERIALUI_hModule
= hinstDLL
;
73 case DLL_PROCESS_DETACH
:
81 /***********************************************************************
82 * EnumPropPages (SERIALUI.2)
84 * Called by the device manager to add prop sheets in Control Panel ???
85 * Pointed to in Win98 registry by
86 * \System\CurrentControlSet\Services\Class\ports\0000\EnumPropPages =
87 * "serialui.dll,EnumPropPages"
89 typedef LPVOID LPDEVICE_INFO
;
90 typedef LPVOID LPFNADDPROPSHEETPAGE
;
91 BOOL WINAPI
SERIALUI_EnumPropPages(LPDEVICE_INFO pdi
, LPFNADDPROPSHEETPAGE pfnAdd
, LPARAM lParam
)
93 FIXME("(%p %p %lx)\n",pdi
,pfnAdd
,lParam
);
98 * These data structures are convert from values used in fields of a DCB
99 * to strings used in the CommConfigDialog.
101 typedef struct tagPARAM2STRDATA
105 } PARAM2STRDATA
, *LPPARAM2STRDATA
;
107 typedef struct tagPARAM2STR
110 LPPARAM2STRDATA data
;
111 } PARAM2STR
, *LPPARAM2STR
;
112 typedef const LPPARAM2STR LPCPARAM2STR
;
114 #define SERIALUI_TABLESIZE(x) ((sizeof (x))/(sizeof (x[0])))
116 static PARAM2STRDATA SERIALUI_Baud2StrData
[]={
117 {110, "110"}, {300, "300"}, {600, "600"}, {1200, "1200"},
118 {2400, "2400"}, {4800, "4800"}, {9600, "9600"}, {14400, "14400"},
119 {19200, "19200"}, {38400L, "38400"}, {56000L, "56000"}, {57600L, "57600"},
120 {115200L, "115200"}, {128000L, "128000"}, {256000L, "256000"}
122 static PARAM2STR SERIALUI_Baud2Str
={ SERIALUI_TABLESIZE(SERIALUI_Baud2StrData
),SERIALUI_Baud2StrData
};
124 static PARAM2STRDATA SERIALUI_Parity2StrData
[]={
125 {NOPARITY
,"None"}, {ODDPARITY
,"Odd"}, {EVENPARITY
,"Even"}, {MARKPARITY
,"Mark"},
126 {SPACEPARITY
,"Space"}
128 static PARAM2STR SERIALUI_Parity2Str
={ SERIALUI_TABLESIZE(SERIALUI_Parity2StrData
),SERIALUI_Parity2StrData
};
130 static PARAM2STRDATA SERIALUI_Stop2StrData
[]={
131 {ONESTOPBIT
,"1"}, {ONE5STOPBITS
,"1.5"}, {TWOSTOPBITS
,"2"}
133 static PARAM2STR SERIALUI_Stop2Str
={ SERIALUI_TABLESIZE(SERIALUI_Stop2StrData
),SERIALUI_Stop2StrData
};
135 static PARAM2STRDATA SERIALUI_Data2StrData
[]={
136 {5,"5"}, {6,"6"}, {7,"7"}, {8, "8"}, {16,"16"}
138 static PARAM2STR SERIALUI_Data2Str
={ SERIALUI_TABLESIZE(SERIALUI_Data2StrData
),SERIALUI_Data2StrData
};
140 static PARAM2STRDATA SERIALUI_Flow2StrData
[]={
141 {0,"None"}, {1,"Hardware (RTS/CTS)"}, {2,"Software (XON/XOFF)"}
143 static PARAM2STR SERIALUI_Flow2Str
={ SERIALUI_TABLESIZE(SERIALUI_Flow2StrData
),SERIALUI_Flow2StrData
};
146 * Add all the fields to a combo box and highlight the current value
148 static void SERIALUI_AddConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, DWORD dwVal
)
151 HWND hControl
= GetDlgItem(hDlg
,id
);
156 for(i
=0; i
<table
->dwSize
; i
++)
158 n
= SendMessageA(hControl
, CB_ADDSTRING
, 0L, (LPARAM
)table
->data
[i
].name
);
159 if(dwVal
== table
->data
[i
].val
)
161 SendMessageA(hControl
, CB_SETCURSEL
, (WPARAM
)n
, (LPARAM
)0);
167 * Get the current sellection of the given combo box and set a DCB field to
168 * the value matching that selection.
170 static BOOL
SERIALUI_GetConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, LPDWORD lpdwVal
)
174 HWND hControl
= GetDlgItem(hDlg
,id
);
176 if( (!hControl
) || (!lpdwVal
))
178 TRACE("Couldn't get window handle for item %lx\n",id
);
182 if(!GetWindowTextA(hControl
, &lpEntry
[0], sizeof(lpEntry
)))
184 TRACE("Couldn't get window text for item %lx\n",id
);
187 /* TRACE("%ld contains %s\n",id, lpEntry); */
189 for(i
=0; i
<table
->dwSize
; i
++)
191 if(!lstrcmpA(table
->data
[i
].name
,lpEntry
))
193 *lpdwVal
= table
->data
[i
].val
;
202 * Both the enumerated values CBR_XXXX and integer baud rates are valid
203 * dcb.BaudRate. This code is to convert back and forth between CBR_ style
204 * and integers. The dialog box uses integer values.
206 static DWORD SERIALUI_BaudConvertTable
[] = {
207 CBR_110
, 110, CBR_300
, 300, CBR_600
, 600, CBR_1200
, 1200,
208 CBR_2400
, 2400, CBR_4800
, 4800, CBR_9600
, 9600, CBR_14400
, 14400,
209 CBR_19200
, 19200, CBR_38400
, 38400, CBR_56000
, 56000, CBR_57600
, 57600,
210 CBR_115200
, 115200, CBR_128000
, 128000, CBR_256000
, 256000
213 static BOOL
SERIALUI_MakeBaudDword(LPDWORD lpdwBaudRate
)
217 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
219 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
])
221 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
+1];
228 static BOOL
SERIALUI_MakeBaudEnum(LPDWORD lpdwBaudRate
)
232 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
234 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
+1])
236 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
];
243 typedef struct tagSERIALUI_DialogInfo
246 LPCOMMCONFIG lpCommConfig
;
247 BOOL bConvert
; /* baud rate was converted to a DWORD */
248 DWORD dwFlowControl
; /* old flow control */
249 } SERIALUI_DialogInfo
;
251 static void SERIALUI_DCBToDialogInfo(HWND hDlg
, SERIALUI_DialogInfo
*info
)
253 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
254 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
256 /* pass integer pointers to SERIALUI_ dialog config fns */
257 dwBaudRate
= lpdcb
->BaudRate
;
258 dwStopBits
= lpdcb
->StopBits
;
259 dwParity
= lpdcb
->Parity
;
260 dwByteSize
= lpdcb
->ByteSize
;
262 /* map flow control state, if it looks normal */
263 if((lpdcb
->fRtsControl
== RTS_CONTROL_HANDSHAKE
) ||
264 (lpdcb
->fOutxCtsFlow
== TRUE
)) {
266 } else if(lpdcb
->fOutX
|| lpdcb
->fInX
) {
272 info
->bConvert
= SERIALUI_MakeBaudDword(&dwBaudRate
);
274 SERIALUI_AddConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
,dwBaudRate
);
275 SERIALUI_AddConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
,dwStopBits
);
276 SERIALUI_AddConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
,dwParity
);
277 SERIALUI_AddConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
,dwByteSize
);
278 SERIALUI_AddConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, dwFlowControl
);
280 info
->dwFlowControl
= dwFlowControl
;
283 static void SERIALUI_DialogInfoToDCB(HWND hDlg
, SERIALUI_DialogInfo
*info
)
285 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
286 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
288 SERIALUI_GetConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
, &dwBaudRate
);
289 SERIALUI_GetConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
, &dwStopBits
);
290 SERIALUI_GetConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
, &dwParity
);
291 SERIALUI_GetConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
, &dwByteSize
);
292 SERIALUI_GetConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, &dwFlowControl
);
294 TRACE("baud=%ld stop=%ld parity=%ld data=%ld flow=%ld\n",
295 dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
);
297 lpdcb
->BaudRate
= dwBaudRate
;
298 lpdcb
->StopBits
= dwStopBits
;
299 lpdcb
->Parity
= dwParity
;
300 lpdcb
->ByteSize
= dwByteSize
;
302 /* try not to change flow control if the user didn't change it */
303 if(info
->dwFlowControl
!= dwFlowControl
)
305 switch(dwFlowControl
)
308 lpdcb
->fOutxCtsFlow
= FALSE
;
309 lpdcb
->fOutxDsrFlow
= FALSE
;
310 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
311 lpdcb
->fOutX
= FALSE
;
313 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
315 case 1: /* CTS/RTS */
316 lpdcb
->fOutxCtsFlow
= TRUE
;
317 lpdcb
->fOutxDsrFlow
= FALSE
;
318 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
319 lpdcb
->fOutX
= FALSE
;
321 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
324 lpdcb
->fOutxCtsFlow
= FALSE
;
325 lpdcb
->fOutxDsrFlow
= FALSE
;
326 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
329 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
335 SERIALUI_MakeBaudEnum(&lpdcb
->BaudRate
);
338 /***********************************************************************
339 * SERIALUI_ConfigDialogProc
341 * Shows a dialog for configuring a COMM port
343 INT_PTR CALLBACK
SERIALUI_ConfigDialogProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
346 SERIALUI_DialogInfo
*info
;
351 info
= (SERIALUI_DialogInfo
*) lParam
;
354 SetWindowLongA(hWnd
, DWL_USER
, lParam
);
355 snprintf(szTitle
, sizeof(szTitle
), "Settings for %s", info
->lpszDevice
);
356 SetWindowTextA(hWnd
, szTitle
);
357 SERIALUI_DCBToDialogInfo(hWnd
, info
);
362 WORD wID
= LOWORD(wParam
);
364 info
= (SERIALUI_DialogInfo
*) GetWindowLongA(hWnd
, DWL_USER
);
370 SERIALUI_DialogInfoToDCB(hWnd
,info
);
376 /* test code for Get/SetDefaultCommConfig begins */
379 DWORD r
,dwConfSize
= sizeof (COMMCONFIG
);
380 r
= GetDefaultCommConfigA(info
->lpszDevice
,
381 info
->lpCommConfig
, &dwConfSize
);
383 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
385 SERIALUI_DCBToDialogInfo(hWnd
, info
);
390 SERIALUI_DialogInfoToDCB(hWnd
,info
);
391 r
= SetDefaultCommConfigA(info
->lpszDevice
,
392 info
->lpCommConfig
, sizeof (COMMCONFIG
));
394 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
397 /* test code for Get/SetDefaultCommConfig ends */
405 /***********************************************************************
406 * drvCommConfigDialog (SERIALUI.3)
408 * Used by Win9x KERNEL to show a dialog for configuring a COMM port.
410 BOOL WINAPI
SERIALUI_CommConfigDialog(
413 LPCOMMCONFIG lpCommConfig
415 SERIALUI_DialogInfo info
;
417 info
.lpCommConfig
= lpCommConfig
;
418 info
.lpszDevice
= lpszName
;
419 info
.bConvert
= FALSE
;
420 info
.dwFlowControl
= 0;
425 return DialogBoxParamA(SERIALUI_hModule
,
426 MAKEINTRESOURCEA(IDD_SERIALUICONFIG
),
428 SERIALUI_ConfigDialogProc
,
432 static LPCSTR lpszCommKey
= "System\\CurrentControlSet\\Services\\Class\\Ports";
433 static LPCSTR lpszDCB
= "DCB";
435 /***********************************************************************
436 * drvSetDefaultCommConfig (SERIALUI.4)
438 * Used by Win98 KERNEL to set the default config for a COMM port
439 * FIXME: uses the wrong registry key... should use a digit, not
440 * the comm port name.
442 BOOL WINAPI
SERIALUI_SetDefaultCommConfig(
444 LPCOMMCONFIG lpCommConfig
,
447 HKEY hKeyReg
=0, hKeyPort
=0;
451 TRACE("%p %p %lx\n",lpszDevice
,lpCommConfig
,dwSize
);
456 if(dwSize
< sizeof (COMMCONFIG
))
459 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
460 if(r
!= ERROR_SUCCESS
)
463 snprintf(szKeyName
, sizeof(szKeyName
), "%s\\%s", lpszCommKey
,lpszDevice
);
464 r
= RegCreateKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
465 if(r
== ERROR_SUCCESS
)
467 dwDCBSize
= sizeof (DCB
);
468 r
= RegSetValueExA( hKeyPort
, lpszDCB
, 0, REG_BINARY
,
469 (LPSTR
)&lpCommConfig
->dcb
,dwDCBSize
);
470 TRACE("write key r=%ld\n",r
);
471 RegCloseKey(hKeyPort
);
474 RegCloseKey(hKeyReg
);
476 return (r
==ERROR_SUCCESS
);
479 /***********************************************************************
480 * drvGetDefaultCommConfig (SERIALUI.5)
482 * Used by Win9x KERNEL to get the default config for a COMM port
483 * FIXME: uses the wrong registry key... should use a digit, not
484 * the comm port name.
486 BOOL WINAPI
SERIALUI_GetDefaultCommConfig(
488 LPCOMMCONFIG lpCommConfig
,
491 HKEY hKeyReg
, hKeyPort
;
493 DWORD r
,dwSize
,dwType
;
495 TRACE("%p %p %p\n",lpszDevice
,lpCommConfig
,lpdwSize
);
503 if(*lpdwSize
< sizeof (COMMCONFIG
))
506 *lpdwSize
= sizeof (COMMCONFIG
);
507 memset(lpCommConfig
, 0 , sizeof (COMMCONFIG
));
508 lpCommConfig
->dwSize
= sizeof (COMMCONFIG
);
509 lpCommConfig
->wVersion
= 1;
511 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
512 if(r
!= ERROR_SUCCESS
)
515 snprintf(szKeyName
, sizeof(szKeyName
), "%s\\%s", lpszCommKey
,lpszDevice
);
516 r
= RegOpenKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
517 if(r
== ERROR_SUCCESS
)
519 dwSize
= sizeof (DCB
);
521 r
= RegQueryValueExA( hKeyPort
, lpszDCB
, NULL
,
522 &dwType
, (LPSTR
)&lpCommConfig
->dcb
,&dwSize
);
523 if ((r
==ERROR_SUCCESS
) && (dwType
!= REG_BINARY
))
525 if ((r
==ERROR_SUCCESS
) && (dwSize
!= sizeof(DCB
)))
528 RegCloseKey(hKeyPort
);
532 /* FIXME: default to a hardcoded commconfig */
534 lpCommConfig
->dcb
.DCBlength
= sizeof(DCB
);
535 lpCommConfig
->dcb
.BaudRate
= 9600;
536 lpCommConfig
->dcb
.fBinary
= TRUE
;
537 lpCommConfig
->dcb
.fParity
= FALSE
;
538 lpCommConfig
->dcb
.ByteSize
= 8;
539 lpCommConfig
->dcb
.Parity
= NOPARITY
;
540 lpCommConfig
->dcb
.StopBits
= ONESTOPBIT
;
544 RegCloseKey(hKeyReg
);
546 return (r
==ERROR_SUCCESS
);