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