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