b248072a303ea1647d2b6d45ab9b7fcb9ff483dd
[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 TRACE("Done!\n");
327 }
328
329
330 static
331 BOOL
332 OnInitDialog(
333 HWND hwnd,
334 WPARAM wParam,
335 LPARAM lParam)
336 {
337 PPORT_DATA pPortData;
338 WCHAR szBuffer[256];
339 UINT i;
340 HWND hwndControl;
341
342 TRACE("OnInitDialog()\n");
343
344 pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam;
345 if (pPortData == NULL)
346 {
347 ERR("pPortData is NULL\n");
348 return FALSE;
349 }
350
351 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData);
352
353 /* Read and parse the port settings */
354 ReadPortSettings(pPortData);
355
356 /* Fill the 'Bits per second' combobox */
357 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
358 if (hwndControl)
359 {
360 for (i = 0; i < ARRAYSIZE(BaudRates); i++)
361 {
362 _ultow(BaudRates[i], szBuffer, 10);
363 ComboBox_AddString(hwndControl, szBuffer);
364 }
365
366 ComboBox_SetCurSel(hwndControl, pPortData->nBaudRateIndex);
367 }
368
369 /* Fill the 'Data bits' combobox */
370 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
371 if (hwndControl)
372 {
373 for (i = 0; i < ARRAYSIZE(DataBits); i++)
374 {
375 ComboBox_AddString(hwndControl, DataBits[i]);
376 }
377
378 ComboBox_SetCurSel(hwndControl, pPortData->nDataBitsIndex);
379 }
380
381 /* Fill the 'Parity' combobox */
382 LoadStringW(hInstance, IDS_PARITY, szBuffer, ARRAYSIZE(szBuffer));
383
384 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
385 if (hwndControl)
386 {
387 FillComboBox(hwndControl, szBuffer);
388 ComboBox_SetCurSel(hwndControl, pPortData->nParityIndex);
389 }
390
391 /* Fill the 'Stop bits' combobox */
392 LoadStringW(hInstance, IDS_STOPBITS, szBuffer, ARRAYSIZE(szBuffer));
393
394 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
395 if (hwndControl)
396 {
397 FillComboBox(hwndControl, szBuffer);
398 ComboBox_SetCurSel(hwndControl, pPortData->nStopBitsIndex);
399 }
400
401 /* Fill the 'Flow control' combobox */
402 LoadStringW(hInstance, IDS_FLOWCONTROL, szBuffer, ARRAYSIZE(szBuffer));
403
404 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
405 if (hwndControl)
406 {
407 FillComboBox(hwndControl, szBuffer);
408 ComboBox_SetCurSel(hwndControl, pPortData->nFlowControlIndex);
409 }
410
411 /* Disable the 'Advanced' button */
412 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_ADVANCED);
413 if (hwndControl)
414 EnableWindow(hwndControl, FALSE);
415
416 return TRUE;
417 }
418
419
420 static
421 VOID
422 RestoreDefaultValues(
423 HWND hwnd,
424 PPORT_DATA pPortData)
425 {
426 HWND hwndControl;
427
428 /* Reset the 'Bits per second' combobox */
429 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
430 if (hwndControl)
431 {
432 ComboBox_SetCurSel(hwndControl, DEFAULT_BAUD_RATE_INDEX);
433 }
434
435 /* Reset the 'Data bits' combobox */
436 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
437 if (hwndControl)
438 {
439 ComboBox_SetCurSel(hwndControl, DEFAULT_DATA_BITS_INDEX);
440 }
441
442 /* Reset the 'Parity' combobox */
443 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
444 if (hwndControl)
445 {
446 ComboBox_SetCurSel(hwndControl, DEFAULT_PARITY_INDEX);
447 }
448
449 /* Reset the 'Stop bits' combobox */
450 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
451 if (hwndControl)
452 {
453 ComboBox_SetCurSel(hwndControl, DEFAULT_STOP_BITS_INDEX);
454 }
455
456 /* Reset the 'Flow control' combobox */
457 hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
458 if (hwndControl)
459 {
460 ComboBox_SetCurSel(hwndControl, DEFAULT_FLOW_CONTROL_INDEX);
461 }
462
463 pPortData->bChanged = TRUE;
464 }
465
466
467 static
468 VOID
469 OnCommand(
470 HWND hwnd,
471 WPARAM wParam,
472 LPARAM lParam)
473 {
474 PPORT_DATA pPortData;
475
476 TRACE("OnCommand()\n");
477
478 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
479 if (pPortData == NULL)
480 {
481 ERR("pPortData is NULL\n");
482 return;
483 }
484
485 switch (LOWORD(wParam))
486 {
487 case IDC_SERIAL_BITSPERSECOND:
488 case IDC_SERIAL_DATABITS:
489 case IDC_SERIAL_PARITY:
490 case IDC_SERIAL_STOPBITS:
491 case IDC_SERIAL_FLOWCONTROL:
492 if (HIWORD(wParam) == CBN_SELCHANGE ||
493 HIWORD(wParam) == CBN_EDITCHANGE)
494 {
495 pPortData->bChanged = TRUE;
496 }
497 break;
498
499 // case IDC_SERIAL_ADVANCED:
500
501 case IDC_SERIAL_RESTORE:
502 RestoreDefaultValues(hwnd, pPortData);
503 break;
504
505 default:
506 break;
507 }
508 }
509
510
511 static
512 VOID
513 OnNotify(
514 HWND hwnd,
515 WPARAM wParam,
516 LPARAM lParam)
517 {
518 PPORT_DATA pPortData;
519
520 TRACE("OnCommand()\n");
521
522 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
523 if (pPortData == NULL)
524 {
525 ERR("pPortData is NULL\n");
526 return;
527 }
528
529 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
530 {
531 FIXME("PSN_APPLY!\n");
532 WritePortSettings(hwnd, pPortData);
533 }
534 }
535
536
537 static
538 VOID
539 OnDestroy(
540 HWND hwnd)
541 {
542 PPORT_DATA pPortData;
543
544 TRACE("OnDestroy()\n");
545
546 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
547 if (pPortData == NULL)
548 {
549 ERR("pPortData is NULL\n");
550 return;
551 }
552
553 HeapFree(GetProcessHeap(), 0, pPortData);
554 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL);
555 }
556
557
558 static
559 INT_PTR
560 CALLBACK
561 SerialSettingsDlgProc(HWND hwnd,
562 UINT uMsg,
563 WPARAM wParam,
564 LPARAM lParam)
565 {
566 TRACE("SerialSettingsDlgProc()\n");
567
568 switch (uMsg)
569 {
570 case WM_INITDIALOG:
571 return OnInitDialog(hwnd, wParam, lParam);
572
573 case WM_COMMAND:
574 OnCommand(hwnd, wParam, lParam);
575 break;
576
577 case WM_NOTIFY:
578 OnNotify(hwnd, wParam, lParam);
579 break;
580
581 case WM_DESTROY:
582 OnDestroy(hwnd);
583 break;
584 }
585
586 return FALSE;
587 }
588
589
590 BOOL
591 WINAPI
592 SerialPortPropPageProvider(
593 PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
594 LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
595 LPARAM lParam)
596 {
597 PROPSHEETPAGEW PropSheetPage;
598 HPROPSHEETPAGE hPropSheetPage;
599 PPORT_DATA pPortData;
600
601 TRACE("SerialPortPropPageProvider(%p %p %lx)\n",
602 lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam);
603
604 pPortData = HeapAlloc(GetProcessHeap(),
605 HEAP_ZERO_MEMORY,
606 sizeof(PORT_DATA));
607 if (pPortData == NULL)
608 {
609 ERR("Port data allocation failed!\n");
610 return FALSE;
611 }
612
613 pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet;
614 pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData;
615
616 if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
617 {
618 TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
619
620 PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW);
621 PropSheetPage.dwFlags = 0;
622 PropSheetPage.hInstance = hInstance;
623 PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERIALSETTINGS);
624 PropSheetPage.pfnDlgProc = SerialSettingsDlgProc;
625 PropSheetPage.lParam = (LPARAM)pPortData;
626 PropSheetPage.pfnCallback = NULL;
627
628 hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
629 if (hPropSheetPage == NULL)
630 {
631 ERR("CreatePropertySheetPageW() failed!\n");
632 return FALSE;
633 }
634
635 if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
636 {
637 ERR("lpfnAddPropSheetPageProc() failed!\n");
638 DestroyPropertySheetPage(hPropSheetPage);
639 return FALSE;
640 }
641 }
642
643 TRACE("Done!\n");
644
645 return TRUE;
646 }
647
648 /* EOF */