[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
714 LONG
715 APIENTRY
716 UserChangeDisplaySettings(
717 PUNICODE_STRING pustrDevice,
718 LPDEVMODEW pdm,
719 HWND hwnd,
720 DWORD flags,
721 LPVOID lParam)
722 {
723 DEVMODEW dmReg;
724 LONG lResult = DISP_CHANGE_SUCCESSFUL;
725 HKEY hkey;
726 NTSTATUS Status;
727 PPDEVOBJ ppdev;
728
729 /* If no DEVMODE is given, use registry settings */
730 if (!pdm)
731 {
732 /* Get the registry settings */
733 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
734 if (!NT_SUCCESS(Status))
735 {
736 DPRINT1("Could not load registry settings\n");
737 return DISP_CHANGE_BADPARAM;
738 }
739 pdm = &dmReg;
740 }
741
742 /* Get the PDEV */
743 ppdev = EngpGetPDEV(pustrDevice);
744 if (!ppdev)
745 {
746 DPRINT1("failed to get PDEV\n");
747 return DISP_CHANGE_BADPARAM;
748 }
749
750 /* Look for the requested DEVMODE */
751 pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
752 if (!pdm)
753 {
754 DPRINT1("Could not find a matching DEVMODE\n");
755 lResult = DISP_CHANGE_BADMODE;
756 goto leave;
757 }
758
759 /* Shall we update the registry? */
760 if (flags & CDS_UPDATEREGISTRY)
761 {
762 /* Open the local or global settings key */
763 Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, flags & CDS_GLOBAL);
764 if (NT_SUCCESS(Status))
765 {
766 /* Store the settings */
767 RegWriteDisplaySettings(hkey, pdm);
768
769 /* Close the registry key */
770 ZwClose(hkey);
771 }
772 else
773 {
774 DPRINT1("Could not open registry key\n");
775 lResult = DISP_CHANGE_NOTUPDATED;
776 }
777 }
778
779 /* Check if DEVMODE matches the current mode */
780 if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
781 {
782 DPRINT1("DEVMODE matches, nothing to do\n");
783 goto leave;
784 }
785
786 /* Shall we apply the settings? */
787 if (!(flags & CDS_NORESET))
788 {
789 if (!PDEVOBJ_bSwitchMode(ppdev, pdm))
790 {
791 DPRINT1("failed to set mode\n");
792 lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
793 DISP_CHANGE_FAILED : DISP_CHANGE_RESTART;
794 }
795
796 /* Send message */
797
798 }
799
800 leave:
801 PDEVOBJ_vRelease(ppdev);
802
803 return lResult;
804 }
805
806 LONG
807 APIENTRY
808 NtUserChangeDisplaySettings(
809 PUNICODE_STRING pustrDevice,
810 LPDEVMODEW lpDevMode,
811 HWND hwnd,
812 DWORD dwflags,
813 LPVOID lParam)
814 {
815 WCHAR awcDevice[CCHDEVICENAME];
816 UNICODE_STRING ustrDevice;
817 DEVMODEW dmLocal;
818 LONG Ret;
819
820 /* Check arguments */
821 if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
822 (hwnd != NULL))
823 {
824 SetLastWin32Error(ERROR_INVALID_PARAMETER);
825 return DISP_CHANGE_BADPARAM;
826 }
827
828 /* Check flags */
829 if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY))
830 {
831 return DISP_CHANGE_BADFLAGS;
832 }
833
834 /* Copy the device name */
835 if (pustrDevice)
836 {
837 /* Initialize destination string */
838 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
839
840 _SEH2_TRY
841 {
842 /* Probe the UNICODE_STRING and the buffer */
843 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
844 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
845
846 /* Copy the string */
847 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
848 }
849 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
850 {
851 SetLastNtError(_SEH2_GetExceptionCode());
852 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
853 }
854 _SEH2_END
855
856 pustrDevice = &ustrDevice;
857 }
858
859 /* Copy devmode */
860 if (lpDevMode)
861 {
862 _SEH2_TRY
863 {
864 ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1);
865 dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize);
866 ProbeForRead(lpDevMode, dmLocal.dmSize, 1);
867 RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize);
868 dmLocal.dmSize = sizeof(dmLocal);
869 }
870 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
871 {
872 SetLastNtError(_SEH2_GetExceptionCode());
873 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
874 }
875 _SEH2_END
876
877 if (dmLocal.dmDriverExtra > 0)
878 {
879 DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
880 dmLocal.dmDriverExtra = 0;
881 }
882 lpDevMode = &dmLocal;
883 }
884
885 // FIXME: Copy videoparameters
886
887 /* Call internal function */
888 Ret = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
889
890 return Ret;
891 }
892