1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Video initialization and display settings 5 * FILE: win32ss/user/ntuser/display.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org) 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserDisplay); 11 12 BOOL gbBaseVideo = 0; 13 static PPROCESSINFO gpFullscreen = NULL; 14 15 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO"; 16 17 VOID 18 RegWriteDisplaySettings(HKEY hkey, PDEVMODEW pdm) 19 { 20 RegWriteDWORD(hkey, L"DefaultSettings.BitsPerPel", pdm->dmBitsPerPel); 21 RegWriteDWORD(hkey, L"DefaultSettings.XResolution", pdm->dmPelsWidth); 22 RegWriteDWORD(hkey, L"DefaultSettings.YResolution", pdm->dmPelsHeight); 23 RegWriteDWORD(hkey, L"DefaultSettings.Flags", pdm->dmDisplayFlags); 24 RegWriteDWORD(hkey, L"DefaultSettings.VRefresh", pdm->dmDisplayFrequency); 25 RegWriteDWORD(hkey, L"DefaultSettings.XPanning", pdm->dmPanningWidth); 26 RegWriteDWORD(hkey, L"DefaultSettings.YPanning", pdm->dmPanningHeight); 27 RegWriteDWORD(hkey, L"DefaultSettings.Orientation", pdm->dmDisplayOrientation); 28 RegWriteDWORD(hkey, L"DefaultSettings.FixedOutput", pdm->dmDisplayFixedOutput); 29 RegWriteDWORD(hkey, L"Attach.RelativeX", pdm->dmPosition.x); 30 RegWriteDWORD(hkey, L"Attach.RelativeY", pdm->dmPosition.y); 31 // RegWriteDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", pdm->); 32 } 33 34 VOID 35 RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm) 36 { 37 DWORD dwValue; 38 39 /* Zero out the structure */ 40 RtlZeroMemory(pdm, sizeof(DEVMODEW)); 41 42 /* Helper macro */ 43 #define READ(field, str, flag) \ 44 if (RegReadDWORD(hkey, L##str, &dwValue)) \ 45 { \ 46 pdm->field = dwValue; \ 47 pdm->dmFields |= flag; \ 48 } 49 50 /* Read all present settings */ 51 READ(dmBitsPerPel, "DefaultSettings.BitsPerPel", DM_BITSPERPEL); 52 READ(dmPelsWidth, "DefaultSettings.XResolution", DM_PELSWIDTH); 53 READ(dmPelsHeight, "DefaultSettings.YResolution", DM_PELSHEIGHT); 54 READ(dmDisplayFlags, "DefaultSettings.Flags", DM_DISPLAYFLAGS); 55 READ(dmDisplayFrequency, "DefaultSettings.VRefresh", DM_DISPLAYFREQUENCY); 56 READ(dmPanningWidth, "DefaultSettings.XPanning", DM_PANNINGWIDTH); 57 READ(dmPanningHeight, "DefaultSettings.YPanning", DM_PANNINGHEIGHT); 58 READ(dmDisplayOrientation, "DefaultSettings.Orientation", DM_DISPLAYORIENTATION); 59 READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput", DM_DISPLAYFIXEDOUTPUT); 60 READ(dmPosition.x, "Attach.RelativeX", DM_POSITION); 61 READ(dmPosition.y, "Attach.RelativeY", DM_POSITION); 62 } 63 64 PGRAPHICS_DEVICE 65 NTAPI 66 InitDisplayDriver( 67 IN PWSTR pwszDeviceName, 68 IN PWSTR pwszRegKey) 69 { 70 PGRAPHICS_DEVICE pGraphicsDevice; 71 UNICODE_STRING ustrDeviceName, ustrDisplayDrivers, ustrDescription; 72 NTSTATUS Status; 73 WCHAR awcBuffer[128]; 74 ULONG cbSize; 75 HKEY hkey; 76 DEVMODEW dmDefault; 77 DWORD dwVga; 78 79 TRACE("InitDisplayDriver(%S, %S);\n", 80 pwszDeviceName, pwszRegKey); 81 82 /* Open the driver's registry key */ 83 Status = RegOpenKey(pwszRegKey, &hkey); 84 if (!NT_SUCCESS(Status)) 85 { 86 ERR("Failed to open registry key: %ls\n", pwszRegKey); 87 return NULL; 88 } 89 90 /* Query the diplay drivers */ 91 cbSize = sizeof(awcBuffer) - 10; 92 Status = RegQueryValue(hkey, 93 L"InstalledDisplayDrivers", 94 REG_MULTI_SZ, 95 awcBuffer, 96 &cbSize); 97 if (!NT_SUCCESS(Status)) 98 { 99 ERR("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status); 100 ZwClose(hkey); 101 return NULL; 102 } 103 104 /* Initialize the UNICODE_STRING */ 105 ustrDisplayDrivers.Buffer = awcBuffer; 106 ustrDisplayDrivers.MaximumLength = (USHORT)cbSize; 107 ustrDisplayDrivers.Length = (USHORT)cbSize; 108 109 /* Set Buffer for description and size of remaining buffer */ 110 ustrDescription.Buffer = awcBuffer + (cbSize / sizeof(WCHAR)); 111 cbSize = sizeof(awcBuffer) - cbSize; 112 113 /* Query the device string */ 114 Status = RegQueryValue(hkey, 115 L"Device Description", 116 REG_SZ, 117 ustrDescription.Buffer, 118 &cbSize); 119 if (NT_SUCCESS(Status)) 120 { 121 ustrDescription.MaximumLength = (USHORT)cbSize; 122 ustrDescription.Length = (USHORT)cbSize; 123 } 124 else 125 { 126 RtlInitUnicodeString(&ustrDescription, L"<unknown>"); 127 } 128 129 /* Query the default settings */ 130 RegReadDisplaySettings(hkey, &dmDefault); 131 132 /* Query if this is a VGA compatible driver */ 133 cbSize = sizeof(DWORD); 134 Status = RegQueryValue(hkey, L"VgaCompatible", REG_DWORD, &dwVga, &cbSize); 135 if (!NT_SUCCESS(Status)) dwVga = 0; 136 137 /* Close the registry key */ 138 ZwClose(hkey); 139 140 /* Register the device with GDI */ 141 RtlInitUnicodeString(&ustrDeviceName, pwszDeviceName); 142 pGraphicsDevice = EngpRegisterGraphicsDevice(&ustrDeviceName, 143 &ustrDisplayDrivers, 144 &ustrDescription, 145 &dmDefault); 146 if (pGraphicsDevice && dwVga) 147 { 148 pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_VGA_COMPATIBLE; 149 } 150 151 return pGraphicsDevice; 152 } 153 154 NTSTATUS 155 NTAPI 156 InitVideo(VOID) 157 { 158 ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0; 159 WCHAR awcDeviceName[20]; 160 WCHAR awcBuffer[256]; 161 NTSTATUS Status; 162 PGRAPHICS_DEVICE pGraphicsDevice; 163 ULONG cbValue; 164 HKEY hkey; 165 166 TRACE("----------------------------- InitVideo() -------------------------------\n"); 167 168 /* Open the key for the boot command line */ 169 Status = RegOpenKey(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control", &hkey); 170 if (NT_SUCCESS(Status)) 171 { 172 cbValue = 256; 173 Status = RegQueryValue(hkey, L"SystemStartOptions", REG_SZ, awcBuffer, &cbValue); 174 if (NT_SUCCESS(Status)) 175 { 176 /* Check if VGA mode is requested. */ 177 if (wcsstr(awcBuffer, L"BASEVIDEO") != 0) 178 { 179 ERR("VGA mode requested.\n"); 180 gbBaseVideo = TRUE; 181 } 182 } 183 184 ZwClose(hkey); 185 } 186 187 /* Open the key for the adapters */ 188 Status = RegOpenKey(KEY_VIDEO, &hkey); 189 if (!NT_SUCCESS(Status)) 190 { 191 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status); 192 return Status; 193 } 194 195 /* Read the name of the VGA adapter */ 196 cbValue = 20; 197 Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue); 198 if (NT_SUCCESS(Status)) 199 { 200 iVGACompatible = _wtoi(&awcDeviceName[13]); 201 ERR("VGA adapter = %lu\n", iVGACompatible); 202 } 203 204 /* Get the maximum mumber of adapters */ 205 if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber)) 206 { 207 ERR("Could not read MaxObjectNumber, defaulting to 0.\n"); 208 } 209 210 TRACE("Found %lu devices\n", ulMaxObjectNumber + 1); 211 212 /* Loop through all adapters */ 213 for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++) 214 { 215 /* Create the adapter's key name */ 216 swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum); 217 218 /* Read the reg key name */ 219 cbValue = sizeof(awcBuffer); 220 Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue); 221 if (!NT_SUCCESS(Status)) 222 { 223 ERR("failed to query the registry path:0x%lx\n", Status); 224 continue; 225 } 226 227 /* Initialize the driver for this device */ 228 pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer); 229 if (!pGraphicsDevice) continue; 230 231 /* Check if this is a VGA compatible adapter */ 232 if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) 233 { 234 /* Save this as the VGA adapter */ 235 if (!gpVgaGraphicsDevice) 236 gpVgaGraphicsDevice = pGraphicsDevice; 237 TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice); 238 } 239 else 240 { 241 /* Set the first one as primary device */ 242 if (!gpPrimaryGraphicsDevice) 243 gpPrimaryGraphicsDevice = pGraphicsDevice; 244 TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice); 245 } 246 } 247 248 /* Close the device map registry key */ 249 ZwClose(hkey); 250 251 /* Was VGA mode requested? */ 252 if (gbBaseVideo) 253 { 254 /* Check if we found a VGA compatible device */ 255 if (gpVgaGraphicsDevice) 256 { 257 /* Set the VgaAdapter as primary */ 258 gpPrimaryGraphicsDevice = gpVgaGraphicsDevice; 259 // FIXME: DEVMODE 260 } 261 else 262 { 263 ERR("Could not find VGA compatible driver. Trying normal.\n"); 264 } 265 } 266 267 /* Check if we had any success */ 268 if (!gpPrimaryGraphicsDevice) 269 { 270 /* Check if there is a VGA device we skipped */ 271 if (gpVgaGraphicsDevice) 272 { 273 /* There is, use the VGA device */ 274 gpPrimaryGraphicsDevice = gpVgaGraphicsDevice; 275 } 276 else 277 { 278 ERR("No usable display driver was found.\n"); 279 return STATUS_UNSUCCESSFUL; 280 } 281 } 282 283 InitSysParams(); 284 285 return 1; 286 } 287 288 NTSTATUS 289 NTAPI 290 UserEnumDisplayDevices( 291 PUNICODE_STRING pustrDevice, 292 DWORD iDevNum, 293 PDISPLAY_DEVICEW pdispdev, 294 DWORD dwFlags) 295 { 296 PGRAPHICS_DEVICE pGraphicsDevice; 297 ULONG cbSize; 298 HKEY hkey; 299 NTSTATUS Status; 300 301 /* Ask gdi for the GRAPHICS_DEVICE */ 302 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, iDevNum, 0); 303 if (!pGraphicsDevice) 304 { 305 /* No device found */ 306 ERR("No GRAPHICS_DEVICE found\n"); 307 return STATUS_UNSUCCESSFUL; 308 } 309 310 /* Open the device map registry key */ 311 Status = RegOpenKey(KEY_VIDEO, &hkey); 312 if (!NT_SUCCESS(Status)) 313 { 314 /* No device found */ 315 ERR("Could not open reg key\n"); 316 return STATUS_UNSUCCESSFUL; 317 } 318 319 /* Query the registry path */ 320 cbSize = sizeof(pdispdev->DeviceKey); 321 RegQueryValue(hkey, 322 pGraphicsDevice->szNtDeviceName, 323 REG_SZ, 324 pdispdev->DeviceKey, 325 &cbSize); 326 327 /* Close registry key */ 328 ZwClose(hkey); 329 330 /* Copy device name, device string and StateFlags */ 331 RtlStringCbCopyW(pdispdev->DeviceName, sizeof(pdispdev->DeviceName), pGraphicsDevice->szWinDeviceName); 332 RtlStringCbCopyW(pdispdev->DeviceString, sizeof(pdispdev->DeviceString), pGraphicsDevice->pwszDescription); 333 pdispdev->StateFlags = pGraphicsDevice->StateFlags; 334 // FIXME: fill in DEVICE ID 335 pdispdev->DeviceID[0] = UNICODE_NULL; 336 337 return STATUS_SUCCESS; 338 } 339 340 //NTSTATUS 341 BOOL 342 NTAPI 343 NtUserEnumDisplayDevices( 344 PUNICODE_STRING pustrDevice, 345 DWORD iDevNum, 346 PDISPLAY_DEVICEW pDisplayDevice, 347 DWORD dwFlags) 348 { 349 UNICODE_STRING ustrDevice; 350 WCHAR awcDevice[CCHDEVICENAME]; 351 DISPLAY_DEVICEW dispdev; 352 NTSTATUS Status; 353 354 TRACE("Enter NtUserEnumDisplayDevices(%wZ, %lu)\n", 355 pustrDevice, iDevNum); 356 357 dispdev.cb = sizeof(dispdev); 358 359 if (pustrDevice) 360 { 361 /* Initialize destination string */ 362 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice)); 363 364 _SEH2_TRY 365 { 366 /* Probe the UNICODE_STRING and the buffer */ 367 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1); 368 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1); 369 370 /* Copy the string */ 371 RtlCopyUnicodeString(&ustrDevice, pustrDevice); 372 } 373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 374 { 375 // _SEH2_YIELD(return _SEH2_GetExceptionCode()); 376 _SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode())); 377 } 378 _SEH2_END 379 380 if (ustrDevice.Length > 0) 381 pustrDevice = &ustrDevice; 382 else 383 pustrDevice = NULL; 384 } 385 386 /* If name is given only iDevNum==0 gives results */ 387 if (pustrDevice && iDevNum != 0) 388 return FALSE; 389 390 /* Acquire global USER lock */ 391 UserEnterShared(); 392 393 /* Call the internal function */ 394 Status = UserEnumDisplayDevices(pustrDevice, iDevNum, &dispdev, dwFlags); 395 396 /* Release lock */ 397 UserLeave(); 398 399 /* On success copy data to caller */ 400 if (NT_SUCCESS(Status)) 401 { 402 /* Enter SEH */ 403 _SEH2_TRY 404 { 405 /* First probe the cb field */ 406 ProbeForWrite(&pDisplayDevice->cb, sizeof(DWORD), 1); 407 408 /* Check the buffer size */ 409 if (pDisplayDevice->cb) 410 { 411 /* Probe the output buffer */ 412 pDisplayDevice->cb = min(pDisplayDevice->cb, sizeof(dispdev)); 413 ProbeForWrite(pDisplayDevice, pDisplayDevice->cb, 1); 414 415 /* Copy as much as the given buffer allows */ 416 RtlCopyMemory(pDisplayDevice, &dispdev, pDisplayDevice->cb); 417 } 418 } 419 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 420 { 421 Status = _SEH2_GetExceptionCode(); 422 } 423 _SEH2_END 424 } 425 426 TRACE("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status); 427 /* Return the result */ 428 // return Status; 429 return NT_SUCCESS(Status); // FIXME 430 } 431 432 NTSTATUS 433 NTAPI 434 UserEnumCurrentDisplaySettings( 435 PUNICODE_STRING pustrDevice, 436 PDEVMODEW *ppdm) 437 { 438 PPDEVOBJ ppdev; 439 440 /* Get the PDEV for the device */ 441 ppdev = EngpGetPDEV(pustrDevice); 442 if (!ppdev) 443 { 444 /* No device found */ 445 ERR("No PDEV found!\n"); 446 return STATUS_INVALID_PARAMETER_1; 447 } 448 449 *ppdm = ppdev->pdmwDev; 450 PDEVOBJ_vRelease(ppdev); 451 452 return STATUS_SUCCESS; 453 } 454 455 NTSTATUS 456 NTAPI 457 UserEnumDisplaySettings( 458 PUNICODE_STRING pustrDevice, 459 DWORD iModeNum, 460 LPDEVMODEW *ppdm, 461 DWORD dwFlags) 462 { 463 PGRAPHICS_DEVICE pGraphicsDevice; 464 PDEVMODEENTRY pdmentry; 465 ULONG i, iFoundMode; 466 PPDEVOBJ ppdev; 467 468 TRACE("Enter UserEnumDisplaySettings('%wZ', %lu)\n", 469 pustrDevice, iModeNum); 470 471 /* Ask GDI for the GRAPHICS_DEVICE */ 472 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0); 473 ppdev = EngpGetPDEV(pustrDevice); 474 475 if (!pGraphicsDevice || !ppdev) 476 { 477 /* No device found */ 478 ERR("No device found!\n"); 479 return STATUS_INVALID_PARAMETER_1; 480 } 481 482 /* let's politely ask the driver for an updated mode list, 483 just in case there's something new in there (vbox) */ 484 485 PDEVOBJ_vRefreshModeList(ppdev); 486 PDEVOBJ_vRelease(ppdev); 487 488 iFoundMode = 0; 489 for (i = 0; i < pGraphicsDevice->cDevModes; i++) 490 { 491 pdmentry = &pGraphicsDevice->pDevModeList[i]; 492 493 /* FIXME: Consider EDS_RAWMODE */ 494 #if 0 495 if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) ||! 496 (dwFlags & EDS_RAWMODE)) 497 #endif 498 { 499 /* Is this the one we want? */ 500 if (iFoundMode == iModeNum) 501 { 502 *ppdm = pdmentry->pdm; 503 return STATUS_SUCCESS; 504 } 505 506 /* Increment number of found modes */ 507 iFoundMode++; 508 } 509 } 510 511 /* Nothing was found */ 512 return STATUS_INVALID_PARAMETER_2; 513 } 514 515 NTSTATUS 516 NTAPI 517 UserOpenDisplaySettingsKey( 518 OUT PHKEY phkey, 519 IN PUNICODE_STRING pustrDevice, 520 IN BOOL bGlobal) 521 { 522 HKEY hkey; 523 DISPLAY_DEVICEW dispdev; 524 NTSTATUS Status; 525 526 /* Get device info */ 527 Status = UserEnumDisplayDevices(pustrDevice, 0, &dispdev, 0); 528 if (!NT_SUCCESS(Status)) 529 return Status; 530 531 if (bGlobal) 532 { 533 // FIXME: Need to fix the registry key somehow 534 } 535 536 /* Open the registry key */ 537 Status = RegOpenKey(dispdev.DeviceKey, &hkey); 538 if (!NT_SUCCESS(Status)) 539 return Status; 540 541 *phkey = hkey; 542 543 return Status; 544 } 545 546 NTSTATUS 547 NTAPI 548 UserEnumRegistryDisplaySettings( 549 IN PUNICODE_STRING pustrDevice, 550 OUT LPDEVMODEW pdm) 551 { 552 HKEY hkey; 553 NTSTATUS Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, 0); 554 if(NT_SUCCESS(Status)) 555 { 556 RegReadDisplaySettings(hkey, pdm); 557 ZwClose(hkey); 558 return STATUS_SUCCESS; 559 } 560 return Status ; 561 } 562 563 NTSTATUS 564 APIENTRY 565 NtUserEnumDisplaySettings( 566 IN PUNICODE_STRING pustrDevice, 567 IN DWORD iModeNum, 568 OUT LPDEVMODEW lpDevMode, 569 IN DWORD dwFlags) 570 { 571 UNICODE_STRING ustrDevice; 572 WCHAR awcDevice[CCHDEVICENAME]; 573 NTSTATUS Status; 574 ULONG cbSize, cbExtra; 575 DEVMODEW dmReg, *pdm; 576 577 TRACE("Enter NtUserEnumDisplaySettings(%wZ, %lu, %p, 0x%lx)\n", 578 pustrDevice, iModeNum, lpDevMode, dwFlags); 579 580 _SEH2_TRY 581 { 582 ProbeForRead(lpDevMode, sizeof(DEVMODEW), sizeof(UCHAR)); 583 584 cbSize = lpDevMode->dmSize; 585 cbExtra = lpDevMode->dmDriverExtra; 586 587 ProbeForWrite(lpDevMode, cbSize + cbExtra, sizeof(UCHAR)); 588 } 589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 590 { 591 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 592 } 593 _SEH2_END; 594 595 if (lpDevMode->dmSize != sizeof(DEVMODEW)) 596 { 597 return STATUS_BUFFER_TOO_SMALL; 598 } 599 600 if (pustrDevice) 601 { 602 /* Initialize destination string */ 603 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice)); 604 605 _SEH2_TRY 606 { 607 /* Probe the UNICODE_STRING and the buffer */ 608 ProbeForReadUnicodeString(pustrDevice); 609 610 if (!pustrDevice->Length || !pustrDevice->Buffer) 611 ExRaiseStatus(STATUS_NO_MEMORY); 612 613 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, sizeof(UCHAR)); 614 615 /* Copy the string */ 616 RtlCopyUnicodeString(&ustrDevice, pustrDevice); 617 } 618 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 619 { 620 _SEH2_YIELD(return STATUS_INVALID_PARAMETER_1); 621 } 622 _SEH2_END; 623 624 pustrDevice = &ustrDevice; 625 } 626 627 /* Acquire global USER lock */ 628 UserEnterShared(); 629 630 if (iModeNum == ENUM_REGISTRY_SETTINGS) 631 { 632 /* Get the registry settings */ 633 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg); 634 pdm = &dmReg; 635 pdm->dmSize = sizeof(DEVMODEW); 636 } 637 else if (iModeNum == ENUM_CURRENT_SETTINGS) 638 { 639 /* Get the current settings */ 640 Status = UserEnumCurrentDisplaySettings(pustrDevice, &pdm); 641 } 642 else 643 { 644 /* Get specified settings */ 645 Status = UserEnumDisplaySettings(pustrDevice, iModeNum, &pdm, dwFlags); 646 } 647 648 /* Release lock */ 649 UserLeave(); 650 651 /* Did we succeed? */ 652 if (NT_SUCCESS(Status)) 653 { 654 /* Copy some information back */ 655 _SEH2_TRY 656 { 657 /* Output what we got */ 658 RtlCopyMemory(lpDevMode, pdm, min(cbSize, pdm->dmSize)); 659 660 /* Output private/extra driver data */ 661 if (cbExtra > 0 && pdm->dmDriverExtra > 0) 662 { 663 RtlCopyMemory((PCHAR)lpDevMode + cbSize, 664 (PCHAR)pdm + pdm->dmSize, 665 min(cbExtra, pdm->dmDriverExtra)); 666 } 667 } 668 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 669 { 670 Status = _SEH2_GetExceptionCode(); 671 } 672 _SEH2_END; 673 } 674 675 return Status; 676 } 677 VOID 678 UserUpdateFullscreen( 679 DWORD flags) 680 { 681 if (flags & CDS_FULLSCREEN) 682 gpFullscreen = gptiCurrent->ppi; 683 else 684 gpFullscreen = NULL; 685 } 686 687 LONG 688 APIENTRY 689 UserChangeDisplaySettings( 690 PUNICODE_STRING pustrDevice, 691 LPDEVMODEW pdm, 692 DWORD flags, 693 LPVOID lParam) 694 { 695 DEVMODEW dm; 696 LONG lResult = DISP_CHANGE_SUCCESSFUL; 697 HKEY hkey; 698 NTSTATUS Status; 699 PPDEVOBJ ppdev; 700 WORD OrigBC; 701 //PDESKTOP pdesk; 702 703 /* If no DEVMODE is given, use registry settings */ 704 if (!pdm) 705 { 706 /* Get the registry settings */ 707 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dm); 708 if (!NT_SUCCESS(Status)) 709 { 710 ERR("Could not load registry settings\n"); 711 return DISP_CHANGE_BADPARAM; 712 } 713 } 714 else if (pdm->dmSize < FIELD_OFFSET(DEVMODEW, dmFields)) 715 return DISP_CHANGE_BADMODE; /* This is what winXP SP3 returns */ 716 else 717 dm = *pdm; 718 719 /* Save original bit count */ 720 OrigBC = gpsi->BitCount; 721 722 /* Check params */ 723 if ((dm.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT)) 724 { 725 ERR("Devmode doesn't specify the resolution.\n"); 726 return DISP_CHANGE_BADMODE; 727 } 728 729 /* Get the PDEV */ 730 ppdev = EngpGetPDEV(pustrDevice); 731 if (!ppdev) 732 { 733 ERR("Failed to get PDEV\n"); 734 return DISP_CHANGE_BADPARAM; 735 } 736 737 /* Fixup values */ 738 if(dm.dmBitsPerPel == 0 || !(dm.dmFields & DM_BITSPERPEL)) 739 { 740 dm.dmBitsPerPel = ppdev->pdmwDev->dmBitsPerPel; 741 dm.dmFields |= DM_BITSPERPEL; 742 } 743 744 if((dm.dmFields & DM_DISPLAYFREQUENCY) && (dm.dmDisplayFrequency == 0)) 745 dm.dmDisplayFrequency = ppdev->pdmwDev->dmDisplayFrequency; 746 747 /* Look for the requested DEVMODE */ 748 pdm = PDEVOBJ_pdmMatchDevMode(ppdev, &dm); 749 if (!pdm) 750 { 751 ERR("Could not find a matching DEVMODE\n"); 752 lResult = DISP_CHANGE_BADMODE; 753 goto leave; 754 } 755 else if (flags & CDS_TEST) 756 { 757 /* It's possible, go ahead! */ 758 lResult = DISP_CHANGE_SUCCESSFUL; 759 goto leave; 760 } 761 762 /* Shall we update the registry? */ 763 if (flags & CDS_UPDATEREGISTRY) 764 { 765 /* Open the local or global settings key */ 766 Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, flags & CDS_GLOBAL); 767 if (NT_SUCCESS(Status)) 768 { 769 /* Store the settings */ 770 RegWriteDisplaySettings(hkey, pdm); 771 772 /* Close the registry key */ 773 ZwClose(hkey); 774 } 775 else 776 { 777 ERR("Could not open registry key\n"); 778 lResult = DISP_CHANGE_NOTUPDATED; 779 } 780 } 781 782 /* Shall we apply the settings? */ 783 if (!(flags & CDS_NORESET)) 784 { 785 ULONG ulResult; 786 PVOID pvOldCursor; 787 TEXTMETRICW tmw; 788 789 /* Remove mouse pointer */ 790 pvOldCursor = UserSetCursor(NULL, TRUE); 791 792 /* Do the mode switch */ 793 ulResult = PDEVOBJ_bSwitchMode(ppdev, pdm); 794 795 /* Restore mouse pointer, no hooks called */ 796 pvOldCursor = UserSetCursor(pvOldCursor, TRUE); 797 ASSERT(pvOldCursor == NULL); 798 799 /* Check for failure */ 800 if (!ulResult) 801 { 802 ERR("Failed to set mode\n"); 803 lResult = (lResult == DISP_CHANGE_NOTUPDATED) ? 804 DISP_CHANGE_FAILED : DISP_CHANGE_RESTART; 805 806 goto leave; 807 } 808 809 UserUpdateFullscreen(flags); 810 811 /* Update the system metrics */ 812 InitMetrics(); 813 814 /* Set new size of the monitor */ 815 UserUpdateMonitorSize((HDEV)ppdev); 816 817 /* Update the SERVERINFO */ 818 gpsi->dmLogPixels = ppdev->gdiinfo.ulLogPixelsY; 819 gpsi->Planes = ppdev->gdiinfo.cPlanes; 820 gpsi->BitsPixel = ppdev->gdiinfo.cBitsPixel; 821 gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel; 822 if (ppdev->gdiinfo.flRaster & RC_PALETTE) 823 { 824 gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY; 825 } 826 else 827 gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY; 828 // Font is realized and this dc was previously set to internal DC_ATTR. 829 gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar); 830 gpsi->tmSysFont = tmw; 831 832 /* Remove all cursor clipping */ 833 UserClipCursor(NULL); 834 835 //pdesk = IntGetActiveDesktop(); 836 //IntHideDesktop(pdesk); 837 838 /* Send WM_DISPLAYCHANGE to all toplevel windows */ 839 UserSendNotifyMessage( HWND_BROADCAST, 840 WM_DISPLAYCHANGE, 841 gpsi->BitCount, 842 MAKELONG(gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN]) ); 843 844 ERR("BitCount New %d Orig %d ChkNew %d\n",gpsi->BitCount,OrigBC,ppdev->gdiinfo.cBitsPixel); 845 846 /* Not full screen and different bit count, send messages */ 847 if (!(flags & CDS_FULLSCREEN) && 848 gpsi->BitCount != OrigBC ) 849 { 850 ERR("Detect settings changed.\n"); 851 UserSendNotifyMessage( HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0 ); 852 UserSendNotifyMessage( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0 ); 853 } 854 855 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes); 856 857 UserRedrawDesktop(); 858 } 859 860 leave: 861 /* Release the PDEV */ 862 PDEVOBJ_vRelease(ppdev); 863 864 return lResult; 865 } 866 867 VOID 868 UserDisplayNotifyShutdown( 869 PPROCESSINFO ppiCurrent) 870 { 871 if (ppiCurrent == gpFullscreen) 872 { 873 UserChangeDisplaySettings(NULL, NULL, 0, NULL); 874 if (gpFullscreen) 875 ERR("Failed to restore display mode!\n"); 876 } 877 } 878 879 LONG 880 APIENTRY 881 NtUserChangeDisplaySettings( 882 PUNICODE_STRING pustrDevice, 883 LPDEVMODEW lpDevMode, 884 DWORD dwflags, 885 LPVOID lParam) 886 { 887 WCHAR awcDevice[CCHDEVICENAME]; 888 UNICODE_STRING ustrDevice; 889 DEVMODEW dmLocal; 890 LONG lRet; 891 892 /* Check arguments */ 893 if ((dwflags != CDS_VIDEOPARAMETERS) && (lParam != NULL)) 894 { 895 EngSetLastError(ERROR_INVALID_PARAMETER); 896 return DISP_CHANGE_BADPARAM; 897 } 898 899 /* Check flags */ 900 if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY)) 901 { 902 return DISP_CHANGE_BADFLAGS; 903 } 904 905 /* Copy the device name */ 906 if (pustrDevice) 907 { 908 /* Initialize destination string */ 909 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice)); 910 911 _SEH2_TRY 912 { 913 /* Probe the UNICODE_STRING and the buffer */ 914 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1); 915 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1); 916 917 /* Copy the string */ 918 RtlCopyUnicodeString(&ustrDevice, pustrDevice); 919 } 920 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 921 { 922 /* Set and return error */ 923 SetLastNtError(_SEH2_GetExceptionCode()); 924 _SEH2_YIELD(return DISP_CHANGE_BADPARAM); 925 } 926 _SEH2_END 927 928 pustrDevice = &ustrDevice; 929 } 930 931 /* Copy devmode */ 932 if (lpDevMode) 933 { 934 _SEH2_TRY 935 { 936 /* Probe the size field of the structure */ 937 ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1); 938 939 /* Calculate usable size */ 940 dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize); 941 942 /* Probe and copy the full DEVMODE */ 943 ProbeForRead(lpDevMode, dmLocal.dmSize, 1); 944 RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize); 945 } 946 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 947 { 948 /* Set and return error */ 949 SetLastNtError(_SEH2_GetExceptionCode()); 950 _SEH2_YIELD(return DISP_CHANGE_BADPARAM); 951 } 952 _SEH2_END 953 954 /* Check for extra parameters */ 955 if (dmLocal.dmDriverExtra > 0) 956 { 957 /* FIXME: TODO */ 958 ERR("lpDevMode->dmDriverExtra is IGNORED!\n"); 959 dmLocal.dmDriverExtra = 0; 960 } 961 962 /* Use the local structure */ 963 lpDevMode = &dmLocal; 964 } 965 966 // FIXME: Copy videoparameters 967 968 /* Acquire global USER lock */ 969 UserEnterExclusive(); 970 971 /* Call internal function */ 972 lRet = UserChangeDisplaySettings(pustrDevice, lpDevMode, dwflags, NULL); 973 974 /* Release lock */ 975 UserLeave(); 976 977 return lRet; 978 } 979 980