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 DWORD dwDisposition; 252 DWORD dwFilterResourceMethod; 253 DWORD dwLegacy; 254 DWORD dwPortNumber; 255 DWORD dwPortMap; 256 HKEY hKey; 257 DWORD dwError; 258 259 TRACE("WritePortSettings(%p)\n", pPortData); 260 261 dwFilterResourceMethod = 1; 262 if (Button_GetCheck(GetDlgItem(hwnd, IDC_TRY_INTERRUPT)) == BST_CHECKED) 263 dwFilterResourceMethod = 0; 264 else if (Button_GetCheck(GetDlgItem(hwnd, IDC_NEVER_INTERRUPT)) == BST_CHECKED) 265 dwFilterResourceMethod = 1; 266 else if (Button_GetCheck(GetDlgItem(hwnd, IDC_ANY_INTERRUPT)) == BST_CHECKED) 267 dwFilterResourceMethod = 2; 268 269 if (dwFilterResourceMethod != pPortData->dwFilterResourceMethod) 270 { 271 hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet, 272 pPortData->DeviceInfoData, 273 DICS_FLAG_GLOBAL, 274 0, 275 DIREG_DEV, 276 KEY_WRITE); 277 if (hKey != INVALID_HANDLE_VALUE) 278 { 279 dwError = RegSetValueExW(hKey, 280 L"FilterResourceMethod", 281 0, 282 REG_DWORD, 283 (PBYTE)&dwFilterResourceMethod, 284 sizeof(dwFilterResourceMethod)); 285 if (dwError != ERROR_SUCCESS) 286 { 287 ERR("RegSetValueExW failed (Error %lu)\n", dwError); 288 } 289 290 RegCloseKey(hKey); 291 pPortData->dwFilterResourceMethod = dwFilterResourceMethod; 292 } 293 } 294 295 dwLegacy = 0; 296 if (Button_GetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY)) == BST_CHECKED) 297 dwLegacy = 1; 298 299 if (dwLegacy != pPortData->dwLegacy) 300 { 301 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 302 L"SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters", 303 0, 304 NULL, 305 REG_OPTION_NON_VOLATILE, 306 KEY_WRITE, 307 NULL, 308 &hKey, 309 &dwDisposition); 310 if (dwError == ERROR_SUCCESS) 311 { 312 dwError = RegSetValueExW(hKey, 313 L"ParEnableLegacyZip", 314 0, 315 REG_DWORD, 316 (LPBYTE)&dwLegacy, 317 sizeof(dwLegacy)); 318 RegCloseKey(hKey); 319 320 if (dwError == ERROR_SUCCESS) 321 { 322 FIXME("Notify the driver!\n"); 323 324 pPortData->dwLegacy = dwLegacy; 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 return; 341 } 342 343 ChangePortNumber(pPortData, 344 dwPortNumber); 345 } 346 } 347 } 348 349 350 static 351 BOOL 352 OnInitDialog(HWND hwnd, 353 WPARAM wParam, 354 LPARAM lParam) 355 { 356 WCHAR szBuffer[256]; 357 WCHAR szPortInUse[64]; 358 PPORT_DATA pPortData; 359 HWND hwndControl; 360 DWORD dwPortMap; 361 UINT i; 362 363 TRACE("OnInitDialog()\n"); 364 365 pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam; 366 if (pPortData == NULL) 367 { 368 ERR("pPortData is NULL\n"); 369 return FALSE; 370 } 371 372 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData); 373 374 /* Read and parse the port settings */ 375 ReadPortSettings(pPortData); 376 377 /* Set the 'Filter Resource Method' radiobuttons */ 378 hwndControl = GetDlgItem(hwnd, 379 IDC_TRY_INTERRUPT + pPortData->dwFilterResourceMethod); 380 if (hwndControl) 381 Button_SetCheck(hwndControl, BST_CHECKED); 382 383 /* Disable the 'Enable legacy PNP detection' checkbox */ 384 hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_LEGACY); 385 if (hwndControl) 386 { 387 Button_SetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY), 388 pPortData->dwLegacy ? BST_CHECKED : BST_UNCHECKED); 389 } 390 391 LoadStringW(hInstance, IDS_PORT_IN_USE, szPortInUse, ARRAYSIZE(szPortInUse)); 392 393 /* Fill the 'LPT Port Number' combobox */ 394 hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_NAME); 395 if (hwndControl) 396 { 397 GetUsedPorts(&dwPortMap); 398 399 for (i = 1; i < 4; i++) 400 { 401 swprintf(szBuffer, L"LPT%lu", i); 402 403 if ((dwPortMap & (1 << i)) && (pPortData->dwPortNumber != i)) 404 wcscat(szBuffer, szPortInUse); 405 406 ComboBox_AddString(hwndControl, szBuffer); 407 408 if (_wcsicmp(pPortData->szPortName, szBuffer) == 0) 409 pPortData->dwPortNumber = i; 410 } 411 412 if (pPortData->dwPortNumber != 0) 413 { 414 ComboBox_SetCurSel(hwndControl, pPortData->dwPortNumber - 1); 415 } 416 } 417 418 return TRUE; 419 } 420 421 422 static 423 VOID 424 OnNotify( 425 HWND hwnd, 426 WPARAM wParam, 427 LPARAM lParam) 428 { 429 PPORT_DATA pPortData; 430 431 TRACE("OnNotify()\n"); 432 433 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER); 434 if (pPortData == NULL) 435 { 436 ERR("pPortData is NULL\n"); 437 return; 438 } 439 440 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY) 441 { 442 TRACE("PSN_APPLY!\n"); 443 WritePortSettings(hwnd, pPortData); 444 } 445 } 446 447 448 static 449 VOID 450 OnDestroy( 451 HWND hwnd) 452 { 453 PPORT_DATA pPortData; 454 455 TRACE("OnDestroy()\n"); 456 457 pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER); 458 if (pPortData == NULL) 459 { 460 ERR("pPortData is NULL\n"); 461 return; 462 } 463 464 HeapFree(GetProcessHeap(), 0, pPortData); 465 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL); 466 } 467 468 469 static 470 INT_PTR 471 CALLBACK 472 ParallelSettingsDlgProc(HWND hwnd, 473 UINT uMsg, 474 WPARAM wParam, 475 LPARAM lParam) 476 { 477 TRACE("ParallelSettingsDlgProc()\n"); 478 479 switch (uMsg) 480 { 481 case WM_INITDIALOG: 482 return OnInitDialog(hwnd, wParam, lParam); 483 484 case WM_NOTIFY: 485 OnNotify(hwnd, wParam, lParam); 486 break; 487 488 case WM_DESTROY: 489 OnDestroy(hwnd); 490 break; 491 } 492 493 return FALSE; 494 } 495 496 497 BOOL 498 WINAPI 499 ParallelPortPropPageProvider(PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest, 500 LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc, 501 LPARAM lParam) 502 { 503 PROPSHEETPAGEW PropSheetPage; 504 HPROPSHEETPAGE hPropSheetPage; 505 PPORT_DATA pPortData; 506 507 TRACE("ParallelPortPropPageProvider(%p %p %lx)\n", 508 lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam); 509 510 pPortData = HeapAlloc(GetProcessHeap(), 511 HEAP_ZERO_MEMORY, 512 sizeof(PORT_DATA)); 513 if (pPortData == NULL) 514 { 515 ERR("Port data allocation failed!\n"); 516 return FALSE; 517 } 518 519 pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet; 520 pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData; 521 522 if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES) 523 { 524 TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n"); 525 526 PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW); 527 PropSheetPage.dwFlags = 0; 528 PropSheetPage.hInstance = hInstance; 529 PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PARALLELSETTINGS); 530 PropSheetPage.pfnDlgProc = ParallelSettingsDlgProc; 531 PropSheetPage.lParam = (LPARAM)pPortData; 532 PropSheetPage.pfnCallback = NULL; 533 534 hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage); 535 if (hPropSheetPage == NULL) 536 { 537 ERR("CreatePropertySheetPageW() failed!\n"); 538 return FALSE; 539 } 540 541 if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam)) 542 { 543 ERR("lpfnAddPropSheetPageProc() failed!\n"); 544 DestroyPropertySheetPage(hPropSheetPage); 545 return FALSE; 546 } 547 } 548 549 TRACE("Done!\n"); 550 551 return TRUE; 552 } 553 554 /* EOF */ 555