sync with trunk (r46275)
[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
515 return STATUS_SUCCESS;
516 }
517
518 NTSTATUS
519 NTAPI
520 UserEnumDisplaySettings(
521 PUNICODE_STRING pustrDevice,
522 DWORD iModeNum,
523 LPDEVMODEW *ppdm,
524 DWORD dwFlags)
525 {
526 PGRAPHICS_DEVICE pGraphicsDevice;
527 PDEVMODEENTRY pdmentry;
528 ULONG i, iFoundMode;
529
530 DPRINT1("Enter UserEnumDisplaySettings('%ls', %ld)\n",
531 pustrDevice ? pustrDevice->Buffer : NULL, iModeNum);
532
533 /* Ask gdi for the GRAPHICS_DEVICE */
534 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0);
535 if (!pGraphicsDevice)
536 {
537 /* No device found */
538 DPRINT1("No device found!\n");
539 return FALSE;
540 }
541
542 if (iModeNum == 0)
543 {
544 DPRINT1("Should initialize modes somehow\n");
545 // Update DISPLAY_DEVICEs?
546 }
547
548 iFoundMode = 0;
549 for (i = 0; i < pGraphicsDevice->cDevModes; i++)
550 {
551 pdmentry = &pGraphicsDevice->pDevModeList[i];
552
553 // if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) || // FIXME!
554 // (dwFlags & EDS_RAWMODE))
555 {
556 /* Is this the one we want? */
557 if (iFoundMode == iModeNum)
558 {
559 *ppdm = pdmentry->pdm;
560 return STATUS_SUCCESS;
561 }
562
563 /* Increment number of found modes */
564 iFoundMode++;
565 }
566 }
567
568 /* Nothing was found */
569 return STATUS_INVALID_PARAMETER;
570 }
571
572 NTSTATUS
573 NTAPI
574 UserOpenDisplaySettingsKey(
575 OUT PHKEY phkey,
576 IN PUNICODE_STRING pustrDevice,
577 IN BOOL bGlobal)
578 {
579 HKEY hkey;
580 DISPLAY_DEVICEW dispdev;
581 NTSTATUS Status;
582
583 /* Get device info */
584 Status = UserEnumDisplayDevices(pustrDevice, 0, &dispdev, 0);
585 if (!NT_SUCCESS(Status))
586 return Status;
587
588 if (bGlobal)
589 {
590 // FIXME: need to fix the registry key somehow
591 }
592
593 /* Open the registry key */
594 Status = RegOpenKey(dispdev.DeviceKey, &hkey);
595 if (!NT_SUCCESS(Status))
596 return Status;
597
598 *phkey = hkey;
599
600 return Status;
601 }
602
603 NTSTATUS
604 NTAPI
605 UserEnumRegistryDisplaySettings(
606 IN PUNICODE_STRING pustrDevice,
607 OUT LPDEVMODEW pdm)
608 {
609 UNIMPLEMENTED;
610 return STATUS_NOT_IMPLEMENTED;
611 }
612
613
614 NTSTATUS
615 APIENTRY
616 NtUserEnumDisplaySettings(
617 IN PUNICODE_STRING pustrDevice,
618 IN DWORD iModeNum,
619 OUT LPDEVMODEW lpDevMode,
620 IN DWORD dwFlags)
621 {
622 UNICODE_STRING ustrDevice;
623 WCHAR awcDevice[CCHDEVICENAME];
624 NTSTATUS Status;
625 ULONG cbSize, cbExtra;
626 DEVMODEW dmReg, *pdm;
627
628 DPRINT1("Enter NtUserEnumDisplaySettings(%ls, %ld)\n",
629 pustrDevice ? pustrDevice->Buffer:0, iModeNum);
630
631 if (pustrDevice)
632 {
633 /* Initialize destination string */
634 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
635
636 _SEH2_TRY
637 {
638 /* Probe the UNICODE_STRING and the buffer */
639 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
640 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
641
642 /* Copy the string */
643 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
644 }
645 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
646 {
647 _SEH2_YIELD(return _SEH2_GetExceptionCode());
648 }
649 _SEH2_END
650
651 pustrDevice = &ustrDevice;
652 }
653
654 /* Acquire global USER lock */
655 UserEnterExclusive();
656
657 if (iModeNum == ENUM_REGISTRY_SETTINGS)
658 {
659 /* Get the registry settings */
660 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
661 pdm = &dmReg;
662 }
663 else if (iModeNum == ENUM_CURRENT_SETTINGS)
664 {
665 /* Get the current settings */
666 Status = UserEnumCurrentDisplaySettings(pustrDevice, &pdm);
667 }
668 else
669 {
670 /* Get specified settings */
671 Status = UserEnumDisplaySettings(pustrDevice, iModeNum, &pdm, dwFlags);
672 }
673
674 /* Release lock */
675 UserLeave();
676
677 /* Did we succeed? */
678 if (NT_SUCCESS(Status))
679 {
680 /* Copy some information back */
681 _SEH2_TRY
682 {
683 ProbeForRead(lpDevMode, sizeof(DEVMODEW), 1);
684 cbSize = lpDevMode->dmSize;
685 cbExtra = lpDevMode->dmDriverExtra;
686
687 ProbeForWrite(lpDevMode, cbSize + cbExtra, 1);
688 lpDevMode->dmPelsWidth = pdm->dmPelsWidth;
689 lpDevMode->dmPelsHeight = pdm->dmPelsHeight;
690 lpDevMode->dmBitsPerPel = pdm->dmBitsPerPel;
691 lpDevMode->dmDisplayFrequency = pdm->dmDisplayFrequency;
692 lpDevMode->dmDisplayFlags = pdm->dmDisplayFlags;
693
694 /* output private/extra driver data */
695 if (cbExtra > 0 && pdm->dmDriverExtra > 0)
696 {
697 RtlCopyMemory((PCHAR)lpDevMode + cbSize,
698 (PCHAR)pdm + pdm->dmSize,
699 min(cbExtra, pdm->dmDriverExtra));
700 }
701 }
702 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
703 {
704 Status = _SEH2_GetExceptionCode();
705 }
706 _SEH2_END;
707 }
708
709 return Status;
710 }
711
712
713 LONG
714 APIENTRY
715 UserChangeDisplaySettings(
716 PUNICODE_STRING pustrDevice,
717 LPDEVMODEW pdm,
718 HWND hwnd,
719 DWORD flags,
720 LPVOID lParam)
721 {
722 DEVMODEW dmReg;
723 LONG lResult = DISP_CHANGE_SUCCESSFUL;
724 HKEY hkey;
725 NTSTATUS Status;
726 PPDEVOBJ ppdev;
727
728 /* If no DEVMODE is given, use registry settings */
729 if (!pdm)
730 {
731 /* Get the registry settings */
732 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
733 if (!NT_SUCCESS(Status))
734 {
735 DPRINT1("Could not load registry settings\n");
736 return DISP_CHANGE_BADPARAM;
737 }
738 pdm = &dmReg;
739 }
740
741 /* Get the PDEV */
742 ppdev = EngpGetPDEV(pustrDevice);
743 if (!ppdev)
744 {
745 DPRINT1("failed to get PDEV\n");
746 return DISP_CHANGE_BADPARAM;
747 }
748
749 /* Look for the requested DEVMODE */
750 pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
751 if (!pdm)
752 {
753 DPRINT1("Could not find a matching DEVMODE\n");
754 lResult = DISP_CHANGE_BADMODE;
755 goto leave;
756 }
757
758 /* Shall we update the registry? */
759 if (flags & CDS_UPDATEREGISTRY)
760 {
761 /* Open the local or global settings key */
762 Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, flags & CDS_GLOBAL);
763 if (NT_SUCCESS(Status))
764 {
765 /* Store the settings */
766 RegWriteDisplaySettings(hkey, pdm);
767
768 /* Close the registry key */
769 ZwClose(hkey);
770 }
771 else
772 {
773 DPRINT1("Could not open registry key\n");
774 lResult = DISP_CHANGE_NOTUPDATED;
775 }
776 }
777
778 /* Check if DEVMODE matches the current mode */
779 if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
780 {
781 DPRINT1("DEVMODE matches, nothing to do\n");
782 goto leave;
783 }
784
785 /* Shall we apply the settings? */
786 if (!(flags & CDS_NORESET))
787 {
788 if (!PDEVOBJ_bSwitchMode(ppdev, pdm))
789 {
790 DPRINT1("failed to set mode\n");
791 lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
792 DISP_CHANGE_FAILED : DISP_CHANGE_RESTART;
793 }
794
795 /* Send message */
796
797 }
798
799 leave:
800 // PDEVOBJ_vReleasePdev(ppdev);
801
802 return lResult;
803 }
804
805 LONG
806 APIENTRY
807 NtUserChangeDisplaySettings(
808 PUNICODE_STRING pustrDevice,
809 LPDEVMODEW lpDevMode,
810 HWND hwnd,
811 DWORD dwflags,
812 LPVOID lParam)
813 {
814 WCHAR awcDevice[CCHDEVICENAME];
815 UNICODE_STRING ustrDevice;
816 DEVMODEW dmLocal;
817 LONG Ret;
818
819 /* Check arguments */
820 if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
821 (hwnd != NULL))
822 {
823 SetLastWin32Error(ERROR_INVALID_PARAMETER);
824 return DISP_CHANGE_BADPARAM;
825 }
826
827 /* Check flags */
828 if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY))
829 {
830 return DISP_CHANGE_BADFLAGS;
831 }
832
833 /* Copy the device name */
834 if (pustrDevice)
835 {
836 /* Initialize destination string */
837 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
838
839 _SEH2_TRY
840 {
841 /* Probe the UNICODE_STRING and the buffer */
842 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
843 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
844
845 /* Copy the string */
846 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
847 }
848 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
849 {
850 SetLastNtError(_SEH2_GetExceptionCode());
851 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
852 }
853 _SEH2_END
854
855 pustrDevice = &ustrDevice;
856 }
857
858 /* Copy devmode */
859 if (lpDevMode)
860 {
861 _SEH2_TRY
862 {
863 ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1);
864 dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize);
865 ProbeForRead(lpDevMode, dmLocal.dmSize, 1);
866 RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize);
867 dmLocal.dmSize = sizeof(dmLocal);
868 }
869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
870 {
871 SetLastNtError(_SEH2_GetExceptionCode());
872 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
873 }
874 _SEH2_END
875
876 if (dmLocal.dmDriverExtra > 0)
877 {
878 DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
879 dmLocal.dmDriverExtra = 0;
880 }
881 lpDevMode = &dmLocal;
882 }
883
884 // FIXME: Copy videoparameters
885
886 /* Call internal function */
887 Ret = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
888
889 return Ret;
890 }
891