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 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 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 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 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 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 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 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 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 */