xref: /reactos/dll/win32/msports/serial.c (revision 4561998a)
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 */