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