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
RegWriteDisplaySettings(HKEY hkey,PDEVMODEW pdm)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
RegReadDisplaySettings(HKEY hkey,PDEVMODEW pdm)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
InitDisplayDriver(IN PWSTR pwszDeviceName,IN PWSTR pwszRegKey)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
InitVideo(VOID)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
UserRefreshDisplay(IN PPDEVOBJ ppdev)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
UserEnumDisplayDevices(PUNICODE_STRING pustrDevice,DWORD iDevNum,PDISPLAY_DEVICEW pdispdev,DWORD dwFlags)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
NtUserEnumDisplayDevices(PUNICODE_STRING pustrDevice,DWORD iDevNum,PDISPLAY_DEVICEW pDisplayDevice,DWORD dwFlags)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
UserEnumCurrentDisplaySettings(PUNICODE_STRING pustrDevice,PDEVMODEW * ppdm)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
UserEnumDisplaySettings(PUNICODE_STRING pustrDevice,DWORD iModeNum,LPDEVMODEW * ppdm,DWORD dwFlags)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
UserOpenDisplaySettingsKey(OUT PHKEY phkey,IN PUNICODE_STRING pustrDevice,IN BOOL bGlobal)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
UserEnumRegistryDisplaySettings(IN PUNICODE_STRING pustrDevice,OUT LPDEVMODEW pdm)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
NtUserEnumDisplaySettings(IN PUNICODE_STRING pustrDevice,IN DWORD iModeNum,OUT LPDEVMODEW lpDevMode,IN DWORD dwFlags)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
UserUpdateFullscreen(DWORD flags)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
UserChangeDisplaySettings(PUNICODE_STRING pustrDevice,LPDEVMODEW pdm,DWORD flags,LPVOID lParam)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
UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent)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
NtUserChangeDisplaySettings(PUNICODE_STRING pustrDevice,LPDEVMODEW lpDevMode,DWORD dwflags,LPVOID lParam)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