[msports] Notify the system of changes to the serial port settings.
[reactos.git] / dll / win32 / msports / serial.c
1 /*
2 * PROJECT: Ports installer library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll\win32\msports\serial.c
5 * PURPOSE: Serial Port property functions
6 * COPYRIGHT: Copyright 2011 Eric Kohl
7 */
8
9 #include "precomp.h"
10
11
12 typedef struct _PORT_DATA
13 {
14 HDEVINFO DeviceInfoSet;
15 PSP_DEVINFO_DATA DeviceInfoData;
16
17 WCHAR szPortName[16];
18 INT nBaudRateIndex;
19 INT nParityIndex;
20 INT nDataBitsIndex;
21 INT nStopBitsIndex;
22 INT nFlowControlIndex;
23
24 BOOL bChanged;
25 } PORT_DATA, *PPORT_DATA;
26
27 #define DEFAULT_BAUD_RATE_INDEX 11
28 #define DEFAULT_DATA_BITS_INDEX 4
29 #define DEFAULT_PARITY_INDEX 2
30 #define DEFAULT_STOP_BITS_INDEX 0
31 #define DEFAULT_FLOW_CONTROL_INDEX 2
32
33 DWORD BaudRates[] = {75, 110, 134, 150, 300, 600, 1200, 1800, 2400, 4800,
34 7200, 9600, 14400, 19200, 38400, 57600, 115200, 128000};
35 PWSTR Paritys[] = {L"e", L"o", L"n", L"m", L"s"};
36 PWSTR DataBits[] = {L"4", L"5", L"6", L"7", L"8"};
37 PWSTR StopBits[] = {L"1", L"1.5", L"2"};
38 PWSTR FlowControls[] = {L"x", L"p"};
39
40
41 static
42 VOID
43 FillComboBox(
44 HWND hwnd,
45 PWSTR szBuffer)
46 {
47 PWSTR pStart, pEnd;
48
49 pStart = szBuffer;
50 for (;;)
51 {
52 pEnd = wcschr(pStart, L',');
53 if (pEnd != NULL)
54 *pEnd = UNICODE_NULL;
55
56 ComboBox_AddString(hwnd, pStart);
57
58 if (pEnd == NULL)
59 break;
60
61 pStart = pEnd + 1;
62 }
63 }
64
65
66 static
67 VOID
68 ReadPortSettings(
69 PPORT_DATA pPortData)
70 {
71 WCHAR szPortData[32];
72 WCHAR szParity[4];
73 WCHAR szDataBits[4];
74 WCHAR szStopBits[4];
75 WCHAR szFlowControl[4];
76 DWORD dwType, dwSize;
77 DWORD dwBaudRate = 0;
78 HKEY hKey;
79 INT n, i;
80 LONG lError;
81
82 TRACE("ReadPortSettings(%p)\n", pPortData);
83
84 pPortData->nBaudRateIndex = DEFAULT_BAUD_RATE_INDEX; /* 9600 */
85 pPortData->nParityIndex = DEFAULT_PARITY_INDEX; /* None */
86 pPortData->nDataBitsIndex = DEFAULT_DATA_BITS_INDEX; /* 8 Data Bits */
87 pPortData->nStopBitsIndex = DEFAULT_STOP_BITS_INDEX; /* 1 Stop Bit */
88 pPortData->nFlowControlIndex = DEFAULT_FLOW_CONTROL_INDEX; /* None */
89 pPortData->bChanged = FALSE;
90
91 hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet,
92 pPortData->DeviceInfoData,
93 DICS_FLAG_GLOBAL,
94 0,
95 DIREG_DEV,
96 KEY_READ);
97 if (hKey == INVALID_HANDLE_VALUE)
98 {
99 ERR("SetupDiOpenDevRegKey() failed\n");
100 return;
101 }
102
103 dwSize = sizeof(pPortData->szPortName);
104 lError = RegQueryValueExW(hKey,
105 L"PortName",
106 NULL,
107 NULL,
108 (PBYTE)pPortData->szPortName,
109 &dwSize);
110 RegCloseKey(hKey);
111
112 if (lError != ERROR_SUCCESS)
113 {
114 ERR("RegQueryValueExW failed (Error %lu)\n", lError);
115 return;
116 }
117
118 wcscat(pPortData->szPortName, L":");
119 TRACE("PortName: '%S'\n", pPortData->szPortName);
120
121 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
122 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports",
123 0,
124 KEY_READ,
125 &hKey);
126 if (lError != ERROR_SUCCESS)
127 {
128 ERR("RegOpenKeyExW failed (Error %lu)\n", lError);
129 return;
130 }
131
132 dwSize = sizeof(szPortData);
133 lError = RegQueryValueExW(hKey,
134 pPortData->szPortName,
135 NULL,
136 &dwType,
137 (LPBYTE)szPortData,
138 &dwSize);
139 RegCloseKey(hKey);
140
141 if (lError != ERROR_SUCCESS)
142 {
143 ERR("RegQueryValueExW failed (Error %lu)\n", lError);
144 return;
145 }
146
147 if ((dwType != REG_SZ) || (dwSize > sizeof(szPortData)))
148 {
149 ERR("Wrong type or size\n");
150 return;
151 }
152
153 TRACE("szPortData: '%S'\n", szPortData);
154
155 /* Replace commas by spaces */
156 for (i = 0; i < wcslen(szPortData); i++)
157 {
158 if (szPortData[i] == L',')
159 szPortData[i] = L' ';
160 }
161
162 TRACE("szPortData: '%S'\n", szPortData);
163
164 /* Parse the port settings */
165 n = swscanf(szPortData,
166 L"%lu %3s %3s %3s %3s",
167 &dwBaudRate,
168 &szParity,
169 &szDataBits,
170 &szStopBits,
171 &szFlowControl);
172
173 TRACE("dwBaudRate: %lu\n", dwBaudRate);
174 TRACE("szParity: '%S'\n", szParity);
175 TRACE("szDataBits: '%S'\n", szDataBits);
176 TRACE("szStopBits: '%S'\n", szStopBits);
177 TRACE("szFlowControl: '%S'\n", szFlowControl);
178
179 if (n > 0)
180 {
181 for (i = 0; i < ARRAYSIZE(BaudRates); i++)
182 {
183 if (dwBaudRate == BaudRates[i])
184 pPortData->nBaudRateIndex = i;
185 }
186 }
187
188 if (n > 1)
189 {
190 for (i = 0; i < ARRAYSIZE(Paritys); i++)
191 {
192 if (_wcsicmp(szParity, Paritys[i]) == 0)
193 pPortData->nParityIndex = i;
194 }
195 }
196
197 if (n > 2)
198 {
199 for (i = 0; i < ARRAYSIZE(DataBits); i++)
200 {
201 if (_wcsicmp(szDataBits, DataBits[i]) == 0)
202 pPortData->nDataBitsIndex = i;
203 }
204 }
205
206 if (n > 3)
207 {
208 for (i = 0; i < ARRAYSIZE(StopBits); i++)
209 {
210 if (_wcsicmp(szStopBits, StopBits[i]) == 0)
211 pPortData->nStopBitsIndex = i;
212 }
213 }
214
215 if (n > 4)
216 {
217 for (i = 0; i < ARRAYSIZE(FlowControls); i++)
218 {
219 if (_wcsicmp(szFlowControl, FlowControls[i]) == 0)
220 pPortData->nFlowControlIndex = i;
221 }
222 }
223 }
224
225
226 static
227 VOID
228 WritePortSettings(
229 HWND hwnd,
230 PPORT_DATA pPortData)
231 {
232 WCHAR szPortData[32];
233 HWND hwndControl;
234 INT nBaudRateIndex;
235 INT nDataBitsIndex;
236 INT nParityIndex;
237 INT nStopBitsIndex;
238 INT nFlowControlIndex;
239 HKEY hKey;
240 LONG lError;
241
242 TRACE("WritePortSettings(%p)\n", pPortData);
243
244 if (pPortData->bChanged == FALSE)
245 {
246 TRACE("Nothing changed. Done!\n");
247 return;
248 }
249
250 nBaudRateIndex = pPortData->nBaudRateIndex;
251 nDataBitsIndex = pPortData->nDataBitsIndex;
252 nParityIndex = pPortData->nParityIndex;
253 nStopBitsIndex = pPortData->nStopBitsIndex;
254 nFlowControlIndex = pPortData->nFlowControlIndex;
255
256 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
257 if (hwndControl)
258 {
259 nBaudRateIndex = ComboBox_GetCurSel(hwndControl);
260 }
261
262 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
263 if (hwndControl)
264 {
265 nDataBitsIndex = ComboBox_GetCurSel(hwndControl);
266 }
267
268 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
269 if (hwndControl)
270 {
271 nParityIndex = ComboBox_GetCurSel(hwndControl);
272 }
273
274 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
275 if (hwndControl)
276 {
277 nStopBitsIndex = ComboBox_GetCurSel(hwndControl);
278 }
279
280 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
281 if (hwndControl)
282 {
283 nFlowControlIndex = ComboBox_GetCurSel(hwndControl);
284 }
285
286 swprintf(szPortData,
287 L"%lu,%s,%s,%s",
288 BaudRates[nBaudRateIndex],
289 Paritys[nParityIndex],
290 DataBits[nDataBitsIndex],
291 StopBits[nStopBitsIndex]);
292 if (nFlowControlIndex < 2)
293 {
294 wcscat(szPortData, L",");
295 wcscat(szPortData, FlowControls[nFlowControlIndex]);
296 }
297
298 TRACE("szPortData: '%S'\n", szPortData);
299
300 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
301 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports",
302 0,
303 KEY_WRITE,
304 &hKey);
305 if (lError != ERROR_SUCCESS)
306 {
307 ERR("RegOpenKeyExW failed (Error %lu)\n", lError);
308 return;
309 }
310
311 lError = RegSetValueExW(hKey,
312 pPortData->szPortName,
313 0,
314 REG_SZ,
315 (LPBYTE)szPortData,
316 (wcslen(szPortData) + 1) * sizeof(WCHAR));
317
318 RegCloseKey(hKey);
319
320 if (lError != ERROR_SUCCESS)
321 {
322 ERR("RegSetValueExW failed (Error %lu)\n", lError);
323 return;
324 }
325
326 /* Notify the system */
327 PostMessageW(HWND_BROADCAST,
328 WM_WININICHANGE,
329 0,
330 (LPARAM)pPortData->szPortName);
331
332 TRACE("Done!\n");
333 }
334
335
336 static
337 BOOL
338 OnInitDialog(
339 HWND hwnd,
340 WPARAM wParam,
341 LPARAM lParam)
342 {
343 PPORT_DATA pPortData;
344 WCHAR szBuffer[256];
345 UINT i;
346 HWND hwndControl;
347
348 TRACE("OnInitDialog()\n");
349
350 pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam;
351 if (pPortData == NULL)
352 {
353 ERR("pPortData is NULL\n");
354 return FALSE;
355 }
356
357 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData);
358
359 /* Read and parse the port settings */
360 ReadPortSettings(pPortData);
361
362 /* Fill the 'Bits per second' combobox */
363 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
364 if (hwndControl)
365 {
366 for (i = 0; i < ARRAYSIZE(BaudRates); i++)
367 {
368 _ultow(BaudRates[i], szBuffer, 10);
369 ComboBox_AddString(hwndControl, szBuffer);
370 }
371
372 ComboBox_SetCurSel(hwndControl, pPortData->nBaudRateIndex);
373 }
374
375 /* Fill the 'Data bits' combobox */
376 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
377 if (hwndControl)
378 {
379 for (i = 0; i < ARRAYSIZE(DataBits); i++)
380 {
381 ComboBox_AddString(hwndControl, DataBits[i]);
382 }
383
384 ComboBox_SetCurSel(hwndControl, pPortData->nDataBitsIndex);
385 }
386
387 /* Fill the 'Parity' combobox */
388 LoadStringW(hInstance, IDS_PARITY, szBuffer, ARRAYSIZE(szBuffer));
389
390 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
391 if (hwndControl)
392 {
393 FillComboBox(hwndControl, szBuffer);
394 ComboBox_SetCurSel(hwndControl, pPortData->nParityIndex);
395 }
396
397 /* Fill the 'Stop bits' combobox */
398 LoadStringW(hInstance, IDS_STOPBITS, szBuffer, ARRAYSIZE(szBuffer));
399
400 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
401 if (hwndControl)
402 {
403 FillComboBox(hwndControl, szBuffer);
404 ComboBox_SetCurSel(hwndControl, pPortData->nStopBitsIndex);
405 }
406
407 /* Fill the 'Flow control' combobox */
408 LoadStringW(hInstance, IDS_FLOWCONTROL, szBuffer, ARRAYSIZE(szBuffer));
409
410 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
411 if (hwndControl)
412 {
413 FillComboBox(hwndControl, szBuffer);
414 ComboBox_SetCurSel(hwndControl, pPortData->nFlowControlIndex);
415 }
416
417 /* Disable the 'Advanced' button */
418 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_ADVANCED);
419 if (hwndControl)
420 EnableWindow(hwndControl, FALSE);
421
422 return TRUE;
423 }
424
425
426 static
427 VOID
428 RestoreDefaultValues(
429 HWND hwnd,
430 PPORT_DATA pPortData)
431 {
432 HWND hwndControl;
433
434 /* Reset the 'Bits per second' combobox */
435 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
436 if (hwndControl)
437 {
438 ComboBox_SetCurSel(hwndControl, DEFAULT_BAUD_RATE_INDEX);
439 }
440
441 /* Reset the 'Data bits' combobox */
442 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
443 if (hwndControl)
444 {
445 ComboBox_SetCurSel(hwndControl, DEFAULT_DATA_BITS_INDEX);
446 }
447
448 /* Reset the 'Parity' combobox */
449 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
450 if (hwndControl)
451 {
452 ComboBox_SetCurSel(hwndControl, DEFAULT_PARITY_INDEX);
453 }
454
455 /* Reset the 'Stop bits' combobox */
456 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
457 if (hwndControl)
458 {
459 ComboBox_SetCurSel(hwndControl, DEFAULT_STOP_BITS_INDEX);
460 }
461
462 /* Reset the 'Flow control' combobox */
463 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
464 if (hwndControl)
465 {
466 ComboBox_SetCurSel(hwndControl, DEFAULT_FLOW_CONTROL_INDEX);
467 }
468
469 pPortData->bChanged = TRUE;
470 }
471
472
473 static
474 VOID
475 OnCommand(
476 HWND hwnd,
477 WPARAM wParam,
478 LPARAM lParam)
479 {
480 PPORT_DATA pPortData;
481
482 TRACE("OnCommand()\n");
483
484 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
485 if (pPortData == NULL)
486 {
487 ERR("pPortData is NULL\n");
488 return;
489 }
490
491 switch (LOWORD(wParam))
492 {
493 case IDC_SERIAL_BITSPERSECOND:
494 case IDC_SERIAL_DATABITS:
495 case IDC_SERIAL_PARITY:
496 case IDC_SERIAL_STOPBITS:
497 case IDC_SERIAL_FLOWCONTROL:
498 if (HIWORD(wParam) == CBN_SELCHANGE ||
499 HIWORD(wParam) == CBN_EDITCHANGE)
500 {
501 pPortData->bChanged = TRUE;
502 }
503 break;
504
505 // case IDC_SERIAL_ADVANCED:
506
507 case IDC_SERIAL_RESTORE:
508 RestoreDefaultValues(hwnd, pPortData);
509 break;
510
511 default:
512 break;
513 }
514 }
515
516
517 static
518 VOID
519 OnNotify(
520 HWND hwnd,
521 WPARAM wParam,
522 LPARAM lParam)
523 {
524 PPORT_DATA pPortData;
525
526 TRACE("OnCommand()\n");
527
528 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
529 if (pPortData == NULL)
530 {
531 ERR("pPortData is NULL\n");
532 return;
533 }
534
535 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
536 {
537 FIXME("PSN_APPLY!\n");
538 WritePortSettings(hwnd, pPortData);
539 }
540 }
541
542
543 static
544 VOID
545 OnDestroy(
546 HWND hwnd)
547 {
548 PPORT_DATA pPortData;
549
550 TRACE("OnDestroy()\n");
551
552 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
553 if (pPortData == NULL)
554 {
555 ERR("pPortData is NULL\n");
556 return;
557 }
558
559 HeapFree(GetProcessHeap(), 0, pPortData);
560 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL);
561 }
562
563
564 static
565 INT_PTR
566 CALLBACK
567 SerialSettingsDlgProc(HWND hwnd,
568 UINT uMsg,
569 WPARAM wParam,
570 LPARAM lParam)
571 {
572 TRACE("SerialSettingsDlgProc()\n");
573
574 switch (uMsg)
575 {
576 case WM_INITDIALOG:
577 return OnInitDialog(hwnd, wParam, lParam);
578
579 case WM_COMMAND:
580 OnCommand(hwnd, wParam, lParam);
581 break;
582
583 case WM_NOTIFY:
584 OnNotify(hwnd, wParam, lParam);
585 break;
586
587 case WM_DESTROY:
588 OnDestroy(hwnd);
589 break;
590 }
591
592 return FALSE;
593 }
594
595
596 BOOL
597 WINAPI
598 SerialPortPropPageProvider(
599 PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
600 LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
601 LPARAM lParam)
602 {
603 PROPSHEETPAGEW PropSheetPage;
604 HPROPSHEETPAGE hPropSheetPage;
605 PPORT_DATA pPortData;
606
607 TRACE("SerialPortPropPageProvider(%p %p %lx)\n",
608 lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam);
609
610 pPortData = HeapAlloc(GetProcessHeap(),
611 HEAP_ZERO_MEMORY,
612 sizeof(PORT_DATA));
613 if (pPortData == NULL)
614 {
615 ERR("Port data allocation failed!\n");
616 return FALSE;
617 }
618
619 pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet;
620 pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData;
621
622 if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
623 {
624 TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
625
626 PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW);
627 PropSheetPage.dwFlags = 0;
628 PropSheetPage.hInstance = hInstance;
629 PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERIALSETTINGS);
630 PropSheetPage.pfnDlgProc = SerialSettingsDlgProc;
631 PropSheetPage.lParam = (LPARAM)pPortData;
632 PropSheetPage.pfnCallback = NULL;
633
634 hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
635 if (hPropSheetPage == NULL)
636 {
637 ERR("CreatePropertySheetPageW() failed!\n");
638 return FALSE;
639 }
640
641 if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
642 {
643 ERR("lpfnAddPropSheetPageProc() failed!\n");
644 DestroyPropertySheetPage(hPropSheetPage);
645 return FALSE;
646 }
647 }
648
649 TRACE("Done!\n");
650
651 return TRUE;
652 }
653
654 /* EOF */