[WIN32K]
[reactos.git] / subsystems / win32 / win32k / ntuser / display.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Video initialization and display settings
5 * FILE: subsystems/win32/win32k/ntuser/display.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 #include <w32k.h>
10
11 #include <intrin.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 PDEVOBJ *gpdevPrimary;
17
18 const PWCHAR KEY_ROOT = L"";
19 const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
20
21 NTSTATUS
22 NTAPI
23 UserEnumDisplayDevices(
24 PUNICODE_STRING pustrDevice,
25 DWORD iDevNum,
26 PDISPLAY_DEVICEW pdispdev,
27 DWORD dwFlags);
28
29 VOID
30 RegWriteSZ(HKEY hkey, PWSTR pwszValue, PWSTR pwszData)
31 {
32 UNICODE_STRING ustrValue;
33 UNICODE_STRING ustrData;
34
35 RtlInitUnicodeString(&ustrValue, pwszValue);
36 RtlInitUnicodeString(&ustrData, pwszData);
37 ZwSetValueKey(hkey, &ustrValue, 0, REG_SZ, &ustrData, ustrData.Length + sizeof(WCHAR));
38 }
39
40 VOID
41 RegWriteDWORD(HKEY hkey, PWSTR pwszValue, DWORD dwData)
42 {
43 UNICODE_STRING ustrValue;
44
45 RtlInitUnicodeString(&ustrValue, pwszValue);
46 ZwSetValueKey(hkey, &ustrValue, 0, REG_DWORD, &dwData, sizeof(DWORD));
47 }
48
49
50 BOOL
51 RegReadDWORD(HKEY hkey, PWSTR pwszValue, PDWORD pdwData)
52 {
53 NTSTATUS Status;
54 ULONG cbSize = sizeof(DWORD);
55 Status = RegQueryValue(hkey, pwszValue, REG_DWORD, pdwData, &cbSize);
56 return NT_SUCCESS(Status);
57 }
58
59 VOID
60 RegWriteDisplaySettings(HKEY hkey, PDEVMODEW pdm)
61 {
62 RegWriteDWORD(hkey, L"DefaultSettings.BitsPerPel", pdm->dmBitsPerPel);
63 RegWriteDWORD(hkey, L"DefaultSettings.XResolution", pdm->dmPelsWidth);
64 RegWriteDWORD(hkey, L"DefaultSettings.YResolution", pdm->dmPelsHeight);
65 RegWriteDWORD(hkey, L"DefaultSettings.Flags", pdm->dmDisplayFlags);
66 RegWriteDWORD(hkey, L"DefaultSettings.VRefresh", pdm->dmDisplayFrequency);
67 RegWriteDWORD(hkey, L"DefaultSettings.XPanning", pdm->dmPanningWidth);
68 RegWriteDWORD(hkey, L"DefaultSettings.YPanning", pdm->dmPanningHeight);
69 RegWriteDWORD(hkey, L"DefaultSettings.Orientation", pdm->dmDisplayOrientation);
70 RegWriteDWORD(hkey, L"DefaultSettings.FixedOutput", pdm->dmDisplayFixedOutput);
71 RegWriteDWORD(hkey, L"Attach.RelativeX", pdm->dmPosition.x);
72 RegWriteDWORD(hkey, L"Attach.RelativeY", pdm->dmPosition.y);
73 // RegWriteDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", pdm->);
74 }
75
76 VOID
77 RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm)
78 {
79 DWORD dwValue;
80
81 RtlZeroMemory(pdm, sizeof(DEVMODEW));
82
83 if (RegReadDWORD(hkey, L"DefaultSettings.BitsPerPel", &dwValue))
84 {
85 pdm->dmBitsPerPel = dwValue;
86 pdm->dmFields |= DM_BITSPERPEL;
87 }
88 if (RegReadDWORD(hkey, L"DefaultSettings.XResolution", &dwValue))
89 {
90 pdm->dmPelsWidth = dwValue;
91 // pdm->dmFields |= DM_XRESOLUTION;
92 }
93 if (RegReadDWORD(hkey, L"DefaultSettings.YResolution", &dwValue))
94 {
95 pdm->dmPelsHeight = dwValue;
96 pdm->dmFields |= DM_YRESOLUTION;
97 }
98 if (RegReadDWORD(hkey, L"DefaultSettings.Flags", &dwValue))
99 {
100 pdm->dmDisplayFlags = dwValue;
101 pdm->dmFields |= DM_BITSPERPEL;
102 }
103 if (RegReadDWORD(hkey, L"DefaultSettings.VRefresh", &dwValue))
104 {
105 pdm->dmDisplayFrequency = dwValue;
106 pdm->dmFields |= DM_DISPLAYFREQUENCY;
107 }
108 if (RegReadDWORD(hkey, L"DefaultSettings.XPanning", &dwValue))
109 {
110 pdm->dmPanningWidth = dwValue;
111 pdm->dmFields |= DM_PANNINGWIDTH;
112 }
113 if (RegReadDWORD(hkey, L"DefaultSettings.YPanning", &dwValue))
114 {
115 pdm->dmPanningHeight = dwValue;
116 pdm->dmFields |= DM_PANNINGHEIGHT;
117 }
118 if (RegReadDWORD(hkey, L"DefaultSettings.Orientation", &dwValue))
119 {
120 pdm->dmDisplayOrientation = dwValue;
121 pdm->dmFields |= DM_DISPLAYORIENTATION;
122 }
123 if (RegReadDWORD(hkey, L"DefaultSettings.FixedOutput", &dwValue))
124 {
125 pdm->dmDisplayFixedOutput = dwValue;
126 pdm->dmFields |= DM_BITSPERPEL;
127 }
128 if (RegReadDWORD(hkey, L"Attach.RelativeX", &dwValue))
129 {
130 pdm->dmPosition.x = dwValue;
131 pdm->dmFields |= DM_POSITION;
132 }
133 if (RegReadDWORD(hkey, L"Attach.RelativeY", &dwValue))
134 {
135 pdm->dmPosition.y = dwValue;
136 pdm->dmFields |= DM_POSITION;
137 }
138 // RegReadDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", &pdm->);
139
140 }
141
142
143
144
145 enum
146 {
147 VF_USEVGA = 0x1,
148 };
149
150 BOOL
151 InitDisplayDriver(
152 PUNICODE_STRING pustrRegPath,
153 FLONG flags)
154 {
155 // PWSTR pwszDriverName;
156 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
157 NTSTATUS Status;
158
159 /* Setup QueryTable for direct registry query */
160 RtlZeroMemory(QueryTable, sizeof(QueryTable));
161 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED|RTL_QUERY_REGISTRY_DIRECT;
162
163
164 /* Check if vga mode is requested */
165 if (flags & VF_USEVGA)
166 {
167 DWORD dwVgaCompatible;
168
169 /* */
170 QueryTable[0].Name = L"VgaCompatible";
171 QueryTable[0].EntryContext = &dwVgaCompatible;
172
173 /* Check if the driver is vga */
174 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
175 pustrRegPath->Buffer,
176 QueryTable,
177 NULL,
178 NULL);
179
180 if (!dwVgaCompatible)
181 {
182 /* This driver is not a vga driver */
183 return FALSE;
184 }
185 }
186
187 #if 0
188
189 /* Query the adapter's registry path */
190 swprintf(awcBuffer, L"\\Device\\Video%lu", iDevNum);
191 QueryTable[0].Name = pGraphicsDevice->szNtDeviceName;
192
193 /* Set string for the registry key */
194 ustrRegistryPath.Buffer = pdispdev->DeviceKey;
195 ustrRegistryPath.Length = 128;
196 ustrRegistryPath.MaximumLength = 128;
197 QueryTable[0].EntryContext = &ustrRegistryPath;
198
199 /* Query the registry */
200 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
201 L"VIDEO",
202 QueryTable,
203 NULL,
204 NULL);
205
206 RegQueryValue(KEY_VIDEO, awcBuffer, REG_SZ, pdispdev->DeviceKey, 256);
207
208 {
209 HANDLE hmod;
210
211 hmod = EngLoadImage(pwszDriverName);
212
213 /* Jump to next name */
214 pwszDriverName += wcslen(pwszDriverName) + 1;
215 }
216 while (pwszDriverName < 0);
217 #endif
218
219 return 0;
220 }
221
222
223 NTSTATUS
224 NTAPI
225 DisplayDriverQueryRoutine(
226 IN PWSTR ValueName,
227 IN ULONG ValueType,
228 IN PVOID ValueData,
229 IN ULONG ValueLength,
230 IN PVOID Context,
231 IN PVOID EntryContext)
232 {
233 PWSTR pwszRegKey = ValueData;
234 PGRAPHICS_DEVICE pGraphicsDevice;
235 UNICODE_STRING ustrDeviceName, ustrDisplayDrivers, ustrDescription;
236 NTSTATUS Status;
237 WCHAR awcBuffer[128];
238 ULONG cbSize;
239 HKEY hkey;
240 DEVMODEW dmDefault;
241
242 UNREFERENCED_PARAMETER(ValueLength);
243 UNREFERENCED_PARAMETER(Context);
244 UNREFERENCED_PARAMETER(EntryContext);
245
246 DPRINT1("DisplayDriverQueryRoutine(%S, %S);\n",
247 ValueName, pwszRegKey);
248
249 /* Check if we have a correct entry */
250 if (ValueType != REG_SZ || ValueName[0] != '\\')
251 {
252 /* Something else, just skip it */
253 return STATUS_SUCCESS;
254 }
255
256 /* Open the driver's registry key */
257 Status = RegOpenKey(pwszRegKey, &hkey);
258 if (!NT_SUCCESS(Status))
259 {
260 DPRINT1("Failed to open registry key\n");
261 return STATUS_SUCCESS;
262 }
263
264 // HACK: only use 1st adapter
265 //if (ValueName[13] != '0')
266 // return STATUS_SUCCESS;
267
268 /* Query the diplay drivers */
269 cbSize = sizeof(awcBuffer) - 10;
270 Status = RegQueryValue(hkey,
271 L"InstalledDisplayDrivers",
272 REG_MULTI_SZ,
273 awcBuffer,
274 &cbSize);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT1("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status);
278 ZwClose(hkey);
279 return STATUS_SUCCESS;
280 }
281
282 /* Initialize the UNICODE_STRING */
283 ustrDisplayDrivers.Buffer = awcBuffer;
284 ustrDisplayDrivers.MaximumLength = cbSize;
285 ustrDisplayDrivers.Length = cbSize;
286
287 /* Set Buffer for description and size of remaining buffer */
288 ustrDescription.Buffer = awcBuffer + (cbSize / sizeof(WCHAR));
289 cbSize = sizeof(awcBuffer) - cbSize;
290
291 /* Query the device string */
292 Status = RegQueryValue(hkey,
293 L"Device Description",
294 REG_SZ,
295 ustrDescription.Buffer,
296 &cbSize);
297 if (NT_SUCCESS(Status))
298 {
299 ustrDescription.MaximumLength = cbSize;
300 ustrDescription.Length = cbSize;
301 }
302 else
303 {
304 RtlInitUnicodeString(&ustrDescription, L"<unknown>");
305 }
306
307 /* Query the default settings */
308 RegReadDisplaySettings(hkey, &dmDefault);
309
310 /* Close the registry key */
311 ZwClose(hkey);
312
313 /* Register the device with GDI */
314 RtlInitUnicodeString(&ustrDeviceName, ValueName);
315 pGraphicsDevice = EngpRegisterGraphicsDevice(&ustrDeviceName,
316 &ustrDisplayDrivers,
317 &ustrDescription,
318 &dmDefault);
319
320 // FIXME: what to do with pGraphicsDevice?
321
322 return STATUS_SUCCESS;
323 }
324
325 BOOL InitSysParams();
326
327 BOOL
328 InitVideo(FLONG flags)
329 {
330 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
331 NTSTATUS Status;
332
333 DPRINT1("----------------------------- InitVideo() -------------------------------\n");
334
335 /* Setup QueryTable for registry query */
336 RtlZeroMemory(QueryTable, sizeof(QueryTable));
337 QueryTable[0].QueryRoutine = DisplayDriverQueryRoutine;
338
339 /* Query the registry */
340 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
341 L"VIDEO",
342 QueryTable,
343 NULL,
344 NULL);
345
346 InitSysParams();
347
348 return 0;
349 }
350
351
352 NTSTATUS
353 NTAPI
354 UserEnumDisplayDevices(
355 PUNICODE_STRING pustrDevice,
356 DWORD iDevNum,
357 PDISPLAY_DEVICEW pdispdev,
358 DWORD dwFlags)
359 {
360 PGRAPHICS_DEVICE pGraphicsDevice;
361 ULONG cbSize;
362 HKEY hkey;
363 NTSTATUS Status;
364
365 /* Ask gdi for the GRAPHICS_DEVICE */
366 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, iDevNum, 0);
367 if (!pGraphicsDevice)
368 {
369 /* No device found */
370 DPRINT1("No GRAPHICS_DEVICE found\n");
371 return STATUS_UNSUCCESSFUL;
372 }
373
374 /* Open thhe device map registry key */
375 Status = RegOpenKey(KEY_VIDEO, &hkey);
376 if (!NT_SUCCESS(Status))
377 {
378 /* No device found */
379 DPRINT1("Could not open reg key\n");
380 return STATUS_UNSUCCESSFUL;
381 }
382
383 /* Query the registry path */
384 cbSize = sizeof(pdispdev->DeviceKey);
385 RegQueryValue(hkey,
386 pGraphicsDevice->szNtDeviceName,
387 REG_SZ,
388 pdispdev->DeviceKey,
389 &cbSize);
390
391 /* Close registry key */
392 ZwClose(hkey);
393
394 /* Copy device name, device string and StateFlags */
395 wcsncpy(pdispdev->DeviceName, pGraphicsDevice->szWinDeviceName, 32);
396 wcsncpy(pdispdev->DeviceString, pGraphicsDevice->pwszDescription, 128);
397 pdispdev->StateFlags = pGraphicsDevice->StateFlags;
398
399 // FIXME: fill in DEVICE ID
400
401 return STATUS_SUCCESS;
402 }
403
404 //NTSTATUS
405 BOOL
406 NTAPI
407 NtUserEnumDisplayDevices(
408 PUNICODE_STRING pustrDevice,
409 DWORD iDevNum,
410 PDISPLAY_DEVICEW pDisplayDevice,
411 DWORD dwFlags)
412 {
413 UNICODE_STRING ustrDevice;
414 WCHAR awcDevice[CCHDEVICENAME];
415 DISPLAY_DEVICEW dispdev;
416 NTSTATUS Status;
417
418 DPRINT1("Enter NtUserEnumDisplayDevices(%p, %ls, %ld)\n",
419 pustrDevice, pustrDevice ? pustrDevice->Buffer : 0, iDevNum);
420
421 // FIXME: HACK, desk.cpl passes broken crap
422 if (pustrDevice && iDevNum != 0)
423 return FALSE;
424
425 dispdev.cb = sizeof(DISPLAY_DEVICEW);
426
427 if (pustrDevice)
428 {
429 /* Initialize destination string */
430 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
431
432 _SEH2_TRY
433 {
434 /* Probe the UNICODE_STRING and the buffer */
435 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
436 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
437
438 /* Copy the string */
439 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
440 }
441 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
442 {
443 // _SEH2_YIELD(return _SEH2_GetExceptionCode());
444 _SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode()));
445 }
446 _SEH2_END
447
448 if (ustrDevice.Length > 0)
449 pustrDevice = &ustrDevice;
450 else
451 pustrDevice = NULL;
452 }
453
454 /* Acquire global USER lock */
455 UserEnterExclusive();
456
457 /* Call the internal function */
458 Status = UserEnumDisplayDevices(pustrDevice, iDevNum, &dispdev, dwFlags);
459
460 /* Release lock */
461 UserLeave();
462
463 /* On success copy data to caller */
464 if (NT_SUCCESS(Status))
465 {
466 /* Enter SEH */
467 _SEH2_TRY
468 {
469 /* First probe the cb field */
470 ProbeForWrite(&pDisplayDevice->cb, sizeof(DWORD), 1);
471
472 /* Check the buffer size */
473 if (pDisplayDevice->cb)
474 {
475 /* Probe the output buffer */
476 pDisplayDevice->cb = min(pDisplayDevice->cb, sizeof(dispdev));
477 ProbeForWrite(pDisplayDevice, pDisplayDevice->cb, 1);
478
479 /* Copy as much as the given buffer allows */
480 RtlCopyMemory(pDisplayDevice, &dispdev, pDisplayDevice->cb);
481 }
482 }
483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
484 {
485 Status = _SEH2_GetExceptionCode();
486 }
487 _SEH2_END
488 }
489
490 DPRINT1("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status);
491 /* Return the result */
492 // return Status;
493 return NT_SUCCESS(Status); // FIXME
494 }
495
496 NTSTATUS
497 NTAPI
498 UserEnumCurrentDisplaySettings(
499 PUNICODE_STRING pustrDevice,
500 PDEVMODEW *ppdm)
501 {
502 PPDEVOBJ ppdev;
503
504 /* Get the PDEV for the device */
505 ppdev = EngpGetPDEV(pustrDevice);
506 if (!ppdev)
507 {
508 /* No device found */
509 DPRINT1("No PDEV found!\n");
510 return STATUS_UNSUCCESSFUL;
511 }
512
513 *ppdm = ppdev->pdmwDev;
514 PDEVOBJ_vRelease(ppdev);
515
516 return STATUS_SUCCESS;
517 }
518
519 NTSTATUS
520 NTAPI
521 UserEnumDisplaySettings(
522 PUNICODE_STRING pustrDevice,
523 DWORD iModeNum,
524 LPDEVMODEW *ppdm,
525 DWORD dwFlags)
526 {
527 PGRAPHICS_DEVICE pGraphicsDevice;
528 PDEVMODEENTRY pdmentry;
529 ULONG i, iFoundMode;
530
531 DPRINT1("Enter UserEnumDisplaySettings('%ls', %ld)\n",
532 pustrDevice ? pustrDevice->Buffer : NULL, iModeNum);
533
534 /* Ask gdi for the GRAPHICS_DEVICE */
535 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0);
536 if (!pGraphicsDevice)
537 {
538 /* No device found */
539 DPRINT1("No device found!\n");
540 return FALSE;
541 }
542
543 if (iModeNum == 0)
544 {
545 DPRINT1("Should initialize modes somehow\n");
546 // Update DISPLAY_DEVICEs?
547 }
548
549 iFoundMode = 0;
550 for (i = 0; i < pGraphicsDevice->cDevModes; i++)
551 {
552 pdmentry = &pGraphicsDevice->pDevModeList[i];
553
554 // if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) || // FIXME!
555 // (dwFlags & EDS_RAWMODE))
556 {
557 /* Is this the one we want? */
558 if (iFoundMode == iModeNum)
559 {
560 *ppdm = pdmentry->pdm;
561 return STATUS_SUCCESS;
562 }
563
564 /* Increment number of found modes */
565 iFoundMode++;
566 }
567 }
568
569 /* Nothing was found */
570 return STATUS_INVALID_PARAMETER;
571 }
572
573 NTSTATUS
574 NTAPI
575 UserOpenDisplaySettingsKey(
576 OUT PHKEY phkey,
577 IN PUNICODE_STRING pustrDevice,
578 IN BOOL bGlobal)
579 {
580 HKEY hkey;
581 DISPLAY_DEVICEW dispdev;
582 NTSTATUS Status;
583
584 /* Get device info */
585 Status = UserEnumDisplayDevices(pustrDevice, 0, &dispdev, 0);
586 if (!NT_SUCCESS(Status))
587 return Status;
588
589 if (bGlobal)
590 {
591 // FIXME: need to fix the registry key somehow
592 }
593
594 /* Open the registry key */
595 Status = RegOpenKey(dispdev.DeviceKey, &hkey);
596 if (!NT_SUCCESS(Status))
597 return Status;
598
599 *phkey = hkey;
600
601 return Status;
602 }
603
604 NTSTATUS
605 NTAPI
606 UserEnumRegistryDisplaySettings(
607 IN PUNICODE_STRING pustrDevice,
608 OUT LPDEVMODEW pdm)
609 {
610 UNIMPLEMENTED;
611 return STATUS_NOT_IMPLEMENTED;
612 }
613
614
615 NTSTATUS
616 APIENTRY
617 NtUserEnumDisplaySettings(
618 IN PUNICODE_STRING pustrDevice,
619 IN DWORD iModeNum,
620 OUT LPDEVMODEW lpDevMode,
621 IN DWORD dwFlags)
622 {
623 UNICODE_STRING ustrDevice;
624 WCHAR awcDevice[CCHDEVICENAME];
625 NTSTATUS Status;
626 ULONG cbSize, cbExtra;
627 DEVMODEW dmReg, *pdm;
628
629 DPRINT1("Enter NtUserEnumDisplaySettings(%ls, %ld)\n",
630 pustrDevice ? pustrDevice->Buffer:0, iModeNum);
631
632 if (pustrDevice)
633 {
634 /* Initialize destination string */
635 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
636
637 _SEH2_TRY
638 {
639 /* Probe the UNICODE_STRING and the buffer */
640 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
641 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
642
643 /* Copy the string */
644 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
645 }
646 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
647 {
648 _SEH2_YIELD(return _SEH2_GetExceptionCode());
649 }
650 _SEH2_END
651
652 pustrDevice = &ustrDevice;
653 }
654
655 /* Acquire global USER lock */
656 UserEnterExclusive();
657
658 if (iModeNum == ENUM_REGISTRY_SETTINGS)
659 {
660 /* Get the registry settings */
661 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
662 pdm = &dmReg;
663 }
664 else if (iModeNum == ENUM_CURRENT_SETTINGS)
665 {
666 /* Get the current settings */
667 Status = UserEnumCurrentDisplaySettings(pustrDevice, &pdm);
668 }
669 else
670 {
671 /* Get specified settings */
672 Status = UserEnumDisplaySettings(pustrDevice, iModeNum, &pdm, dwFlags);
673 }
674
675 /* Release lock */
676 UserLeave();
677
678 /* Did we succeed? */
679 if (NT_SUCCESS(Status))
680 {
681 /* Copy some information back */
682 _SEH2_TRY
683 {
684 ProbeForRead(lpDevMode, sizeof(DEVMODEW), 1);
685 cbSize = lpDevMode->dmSize;
686 cbExtra = lpDevMode->dmDriverExtra;
687
688 ProbeForWrite(lpDevMode, cbSize + cbExtra, 1);
689 lpDevMode->dmPelsWidth = pdm->dmPelsWidth;
690 lpDevMode->dmPelsHeight = pdm->dmPelsHeight;
691 lpDevMode->dmBitsPerPel = pdm->dmBitsPerPel;
692 lpDevMode->dmDisplayFrequency = pdm->dmDisplayFrequency;
693 lpDevMode->dmDisplayFlags = pdm->dmDisplayFlags;
694
695 /* output private/extra driver data */
696 if (cbExtra > 0 && pdm->dmDriverExtra > 0)
697 {
698 RtlCopyMemory((PCHAR)lpDevMode + cbSize,
699 (PCHAR)pdm + pdm->dmSize,
700 min(cbExtra, pdm->dmDriverExtra));
701 }
702 }
703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
704 {
705 Status = _SEH2_GetExceptionCode();
706 }
707 _SEH2_END;
708 }
709
710 return Status;
711 }
712
713 BOOL APIENTRY UserClipCursor(RECTL *prcl);
714 VOID APIENTRY UserRedrawDesktop();
715
716 LONG
717 APIENTRY
718 UserChangeDisplaySettings(
719 PUNICODE_STRING pustrDevice,
720 LPDEVMODEW pdm,
721 HWND hwnd,
722 DWORD flags,
723 LPVOID lParam)
724 {
725 DEVMODEW dmReg;
726 LONG lResult = DISP_CHANGE_SUCCESSFUL;
727 HKEY hkey;
728 NTSTATUS Status;
729 PPDEVOBJ ppdev;
730 PDESKTOP pdesk;
731
732 /* If no DEVMODE is given, use registry settings */
733 if (!pdm)
734 {
735 /* Get the registry settings */
736 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
737 if (!NT_SUCCESS(Status))
738 {
739 DPRINT1("Could not load registry settings\n");
740 return DISP_CHANGE_BADPARAM;
741 }
742 pdm = &dmReg;
743 }
744
745 /* Get the PDEV */
746 ppdev = EngpGetPDEV(pustrDevice);
747 if (!ppdev)
748 {
749 DPRINT1("failed to get PDEV\n");
750 return DISP_CHANGE_BADPARAM;
751 }
752
753 /* Look for the requested DEVMODE */
754 pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
755 if (!pdm)
756 {
757 DPRINT1("Could not find a matching DEVMODE\n");
758 lResult = DISP_CHANGE_BADMODE;
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 DPRINT1("Could not open registry key\n");
778 lResult = DISP_CHANGE_NOTUPDATED;
779 }
780 }
781
782 /* Check if DEVMODE matches the current mode */
783 if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
784 {
785 DPRINT1("DEVMODE matches, nothing to do\n");
786 goto leave;
787 }
788
789 /* Shall we apply the settings? */
790 if (!(flags & CDS_NORESET))
791 {
792 if (!PDEVOBJ_bSwitchMode(ppdev, pdm))
793 {
794 DPRINT1("failed to set mode\n");
795 lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
796 DISP_CHANGE_FAILED : DISP_CHANGE_RESTART;
797 }
798
799 /* Update the system metrics */
800 InitMetrics();
801
802 /* Remove all cursor clipping */
803 UserClipCursor(NULL);
804
805 pdesk = IntGetActiveDesktop();
806 IntHideDesktop(pdesk);
807 co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
808 //UserRedrawDesktop();
809
810 //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
811
812 /* Send message */
813
814 }
815
816 leave:
817 PDEVOBJ_vRelease(ppdev);
818
819 return lResult;
820 }
821
822 LONG
823 APIENTRY
824 NtUserChangeDisplaySettings(
825 PUNICODE_STRING pustrDevice,
826 LPDEVMODEW lpDevMode,
827 HWND hwnd,
828 DWORD dwflags,
829 LPVOID lParam)
830 {
831 WCHAR awcDevice[CCHDEVICENAME];
832 UNICODE_STRING ustrDevice;
833 DEVMODEW dmLocal;
834 LONG Ret;
835
836 /* Check arguments */
837 if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
838 (hwnd != NULL))
839 {
840 SetLastWin32Error(ERROR_INVALID_PARAMETER);
841 return DISP_CHANGE_BADPARAM;
842 }
843
844 /* Check flags */
845 if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY))
846 {
847 return DISP_CHANGE_BADFLAGS;
848 }
849
850 /* Copy the device name */
851 if (pustrDevice)
852 {
853 /* Initialize destination string */
854 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
855
856 _SEH2_TRY
857 {
858 /* Probe the UNICODE_STRING and the buffer */
859 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
860 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
861
862 /* Copy the string */
863 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
864 }
865 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
866 {
867 SetLastNtError(_SEH2_GetExceptionCode());
868 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
869 }
870 _SEH2_END
871
872 pustrDevice = &ustrDevice;
873 }
874
875 /* Copy devmode */
876 if (lpDevMode)
877 {
878 _SEH2_TRY
879 {
880 ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1);
881 dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize);
882 ProbeForRead(lpDevMode, dmLocal.dmSize, 1);
883 RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize);
884 dmLocal.dmSize = sizeof(dmLocal);
885 }
886 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
887 {
888 SetLastNtError(_SEH2_GetExceptionCode());
889 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
890 }
891 _SEH2_END
892
893 if (dmLocal.dmDriverExtra > 0)
894 {
895 DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
896 dmLocal.dmDriverExtra = 0;
897 }
898 lpDevMode = &dmLocal;
899 }
900
901 // FIXME: Copy videoparameters
902 UserEnterExclusive();
903
904 /* Call internal function */
905 Ret = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
906
907 UserLeave();
908
909 return Ret;
910 }
911