xref: /reactos/dll/win32/msports/serial.c (revision 0c2cdcae)
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
FillComboBox(HWND hwnd,PWSTR szBuffer)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
ReadPortSettings(PPORT_DATA pPortData)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
WritePortSettings(HWND hwnd,PPORT_DATA pPortData)228 WritePortSettings(
229     HWND hwnd,
230     PPORT_DATA pPortData)
231 {
232     SP_PROPCHANGE_PARAMS PropChangeParams;
233     WCHAR szPortData[32];
234     HWND hwndControl;
235     INT nBaudRateIndex;
236     INT nDataBitsIndex;
237     INT nParityIndex;
238     INT nStopBitsIndex;
239     INT nFlowControlIndex;
240     HKEY hKey;
241     LONG lError;
242 
243     TRACE("WritePortSettings(%p)\n", pPortData);
244 
245     if (pPortData->bChanged == FALSE)
246     {
247         TRACE("Nothing changed. Done!\n");
248         return;
249     }
250 
251     nBaudRateIndex = pPortData->nBaudRateIndex;
252     nDataBitsIndex = pPortData->nDataBitsIndex;
253     nParityIndex = pPortData->nParityIndex;
254     nStopBitsIndex = pPortData->nStopBitsIndex;
255     nFlowControlIndex = pPortData->nFlowControlIndex;
256 
257     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
258     if (hwndControl)
259     {
260         nBaudRateIndex = ComboBox_GetCurSel(hwndControl);
261     }
262 
263     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
264     if (hwndControl)
265     {
266         nDataBitsIndex = ComboBox_GetCurSel(hwndControl);
267     }
268 
269     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
270     if (hwndControl)
271     {
272         nParityIndex = ComboBox_GetCurSel(hwndControl);
273     }
274 
275     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
276     if (hwndControl)
277     {
278         nStopBitsIndex = ComboBox_GetCurSel(hwndControl);
279     }
280 
281     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
282     if (hwndControl)
283     {
284         nFlowControlIndex = ComboBox_GetCurSel(hwndControl);
285     }
286 
287     swprintf(szPortData,
288              L"%lu,%s,%s,%s",
289              BaudRates[nBaudRateIndex],
290              Paritys[nParityIndex],
291              DataBits[nDataBitsIndex],
292              StopBits[nStopBitsIndex]);
293     if (nFlowControlIndex < 2)
294     {
295         wcscat(szPortData, L",");
296         wcscat(szPortData, FlowControls[nFlowControlIndex]);
297     }
298 
299     TRACE("szPortData: '%S'\n", szPortData);
300 
301     lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
302                            L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports",
303                            0,
304                            KEY_WRITE,
305                            &hKey);
306     if (lError != ERROR_SUCCESS)
307     {
308         ERR("RegOpenKeyExW failed (Error %lu)\n", lError);
309         return;
310     }
311 
312     lError = RegSetValueExW(hKey,
313                             pPortData->szPortName,
314                             0,
315                             REG_SZ,
316                             (LPBYTE)szPortData,
317                             (wcslen(szPortData) + 1) * sizeof(WCHAR));
318 
319     RegCloseKey(hKey);
320 
321     if (lError != ERROR_SUCCESS)
322     {
323         ERR("RegSetValueExW failed (Error %lu)\n", lError);
324         return;
325     }
326 
327     /* Notify the system */
328     PostMessageW(HWND_BROADCAST,
329                  WM_WININICHANGE,
330                  0,
331                  (LPARAM)pPortData->szPortName);
332 
333     /* Notify the installer (and device) */
334     PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
335     PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
336     PropChangeParams.Scope = DICS_FLAG_GLOBAL;
337     PropChangeParams.StateChange = DICS_PROPCHANGE;
338 
339     SetupDiSetClassInstallParams(pPortData->DeviceInfoSet,
340                                  pPortData->DeviceInfoData,
341                                  (PSP_CLASSINSTALL_HEADER)&PropChangeParams,
342                                  sizeof(SP_PROPCHANGE_PARAMS));
343 
344     SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
345                               pPortData->DeviceInfoSet,
346                               pPortData->DeviceInfoData);
347 
348     TRACE("Done!\n");
349 }
350 
351 
352 static
353 BOOL
OnInitDialog(HWND hwnd,WPARAM wParam,LPARAM lParam)354 OnInitDialog(
355     HWND hwnd,
356     WPARAM wParam,
357     LPARAM lParam)
358 {
359     PPORT_DATA pPortData;
360     WCHAR szBuffer[256];
361     UINT i;
362     HWND hwndControl;
363 
364     TRACE("OnInitDialog()\n");
365 
366     pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam;
367     if (pPortData == NULL)
368     {
369         ERR("pPortData is NULL\n");
370         return FALSE;
371     }
372 
373     SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData);
374 
375     /* Read and parse the port settings */
376     ReadPortSettings(pPortData);
377 
378     /* Fill the 'Bits per second' combobox */
379     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
380     if (hwndControl)
381     {
382         for (i = 0; i < ARRAYSIZE(BaudRates); i++)
383         {
384             _ultow(BaudRates[i], szBuffer, 10);
385             ComboBox_AddString(hwndControl, szBuffer);
386         }
387 
388         ComboBox_SetCurSel(hwndControl, pPortData->nBaudRateIndex);
389     }
390 
391     /* Fill the 'Data bits' combobox */
392     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
393     if (hwndControl)
394     {
395         for (i = 0; i < ARRAYSIZE(DataBits); i++)
396         {
397             ComboBox_AddString(hwndControl, DataBits[i]);
398         }
399 
400         ComboBox_SetCurSel(hwndControl, pPortData->nDataBitsIndex);
401     }
402 
403     /* Fill the 'Parity' combobox */
404     LoadStringW(hInstance, IDS_PARITY, szBuffer, ARRAYSIZE(szBuffer));
405 
406     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
407     if (hwndControl)
408     {
409         FillComboBox(hwndControl, szBuffer);
410         ComboBox_SetCurSel(hwndControl, pPortData->nParityIndex);
411     }
412 
413     /* Fill the 'Stop bits' combobox */
414     LoadStringW(hInstance, IDS_STOPBITS, szBuffer, ARRAYSIZE(szBuffer));
415 
416     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
417     if (hwndControl)
418     {
419         FillComboBox(hwndControl, szBuffer);
420         ComboBox_SetCurSel(hwndControl, pPortData->nStopBitsIndex);
421     }
422 
423     /* Fill the 'Flow control' combobox */
424     LoadStringW(hInstance, IDS_FLOWCONTROL, szBuffer, ARRAYSIZE(szBuffer));
425 
426     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
427     if (hwndControl)
428     {
429         FillComboBox(hwndControl, szBuffer);
430         ComboBox_SetCurSel(hwndControl, pPortData->nFlowControlIndex);
431     }
432 
433     /* Disable the 'Advanced' button */
434     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_ADVANCED);
435     if (hwndControl)
436         EnableWindow(hwndControl, FALSE);
437 
438     return TRUE;
439 }
440 
441 
442 static
443 VOID
RestoreDefaultValues(HWND hwnd,PPORT_DATA pPortData)444 RestoreDefaultValues(
445     HWND hwnd,
446     PPORT_DATA pPortData)
447 {
448     HWND hwndControl;
449 
450     /* Reset the 'Bits per second' combobox */
451     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
452     if (hwndControl)
453     {
454         ComboBox_SetCurSel(hwndControl, DEFAULT_BAUD_RATE_INDEX);
455     }
456 
457     /* Reset the 'Data bits' combobox */
458     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
459     if (hwndControl)
460     {
461         ComboBox_SetCurSel(hwndControl, DEFAULT_DATA_BITS_INDEX);
462     }
463 
464     /* Reset the 'Parity' combobox */
465     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
466     if (hwndControl)
467     {
468         ComboBox_SetCurSel(hwndControl, DEFAULT_PARITY_INDEX);
469     }
470 
471     /* Reset the 'Stop bits' combobox */
472     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
473     if (hwndControl)
474     {
475         ComboBox_SetCurSel(hwndControl, DEFAULT_STOP_BITS_INDEX);
476     }
477 
478     /* Reset the 'Flow control' combobox */
479     hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
480     if (hwndControl)
481     {
482         ComboBox_SetCurSel(hwndControl, DEFAULT_FLOW_CONTROL_INDEX);
483     }
484 
485     pPortData->bChanged = TRUE;
486 }
487 
488 
489 static
490 VOID
OnCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)491 OnCommand(
492     HWND hwnd,
493     WPARAM wParam,
494     LPARAM lParam)
495 {
496     PPORT_DATA pPortData;
497 
498     TRACE("OnCommand()\n");
499 
500     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
501     if (pPortData == NULL)
502     {
503         ERR("pPortData is NULL\n");
504         return;
505     }
506 
507     switch (LOWORD(wParam))
508     {
509         case IDC_SERIAL_BITSPERSECOND:
510         case IDC_SERIAL_DATABITS:
511         case IDC_SERIAL_PARITY:
512         case IDC_SERIAL_STOPBITS:
513         case IDC_SERIAL_FLOWCONTROL:
514             if (HIWORD(wParam) == CBN_SELCHANGE ||
515                 HIWORD(wParam) == CBN_EDITCHANGE)
516             {
517                 pPortData->bChanged = TRUE;
518             }
519             break;
520 
521 //        case IDC_SERIAL_ADVANCED:
522 
523         case IDC_SERIAL_RESTORE:
524             RestoreDefaultValues(hwnd, pPortData);
525             break;
526 
527         default:
528             break;
529     }
530 }
531 
532 
533 static
534 VOID
OnNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)535 OnNotify(
536     HWND hwnd,
537     WPARAM wParam,
538     LPARAM lParam)
539 {
540     PPORT_DATA pPortData;
541 
542     TRACE("OnCommand()\n");
543 
544     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
545     if (pPortData == NULL)
546     {
547         ERR("pPortData is NULL\n");
548         return;
549     }
550 
551     if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
552     {
553         FIXME("PSN_APPLY!\n");
554         WritePortSettings(hwnd, pPortData);
555     }
556 }
557 
558 
559 static
560 VOID
OnDestroy(HWND hwnd)561 OnDestroy(
562     HWND hwnd)
563 {
564     PPORT_DATA pPortData;
565 
566     TRACE("OnDestroy()\n");
567 
568     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
569     if (pPortData == NULL)
570     {
571         ERR("pPortData is NULL\n");
572         return;
573     }
574 
575     HeapFree(GetProcessHeap(), 0, pPortData);
576     SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL);
577 }
578 
579 
580 static
581 INT_PTR
582 CALLBACK
SerialSettingsDlgProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)583 SerialSettingsDlgProc(HWND hwnd,
584                       UINT uMsg,
585                       WPARAM wParam,
586                       LPARAM lParam)
587 {
588     TRACE("SerialSettingsDlgProc()\n");
589 
590     switch (uMsg)
591     {
592         case WM_INITDIALOG:
593             return OnInitDialog(hwnd, wParam, lParam);
594 
595         case WM_COMMAND:
596             OnCommand(hwnd, wParam, lParam);
597             break;
598 
599         case WM_NOTIFY:
600             OnNotify(hwnd, wParam, lParam);
601             break;
602 
603         case WM_DESTROY:
604             OnDestroy(hwnd);
605             break;
606     }
607 
608     return FALSE;
609 }
610 
611 
612 BOOL
613 WINAPI
SerialPortPropPageProvider(PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,LPARAM lParam)614 SerialPortPropPageProvider(
615     PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
616     LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
617     LPARAM lParam)
618 {
619     PROPSHEETPAGEW PropSheetPage;
620     HPROPSHEETPAGE hPropSheetPage;
621     PPORT_DATA pPortData;
622 
623     TRACE("SerialPortPropPageProvider(%p %p %lx)\n",
624           lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam);
625 
626     pPortData = HeapAlloc(GetProcessHeap(),
627                           HEAP_ZERO_MEMORY,
628                           sizeof(PORT_DATA));
629     if (pPortData == NULL)
630     {
631         ERR("Port data allocation failed!\n");
632         return FALSE;
633     }
634 
635     pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet;
636     pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData;
637 
638     if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
639     {
640         TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
641 
642         PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW);
643         PropSheetPage.dwFlags = 0;
644         PropSheetPage.hInstance = hInstance;
645         PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERIALSETTINGS);
646         PropSheetPage.pfnDlgProc = SerialSettingsDlgProc;
647         PropSheetPage.lParam = (LPARAM)pPortData;
648         PropSheetPage.pfnCallback = NULL;
649 
650         hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
651         if (hPropSheetPage == NULL)
652         {
653             ERR("CreatePropertySheetPageW() failed!\n");
654             return FALSE;
655         }
656 
657         if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
658         {
659             ERR("lpfnAddPropSheetPageProc() failed!\n");
660             DestroyPropertySheetPage(hPropSheetPage);
661             return FALSE;
662         }
663     }
664 
665     TRACE("Done!\n");
666 
667     return TRUE;
668 }
669 
670 /* EOF */
671