1 /* 2 * PROJECT: Ports installer library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll\win32\msports\parallel.c 5 * PURPOSE: Parallel Port property functions 6 * COPYRIGHT: Copyright 2013 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 DWORD dwPortNumber; 19 DWORD dwFilterResourceMethod; 20 DWORD dwLegacy; 21 22 } PORT_DATA, *PPORT_DATA; 23 24 25 static 26 VOID 27 GetUsedPorts( 28 PDWORD pPortMap) 29 { 30 WCHAR szDeviceName[64]; 31 WCHAR szDosDeviceName[64]; 32 DWORD dwIndex, dwType, dwPortNumber; 33 DWORD dwDeviceNameSize, dwDosDeviceNameSize; 34 PWSTR ptr; 35 HKEY hKey; 36 DWORD dwError; 37 38 *pPortMap = 0; 39 40 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 41 L"Hardware\\DeviceMap\\PARALLEL PORTS", 42 0, 43 KEY_READ, 44 &hKey); 45 if (dwError == ERROR_SUCCESS) 46 { 47 for (dwIndex = 0; ; dwIndex++) 48 { 49 dwDeviceNameSize = ARRAYSIZE(szDeviceName); 50 dwDosDeviceNameSize = sizeof(szDosDeviceName); 51 dwError = RegEnumValueW(hKey, 52 dwIndex, 53 szDeviceName, 54 &dwDeviceNameSize, 55 NULL, 56 &dwType, 57 (LPBYTE)szDosDeviceName, 58 &dwDosDeviceNameSize); 59 if (dwError != ERROR_SUCCESS) 60 break; 61 62 if (dwType == REG_SZ) 63 { 64 TRACE("%S --> %S\n", szDeviceName, szDosDeviceName); 65 if (_wcsnicmp(szDosDeviceName, L"\\DosDevices\\LPT", wcslen(L"\\DosDevices\\LPT")) == 0) 66 { 67 ptr = szDosDeviceName + wcslen(L"\\DosDevices\\LPT"); 68 if (wcschr(ptr, L'.') == NULL) 69 { 70 TRACE("Device number %S\n", ptr); 71 dwPortNumber = wcstoul(ptr, NULL, 10); 72 if (dwPortNumber != 0) 73 { 74 *pPortMap |=(1 << dwPortNumber); 75 } 76 } 77 } 78 } 79 } 80 81 RegCloseKey(hKey); 82 } 83 84 TRACE("Done\n"); 85 } 86 87 88 static 89 VOID 90 ReadPortSettings( 91 PPORT_DATA pPortData) 92 { 93 DWORD dwSize; 94 HKEY hKey; 95 DWORD dwError; 96 97 TRACE("ReadPortSettings(%p)\n", pPortData); 98 99 pPortData->dwFilterResourceMethod = 1; /* Never use an interrupt */ 100 pPortData->dwLegacy = 0; /* Disabled */ 101 pPortData->dwPortNumber = 0; /* Unknown */ 102 103 hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet, 104 pPortData->DeviceInfoData, 105 DICS_FLAG_GLOBAL, 106 0, 107 DIREG_DEV, 108 KEY_READ); 109 if (hKey != INVALID_HANDLE_VALUE) 110 { 111 dwSize = sizeof(pPortData->szPortName); 112 dwError = RegQueryValueExW(hKey, 113 L"PortName", 114 NULL, 115 NULL, 116 (PBYTE)pPortData->szPortName, 117 &dwSize); 118 if (dwError != ERROR_SUCCESS) 119 { 120 ERR("RegQueryValueExW failed (Error %lu)\n", dwError); 121 } 122 123 dwSize = sizeof(pPortData->dwFilterResourceMethod); 124 dwError = RegQueryValueExW(hKey, 125 L"FilterResourceMethod", 126 NULL, 127 NULL, 128 (PBYTE)&pPortData->dwFilterResourceMethod, 129 &dwSize); 130 if (dwError != ERROR_SUCCESS) 131 { 132 ERR("RegQueryValueExW failed (Error %lu)\n", dwError); 133 } 134 135 RegCloseKey(hKey); 136 } 137 138 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 139 L"SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters", 140 0, 141 KEY_READ, 142 &hKey); 143 if (dwError == ERROR_SUCCESS) 144 { 145 dwSize = sizeof(pPortData->dwLegacy); 146 dwError = RegQueryValueExW(hKey, 147 L"ParEnableLegacyZip", 148 NULL, 149 NULL, 150 (PBYTE)&pPortData->dwLegacy, 151 &dwSize); 152 if (dwError != ERROR_SUCCESS) 153 { 154 ERR("RegQueryValueExW failed (Error %lu)\n", dwError); 155 } 156 157 RegCloseKey(hKey); 158 } 159 } 160 161 162 static 163 DWORD 164 ChangePortNumber( 165 _In_ PPORT_DATA pPortData, 166 _In_ DWORD dwNewPortNumber) 167 { 168 WCHAR szDeviceDescription[256]; 169 WCHAR szFriendlyName[256]; 170 WCHAR szNewPortName[16]; 171 HKEY hDeviceKey = INVALID_HANDLE_VALUE; 172 DWORD dwError; 173 174 /* We are done if old and new port number are the same */ 175 if (pPortData->dwPortNumber == dwNewPortNumber) 176 return ERROR_SUCCESS; 177 178 /* Build the new port name */ 179 swprintf(szNewPortName, L"LPT%lu", dwNewPortNumber); 180 181 /* Open the devices hardware key */ 182 hDeviceKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet, 183 pPortData->DeviceInfoData, 184 DICS_FLAG_GLOBAL, 185 0, 186 DIREG_DEV, 187 KEY_READ | KEY_WRITE); 188 if (hDeviceKey == INVALID_HANDLE_VALUE) 189 { 190 return GetLastError(); 191 } 192 193 /* Set the new 'PortName' value */ 194 dwError = RegSetValueExW(hDeviceKey, 195 L"PortName", 196 0, 197 REG_SZ, 198 (LPBYTE)szNewPortName, 199 (wcslen(szNewPortName) + 1) * sizeof(WCHAR)); 200 if (dwError != ERROR_SUCCESS) 201 goto done; 202 203 /* Save the new port name and number */ 204 wcscpy(pPortData->szPortName, szNewPortName); 205 pPortData->dwPortNumber = dwNewPortNumber; 206 207 /* Get the device description... */ 208 if (SetupDiGetDeviceRegistryProperty(pPortData->DeviceInfoSet, 209 pPortData->DeviceInfoData, 210 SPDRP_DEVICEDESC, 211 NULL, 212 (PBYTE)szDeviceDescription, 213 sizeof(szDeviceDescription), 214 NULL)) 215 { 216 /* ... and use it to build a new friendly name */ 217 swprintf(szFriendlyName, 218 L"%s (%s)", 219 szDeviceDescription, 220 szNewPortName); 221 } 222 else 223 { 224 /* ... or build a generic friendly name */ 225 swprintf(szFriendlyName, 226 L"Parallel Port (%s)", 227 szNewPortName); 228 } 229 230 /* Set the friendly name for the device */ 231 SetupDiSetDeviceRegistryProperty(pPortData->DeviceInfoSet, 232 pPortData->DeviceInfoData, 233 SPDRP_FRIENDLYNAME, 234 (PBYTE)szFriendlyName, 235 (wcslen(szFriendlyName) + 1) * sizeof(WCHAR)); 236 237 done: 238 if (hDeviceKey != INVALID_HANDLE_VALUE) 239 RegCloseKey(hDeviceKey); 240 241 return dwError; 242 } 243 244 245 static 246 VOID 247 WritePortSettings( 248 HWND hwnd, 249 PPORT_DATA pPortData) 250 { 251 SP_PROPCHANGE_PARAMS PropChangeParams; 252 DWORD dwDisposition; 253 DWORD dwFilterResourceMethod; 254 DWORD dwLegacy; 255 DWORD dwPortNumber; 256 DWORD dwPortMap; 257 HKEY hKey; 258 BOOL bChanged = FALSE; 259 DWORD dwError; 260 261 TRACE("WritePortSettings(%p)\n", pPortData); 262 263 dwFilterResourceMethod = 1; 264 if (Button_GetCheck(GetDlgItem(hwnd, IDC_TRY_INTERRUPT)) == BST_CHECKED) 265 dwFilterResourceMethod = 0; 266 else if (Button_GetCheck(GetDlgItem(hwnd, IDC_NEVER_INTERRUPT)) == BST_CHECKED) 267 dwFilterResourceMethod = 1; 268 else if (Button_GetCheck(GetDlgItem(hwnd, IDC_ANY_INTERRUPT)) == BST_CHECKED) 269 dwFilterResourceMethod = 2; 270 271 if (dwFilterResourceMethod != pPortData->dwFilterResourceMethod) 272 { 273 hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet, 274 pPortData->DeviceInfoData, 275 DICS_FLAG_GLOBAL, 276 0, 277 DIREG_DEV, 278 KEY_WRITE); 279 if (hKey != INVALID_HANDLE_VALUE) 280 { 281 dwError = RegSetValueExW(hKey, 282 L"FilterResourceMethod", 283 0, 284 REG_DWORD, 285 (PBYTE)&dwFilterResourceMethod, 286 sizeof(dwFilterResourceMethod)); 287 RegCloseKey(hKey); 288 if (dwError == ERROR_SUCCESS) 289 { 290 pPortData->dwFilterResourceMethod = dwFilterResourceMethod; 291 bChanged = TRUE; 292 } 293 } 294 } 295 296 dwLegacy = 0; 297 if (Button_GetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY)) == BST_CHECKED) 298 dwLegacy = 1; 299 300 if (dwLegacy != pPortData->dwLegacy) 301 { 302 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 303 L"SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters", 304 0, 305 NULL, 306 REG_OPTION_NON_VOLATILE, 307 KEY_WRITE, 308 NULL, 309 &hKey, 310 &dwDisposition); 311 if (dwError == ERROR_SUCCESS) 312 { 313 dwError = RegSetValueExW(hKey, 314 L"ParEnableLegacyZip", 315 0, 316 REG_DWORD, 317 (LPBYTE)&dwLegacy, 318 sizeof(dwLegacy)); 319 RegCloseKey(hKey); 320 321 if (dwError == ERROR_SUCCESS) 322 { 323 pPortData->dwLegacy = dwLegacy; 324 bChanged = TRUE; 325 } 326 } 327 } 328 329 dwPortNumber = ComboBox_GetCurSel(GetDlgItem(hwnd, IDC_PARALLEL_NAME)); 330 if (dwPortNumber != LB_ERR) 331 { 332 dwPortNumber++; 333 if (dwPortNumber != pPortData->dwPortNumber) 334 { 335 GetUsedPorts(&dwPortMap); 336 337 if (dwPortMap & 1 << dwPortNumber) 338 { 339 ERR("Port LPT%lu is already in use!\n", dwPortNumber); 340 } 341 else 342 { 343 ChangePortNumber(pPortData, 344 dwPortNumber); 345 bChanged = TRUE; 346 } 347 } 348 } 349 350 if (bChanged) 351 { 352 /* Notify the system */ 353 PostMessageW(HWND_BROADCAST, 354 WM_WININICHANGE, 355 0, 356 (LPARAM)pPortData->szPortName); 357 358 /* Notify the installer (and device) */ 359 PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); 360 PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; 361 PropChangeParams.Scope = DICS_FLAG_GLOBAL; 362 PropChangeParams.StateChange = DICS_PROPCHANGE; 363 364 SetupDiSetClassInstallParams(pPortData->DeviceInfoSet, 365 pPortData->DeviceInfoData, 366 (PSP_CLASSINSTALL_HEADER)&PropChangeParams, 367 sizeof(SP_PROPCHANGE_PARAMS)); 368 369 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, 370 pPortData->DeviceInfoSet, 371 pPortData->DeviceInfoData); 372 } 373 } 374 375 376 static 377 BOOL 378 OnInitDialog(HWND hwnd, 379 WPARAM wParam, 380 LPARAM lParam) 381 { 382 WCHAR szBuffer[256]; 383 WCHAR szPortInUse[64]; 384 PPORT_DATA pPortData; 385 HWND hwndControl; 386 DWORD dwPortMap; 387 UINT i; 388 389 TRACE("OnInitDialog()\n"); 390 391 pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam; 392 if (pPortData == NULL) 393 { 394 ERR("pPortData is NULL\n"); 395 return FALSE; 396 } 397 398 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData); 399 400 /* Read and parse the port settings */ 401 ReadPortSettings(pPortData); 402 403 /* Set the 'Filter Resource Method' radiobuttons */ 404 hwndControl = GetDlgItem(hwnd, 405 IDC_TRY_INTERRUPT + pPortData->dwFilterResourceMethod); 406 if (hwndControl) 407 Button_SetCheck(hwndControl, BST_CHECKED); 408 409 /* Disable the 'Enable legacy PNP detection' checkbox */ 410 hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_LEGACY); 411 if (hwndControl) 412 { 413 Button_SetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY), 414 pPortData->dwLegacy ? BST_CHECKED : BST_UNCHECKED); 415 } 416 417 LoadStringW(hInstance, IDS_PORT_IN_USE, szPortInUse, ARRAYSIZE(szPortInUse)); 418 419 /* Fill the 'LPT Port Number' combobox */ 420 hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_NAME); 421 if (hwndControl) 422 { 423 GetUsedPorts(&dwPortMap); 424 425 for (i = 1; i < 4; i++) 426 { 427 swprintf(szBuffer, L"LPT%lu", i); 428 429 if ((dwPortMap & (1 << i)) && (pPortData->dwPortNumber != i)) 430 wcscat(szBuffer, szPortInUse); 431 432 ComboBox_AddString(hwndControl, szBuffer); 433 434 if (_wcsicmp(pPortData->szPortName, szBuffer) == 0) 435 pPortData->dwPortNumber = i; 436 } 437 438 if (pPortData->dwPortNumber != 0) 439 { 440 ComboBox_SetCurSel(hwndControl, pPortData->dwPortNumber - 1); 441 } 442 } 443 444 return TRUE; 445 } 446 447 448 static 449 VOID 450 OnNotify( 451 HWND hwnd, 452 WPARAM wParam, 453 LPARAM lParam) 454 { 455 PPORT_DATA pPortData; 456 457 TRACE("OnNotify()\n"); 458 459 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER); 460 if (pPortData == NULL) 461 { 462 ERR("pPortData is NULL\n"); 463 return; 464 } 465 466 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY) 467 { 468 TRACE("PSN_APPLY!\n"); 469 WritePortSettings(hwnd, pPortData); 470 } 471 } 472 473 474 static 475 VOID 476 OnDestroy( 477 HWND hwnd) 478 { 479 PPORT_DATA pPortData; 480 481 TRACE("OnDestroy()\n"); 482 483 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER); 484 if (pPortData == NULL) 485 { 486 ERR("pPortData is NULL\n"); 487 return; 488 } 489 490 HeapFree(GetProcessHeap(), 0, pPortData); 491 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL); 492 } 493 494 495 static 496 INT_PTR 497 CALLBACK 498 ParallelSettingsDlgProc(HWND hwnd, 499 UINT uMsg, 500 WPARAM wParam, 501 LPARAM lParam) 502 { 503 TRACE("ParallelSettingsDlgProc()\n"); 504 505 switch (uMsg) 506 { 507 case WM_INITDIALOG: 508 return OnInitDialog(hwnd, wParam, lParam); 509 510 case WM_NOTIFY: 511 OnNotify(hwnd, wParam, lParam); 512 break; 513 514 case WM_DESTROY: 515 OnDestroy(hwnd); 516 break; 517 } 518 519 return FALSE; 520 } 521 522 523 BOOL 524 WINAPI 525 ParallelPortPropPageProvider(PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest, 526 LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc, 527 LPARAM lParam) 528 { 529 PROPSHEETPAGEW PropSheetPage; 530 HPROPSHEETPAGE hPropSheetPage; 531 PPORT_DATA pPortData; 532 533 TRACE("ParallelPortPropPageProvider(%p %p %lx)\n", 534 lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam); 535 536 pPortData = HeapAlloc(GetProcessHeap(), 537 HEAP_ZERO_MEMORY, 538 sizeof(PORT_DATA)); 539 if (pPortData == NULL) 540 { 541 ERR("Port data allocation failed!\n"); 542 return FALSE; 543 } 544 545 pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet; 546 pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData; 547 548 if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES) 549 { 550 TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n"); 551 552 PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW); 553 PropSheetPage.dwFlags = 0; 554 PropSheetPage.hInstance = hInstance; 555 PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PARALLELSETTINGS); 556 PropSheetPage.pfnDlgProc = ParallelSettingsDlgProc; 557 PropSheetPage.lParam = (LPARAM)pPortData; 558 PropSheetPage.pfnCallback = NULL; 559 560 hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage); 561 if (hPropSheetPage == NULL) 562 { 563 ERR("CreatePropertySheetPageW() failed!\n"); 564 return FALSE; 565 } 566 567 if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam)) 568 { 569 ERR("lpfnAddPropSheetPageProc() failed!\n"); 570 DestroyPropertySheetPage(hPropSheetPage); 571 return FALSE; 572 } 573 } 574 575 TRACE("Done!\n"); 576 577 return TRUE; 578 } 579 580 /* EOF */ 581