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 * DllMain [Internal] Initializes the internal 'SERIALUI.DLL'.
53 * hinstDLL [I] handle to the DLL's instance
55 * lpvReserved [I] reserved, must be NULL
62 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
64 TRACE("%p,%lx,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
67 case DLL_PROCESS_ATTACH
:
68 SERIALUI_hModule
= hinstDLL
;
70 case DLL_PROCESS_DETACH
:
78 /***********************************************************************
79 * EnumPropPages (SERIALUI.2)
81 * Called by the device manager to add prop sheets in Control Panel ???
82 * Pointed to in Win98 registry by
83 * \System\CurrentControlSet\Services\Class\ports\0000\EnumPropPages =
84 * "serialui.dll,EnumPropPages"
86 typedef LPVOID LPDEVICE_INFO
;
87 typedef LPVOID LPFNADDPROPSHEETPAGE
;
88 BOOL WINAPI
SERIALUI_EnumPropPages(LPDEVICE_INFO pdi
, LPFNADDPROPSHEETPAGE pfnAdd
, LPARAM lParam
)
90 FIXME("(%p %p %lx)\n",pdi
,pfnAdd
,lParam
);
95 * These data structures are convert from values used in fields of a DCB
96 * to strings used in the CommConfigDialog.
98 typedef struct tagPARAM2STRDATA
102 } PARAM2STRDATA
, *LPPARAM2STRDATA
;
104 typedef struct tagPARAM2STR
107 LPPARAM2STRDATA data
;
108 } PARAM2STR
, *LPPARAM2STR
;
109 typedef const LPPARAM2STR LPCPARAM2STR
;
111 #define SERIALUI_TABLESIZE(x) ((sizeof (x))/(sizeof (x[0])))
113 static PARAM2STRDATA SERIALUI_Baud2StrData
[]={
114 {110, "110"}, {300, "300"}, {600, "600"}, {1200, "1200"},
115 {2400, "2400"}, {4800, "4800"}, {9600, "9600"}, {14400, "14400"},
116 {19200, "19200"}, {38400L, "38400"}, {56000L, "56000"}, {57600L, "57600"},
117 {115200L, "115200"}, {128000L, "128000"}, {256000L, "256000"}
119 static PARAM2STR SERIALUI_Baud2Str
={ SERIALUI_TABLESIZE(SERIALUI_Baud2StrData
),SERIALUI_Baud2StrData
};
121 static PARAM2STRDATA SERIALUI_Parity2StrData
[]={
122 {NOPARITY
,"None"}, {ODDPARITY
,"Odd"}, {EVENPARITY
,"Even"}, {MARKPARITY
,"Mark"},
123 {SPACEPARITY
,"Space"}
125 static PARAM2STR SERIALUI_Parity2Str
={ SERIALUI_TABLESIZE(SERIALUI_Parity2StrData
),SERIALUI_Parity2StrData
};
127 static PARAM2STRDATA SERIALUI_Stop2StrData
[]={
128 {ONESTOPBIT
,"1"}, {ONE5STOPBITS
,"1.5"}, {TWOSTOPBITS
,"2"}
130 static PARAM2STR SERIALUI_Stop2Str
={ SERIALUI_TABLESIZE(SERIALUI_Stop2StrData
),SERIALUI_Stop2StrData
};
132 static PARAM2STRDATA SERIALUI_Data2StrData
[]={
133 {5,"5"}, {6,"6"}, {7,"7"}, {8, "8"}, {16,"16"}
135 static PARAM2STR SERIALUI_Data2Str
={ SERIALUI_TABLESIZE(SERIALUI_Data2StrData
),SERIALUI_Data2StrData
};
137 static PARAM2STRDATA SERIALUI_Flow2StrData
[]={
138 {0,"None"}, {1,"Hardware (RTS/CTS)"}, {2,"Software (XON/XOFF)"}
140 static PARAM2STR SERIALUI_Flow2Str
={ SERIALUI_TABLESIZE(SERIALUI_Flow2StrData
),SERIALUI_Flow2StrData
};
143 * Add all the fields to a combo box and highlight the current value
145 static void SERIALUI_AddConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, DWORD dwVal
)
148 HWND hControl
= GetDlgItem(hDlg
,id
);
153 for(i
=0; i
<table
->dwSize
; i
++)
155 n
= SendMessageA(hControl
, CB_ADDSTRING
, 0L, (LPARAM
)table
->data
[i
].name
);
156 if(dwVal
== table
->data
[i
].val
)
158 SendMessageA(hControl
, CB_SETCURSEL
, (WPARAM
)n
, (LPARAM
)0);
164 * Get the current sellection of the given combo box and set a DCB field to
165 * the value matching that selection.
167 static BOOL
SERIALUI_GetConfItems(HWND hDlg
, DWORD id
, LPCPARAM2STR table
, LPDWORD lpdwVal
)
171 HWND hControl
= GetDlgItem(hDlg
,id
);
173 if( (!hControl
) || (!lpdwVal
))
175 TRACE("Couldn't get window handle for item %lx\n",id
);
179 if(!GetWindowTextA(hControl
, &lpEntry
[0], sizeof lpEntry
))
181 TRACE("Couldn't get window text for item %lx\n",id
);
184 /* TRACE("%ld contains %s\n",id, lpEntry); */
186 for(i
=0; i
<table
->dwSize
; i
++)
188 if(!lstrcmpA(table
->data
[i
].name
,lpEntry
))
190 *lpdwVal
= table
->data
[i
].val
;
199 * Both the enumerated values CBR_XXXX and integer baud rates are valid
200 * dcb.BaudRate. This code is to convert back and forth between CBR_ style
201 * and integers. The dialog box uses integer values.
203 static DWORD SERIALUI_BaudConvertTable
[] = {
204 CBR_110
, 110, CBR_300
, 300, CBR_600
, 600, CBR_1200
, 1200,
205 CBR_2400
, 2400, CBR_4800
, 4800, CBR_9600
, 9600, CBR_14400
, 14400,
206 CBR_19200
, 19200, CBR_38400
, 38400, CBR_56000
, 56000, CBR_57600
, 57600,
207 CBR_115200
, 115200, CBR_128000
, 128000, CBR_256000
, 256000
210 static BOOL
SERIALUI_MakeBaudDword(LPDWORD lpdwBaudRate
)
214 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
216 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
])
218 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
+1];
225 static BOOL
SERIALUI_MakeBaudEnum(LPDWORD lpdwBaudRate
)
229 for(i
=0; i
<(sizeof(SERIALUI_BaudConvertTable
)/sizeof(DWORD
)); i
+=2)
231 if(*lpdwBaudRate
== SERIALUI_BaudConvertTable
[i
+1])
233 *lpdwBaudRate
= SERIALUI_BaudConvertTable
[i
];
240 typedef struct tagSERIALUI_DialogInfo
243 LPCOMMCONFIG lpCommConfig
;
244 BOOL bConvert
; /* baud rate was converted to a DWORD */
245 DWORD dwFlowControl
; /* old flow control */
246 } SERIALUI_DialogInfo
;
248 static void SERIALUI_DCBToDialogInfo(HWND hDlg
, SERIALUI_DialogInfo
*info
)
250 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
251 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
253 /* pass integer pointers to SERIALUI_ dialog config fns */
254 dwBaudRate
= lpdcb
->BaudRate
;
255 dwStopBits
= lpdcb
->StopBits
;
256 dwParity
= lpdcb
->Parity
;
257 dwByteSize
= lpdcb
->ByteSize
;
259 /* map flow control state, if it looks normal */
260 if((lpdcb
->fRtsControl
== RTS_CONTROL_HANDSHAKE
) ||
261 (lpdcb
->fOutxCtsFlow
== TRUE
)) {
263 } else if(lpdcb
->fOutX
|| lpdcb
->fInX
) {
269 info
->bConvert
= SERIALUI_MakeBaudDword(&dwBaudRate
);
271 SERIALUI_AddConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
,dwBaudRate
);
272 SERIALUI_AddConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
,dwStopBits
);
273 SERIALUI_AddConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
,dwParity
);
274 SERIALUI_AddConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
,dwByteSize
);
275 SERIALUI_AddConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, dwFlowControl
);
277 info
->dwFlowControl
= dwFlowControl
;
280 static void SERIALUI_DialogInfoToDCB(HWND hDlg
, SERIALUI_DialogInfo
*info
)
282 DWORD dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
;
283 LPDCB lpdcb
= &info
->lpCommConfig
->dcb
;
285 SERIALUI_GetConfItems( hDlg
, IDC_BAUD
, &SERIALUI_Baud2Str
, &dwBaudRate
);
286 SERIALUI_GetConfItems( hDlg
, IDC_STOP
, &SERIALUI_Stop2Str
, &dwStopBits
);
287 SERIALUI_GetConfItems( hDlg
, IDC_PARITY
, &SERIALUI_Parity2Str
, &dwParity
);
288 SERIALUI_GetConfItems( hDlg
, IDC_DATA
, &SERIALUI_Data2Str
, &dwByteSize
);
289 SERIALUI_GetConfItems( hDlg
, IDC_FLOW
, &SERIALUI_Flow2Str
, &dwFlowControl
);
291 TRACE("baud=%ld stop=%ld parity=%ld data=%ld flow=%ld\n",
292 dwBaudRate
, dwStopBits
, dwParity
, dwByteSize
, dwFlowControl
);
294 lpdcb
->BaudRate
= dwBaudRate
;
295 lpdcb
->StopBits
= dwStopBits
;
296 lpdcb
->Parity
= dwParity
;
297 lpdcb
->ByteSize
= dwByteSize
;
299 /* try not to change flow control if the user didn't change it */
300 if(info
->dwFlowControl
!= dwFlowControl
)
302 switch(dwFlowControl
)
305 lpdcb
->fOutxCtsFlow
= FALSE
;
306 lpdcb
->fOutxDsrFlow
= FALSE
;
307 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
308 lpdcb
->fOutX
= FALSE
;
310 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
312 case 1: /* CTS/RTS */
313 lpdcb
->fOutxCtsFlow
= TRUE
;
314 lpdcb
->fOutxDsrFlow
= FALSE
;
315 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
316 lpdcb
->fOutX
= FALSE
;
318 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
321 lpdcb
->fOutxCtsFlow
= FALSE
;
322 lpdcb
->fOutxDsrFlow
= FALSE
;
323 lpdcb
->fDtrControl
= DTR_CONTROL_DISABLE
;
326 lpdcb
->fRtsControl
= RTS_CONTROL_DISABLE
;
332 SERIALUI_MakeBaudEnum(&lpdcb
->BaudRate
);
335 /***********************************************************************
336 * SERIALUI_ConfigDialogProc
338 * Shows a dialog for configuring a COMM port
340 INT_PTR CALLBACK
SERIALUI_ConfigDialogProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
343 SERIALUI_DialogInfo
*info
;
348 info
= (SERIALUI_DialogInfo
*) lParam
;
351 SetWindowLongA(hWnd
, DWL_USER
, lParam
);
352 snprintf(szTitle
, sizeof szTitle
, "Settings for %s", info
->lpszDevice
);
353 SetWindowTextA(hWnd
, szTitle
);
354 SERIALUI_DCBToDialogInfo(hWnd
, info
);
359 WORD wID
= LOWORD(wParam
);
361 info
= (SERIALUI_DialogInfo
*) GetWindowLongA(hWnd
, DWL_USER
);
367 SERIALUI_DialogInfoToDCB(hWnd
,info
);
373 /* test code for Get/SetDefaultCommConfig begins */
376 DWORD r
,dwConfSize
= sizeof (COMMCONFIG
);
377 r
= GetDefaultCommConfigA(info
->lpszDevice
,
378 info
->lpCommConfig
, &dwConfSize
);
380 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
382 SERIALUI_DCBToDialogInfo(hWnd
, info
);
387 SERIALUI_DialogInfoToDCB(hWnd
,info
);
388 r
= SetDefaultCommConfigA(info
->lpszDevice
,
389 info
->lpCommConfig
, sizeof (COMMCONFIG
));
391 MessageBoxA(hWnd
,"Failed","GetDefaultCommConfig",MB_OK
);
394 /* test code for Get/SetDefaultCommConfig ends */
402 /***********************************************************************
403 * drvCommConfigDialog (SERIALUI.3)
405 * Used by Win9x KERNEL to show a dialog for configuring a COMM port.
407 BOOL WINAPI
SERIALUI_CommConfigDialog(
410 LPCOMMCONFIG lpCommConfig
412 SERIALUI_DialogInfo info
;
414 info
.lpCommConfig
= lpCommConfig
;
415 info
.lpszDevice
= lpszName
;
416 info
.bConvert
= FALSE
;
417 info
.dwFlowControl
= 0;
422 return DialogBoxParamA(SERIALUI_hModule
,
423 MAKEINTRESOURCEA(IDD_SERIALUICONFIG
),
425 SERIALUI_ConfigDialogProc
,
429 static LPCSTR lpszCommKey
= "System\\CurrentControlSet\\Services\\Class\\Ports";
430 static LPCSTR lpszDCB
= "DCB";
432 /***********************************************************************
433 * drvSetDefaultCommConfig (SERIALUI.4)
435 * Used by Win98 KERNEL to set the default config for a COMM port
436 * FIXME: uses the wrong registry key... should use a digit, not
437 * the comm port name.
439 BOOL WINAPI
SERIALUI_SetDefaultCommConfig(
441 LPCOMMCONFIG lpCommConfig
,
444 HKEY hKeyReg
=0, hKeyPort
=0;
448 TRACE("%p %p %lx\n",lpszDevice
,lpCommConfig
,dwSize
);
453 if(dwSize
< sizeof (COMMCONFIG
))
456 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
457 if(r
!= ERROR_SUCCESS
)
460 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
461 r
= RegCreateKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
462 if(r
== ERROR_SUCCESS
)
464 dwDCBSize
= sizeof (DCB
);
465 r
= RegSetValueExA( hKeyPort
, lpszDCB
, 0, REG_BINARY
,
466 (LPSTR
)&lpCommConfig
->dcb
,dwDCBSize
);
467 TRACE("write key r=%ld\n",r
);
468 RegCloseKey(hKeyPort
);
471 RegCloseKey(hKeyReg
);
473 return (r
==ERROR_SUCCESS
);
476 /***********************************************************************
477 * drvGetDefaultCommConfig (SERIALUI.5)
479 * Used by Win9x KERNEL to get the default config for a COMM port
480 * FIXME: uses the wrong registry key... should use a digit, not
481 * the comm port name.
483 BOOL WINAPI
SERIALUI_GetDefaultCommConfig(
485 LPCOMMCONFIG lpCommConfig
,
488 HKEY hKeyReg
, hKeyPort
;
490 DWORD r
,dwSize
,dwType
;
492 TRACE("%p %p %p\n",lpszDevice
,lpCommConfig
,lpdwSize
);
500 if(*lpdwSize
< sizeof (COMMCONFIG
))
503 *lpdwSize
= sizeof (COMMCONFIG
);
504 memset(lpCommConfig
, 0 , sizeof (COMMCONFIG
));
505 lpCommConfig
->dwSize
= sizeof (COMMCONFIG
);
506 lpCommConfig
->wVersion
= 1;
508 r
= RegConnectRegistryA(NULL
, HKEY_LOCAL_MACHINE
, &hKeyReg
);
509 if(r
!= ERROR_SUCCESS
)
512 snprintf(szKeyName
, sizeof szKeyName
, "%s\\%s", lpszCommKey
,lpszDevice
);
513 r
= RegOpenKeyA(hKeyReg
, szKeyName
, &hKeyPort
);
514 if(r
== ERROR_SUCCESS
)
516 dwSize
= sizeof (DCB
);
518 r
= RegQueryValueExA( hKeyPort
, lpszDCB
, NULL
,
519 &dwType
, (LPSTR
)&lpCommConfig
->dcb
,&dwSize
);
520 if ((r
==ERROR_SUCCESS
) && (dwType
!= REG_BINARY
))
522 if ((r
==ERROR_SUCCESS
) && (dwSize
!= sizeof(DCB
)))
525 RegCloseKey(hKeyPort
);
529 /* FIXME: default to a hardcoded commconfig */
531 lpCommConfig
->dcb
.DCBlength
= sizeof(DCB
);
532 lpCommConfig
->dcb
.BaudRate
= 9600;
533 lpCommConfig
->dcb
.fBinary
= TRUE
;
534 lpCommConfig
->dcb
.fParity
= FALSE
;
535 lpCommConfig
->dcb
.ByteSize
= 8;
536 lpCommConfig
->dcb
.Parity
= NOPARITY
;
537 lpCommConfig
->dcb
.StopBits
= ONESTOPBIT
;
541 RegCloseKey(hKeyReg
);
543 return (r
==ERROR_SUCCESS
);