[WIN32K]: Stop memory corruption when InstalledDisplayDrivers has more than one drive...
[reactos.git] / reactos / subsystems / win32 / win32k / objects / device.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for creation and destruction of DCs
5 * FILE: subsystem/win32/win32k/objects/device.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
7 */
8
9 #include <w32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 // TODO: proper implementation of LDEVOBJ and PDEVOBJ interface
15
16 /*static*/ PDEVOBJ PrimarySurface;
17 PPDEVOBJ pPrimarySurface = &PrimarySurface;
18 static KEVENT VideoDriverNeedsPreparation;
19 static KEVENT VideoDriverPrepared;
20 PDC defaultDCstate = NULL;
21
22
23 NTSTATUS FASTCALL
24 InitDcImpl(VOID)
25 {
26 KeInitializeEvent(&VideoDriverNeedsPreparation, SynchronizationEvent, TRUE);
27 KeInitializeEvent(&VideoDriverPrepared, NotificationEvent, FALSE);
28 return STATUS_SUCCESS;
29 }
30
31
32 static BOOLEAN FASTCALL
33 GetRegistryPath(PUNICODE_STRING RegistryPath, ULONG DisplayNumber)
34 {
35 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
36 WCHAR DeviceNameBuffer[20];
37 NTSTATUS Status;
38
39 swprintf(DeviceNameBuffer, L"\\Device\\Video%lu", DisplayNumber);
40 RtlInitUnicodeString(RegistryPath, NULL);
41 RtlZeroMemory(QueryTable, sizeof(QueryTable));
42 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
43 QueryTable[0].Name = DeviceNameBuffer;
44 QueryTable[0].EntryContext = RegistryPath;
45
46 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
47 L"VIDEO",
48 QueryTable,
49 NULL,
50 NULL);
51 if (! NT_SUCCESS(Status))
52 {
53 DPRINT1("No \\Device\\Video%lu value in DEVICEMAP\\VIDEO found\n", DisplayNumber);
54 return FALSE;
55 }
56
57 DPRINT("RegistryPath %wZ\n", RegistryPath);
58
59 return TRUE;
60 }
61
62
63 NTSTATUS
64 NTAPI
65 EnumDisplayQueryRoutine(IN PWSTR ValueName,
66 IN ULONG ValueType,
67 IN PVOID ValueData,
68 IN ULONG ValueLength,
69 IN PVOID Context,
70 IN PVOID EntryContext)
71 {
72 if ((Context == NULL) && ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)))
73 {
74 *(PULONG)EntryContext = ValueLength;
75 }
76 else
77 {
78 DPRINT1("Value data: %S %d\n", ValueData, ValueLength);
79 RtlCopyMemory(Context, ValueData, ValueLength);
80 }
81
82 return STATUS_SUCCESS;
83 }
84
85 static BOOL FASTCALL
86 FindDriverFileNames(PUNICODE_STRING DriverFileNames, ULONG DisplayNumber)
87 {
88 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
89 UNICODE_STRING RegistryPath;
90 NTSTATUS Status;
91 PWCHAR DriverNames = NULL;
92 ULONG Length = 0;
93
94 if (! GetRegistryPath(&RegistryPath, DisplayNumber))
95 {
96 DPRINT("GetRegistryPath failed\n");
97 return FALSE;
98 }
99
100 RtlZeroMemory(QueryTable, sizeof(QueryTable));
101 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
102 QueryTable[0].Name = L"InstalledDisplayDrivers";
103 QueryTable[0].EntryContext = &Length;
104 QueryTable[0].QueryRoutine = EnumDisplayQueryRoutine;
105
106 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
107 RegistryPath.Buffer,
108 QueryTable,
109 NULL,
110 NULL);
111 // DPRINT1("Status: %lx\n", Status);
112 if (Length)
113 {
114 DriverNames = ExAllocatePool(PagedPool, Length);
115 // DPRINT1("Length allocated: %d\n", Length);
116 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
117 RegistryPath.Buffer,
118 QueryTable,
119 DriverNames,
120 NULL);
121 if (!NT_SUCCESS(Status)) DriverNames = NULL;
122 }
123
124 ExFreePoolWithTag(RegistryPath.Buffer, TAG_RTLREGISTRY);
125 if (! NT_SUCCESS(Status))
126 {
127 DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
128 return FALSE;
129 }
130
131 RtlInitUnicodeString(DriverFileNames, DriverNames);
132 DriverFileNames->Length = Length;
133 DriverFileNames->MaximumLength = Length;
134 //DPRINT1("DriverFileNames %wZ\n", DriverFileNames);
135
136 return TRUE;
137 }
138
139
140 static NTSTATUS APIENTRY
141 DevModeCallback(IN PWSTR ValueName,
142 IN ULONG ValueType,
143 IN PVOID ValueData,
144 IN ULONG ValueLength,
145 IN PVOID Context,
146 IN PVOID EntryContext)
147 {
148 PDEVMODEW DevMode = (PDEVMODEW) Context;
149
150 DPRINT("Found registry value for name %S: type %d, length %d\n",
151 ValueName, ValueType, ValueLength);
152
153 if (REG_DWORD == ValueType && sizeof(DWORD) == ValueLength)
154 {
155 if (0 == _wcsicmp(ValueName, L"DefaultSettings.BitsPerPel"))
156 {
157 DevMode->dmBitsPerPel = *((DWORD *) ValueData);
158 }
159 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.Flags"))
160 {
161 DevMode->dmDisplayFlags = *((DWORD *) ValueData);
162 }
163 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.VRefresh"))
164 {
165 DevMode->dmDisplayFrequency = *((DWORD *) ValueData);
166 }
167 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XPanning"))
168 {
169 DevMode->dmPanningWidth = *((DWORD *) ValueData);
170 }
171 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XResolution"))
172 {
173 DevMode->dmPelsWidth = *((DWORD *) ValueData);
174 }
175 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YPanning"))
176 {
177 DevMode->dmPanningHeight = *((DWORD *) ValueData);
178 }
179 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YResolution"))
180 {
181 DevMode->dmPelsHeight = *((DWORD *) ValueData);
182 }
183 }
184
185 return STATUS_SUCCESS;
186 }
187
188
189 static BOOL FASTCALL
190 SetupDevMode(PDEVMODEW DevMode, ULONG DisplayNumber)
191 {
192 UNICODE_STRING RegistryPath;
193 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
194 NTSTATUS Status;
195 BOOLEAN Valid = TRUE;
196
197 if (!GetRegistryPath(&RegistryPath, DisplayNumber))
198 {
199 DPRINT("GetRegistryPath failed\n");
200 return FALSE;
201 }
202
203 RtlZeroMemory(QueryTable, sizeof(QueryTable));
204 QueryTable[0].QueryRoutine = DevModeCallback;
205 QueryTable[0].Flags = 0;
206 QueryTable[0].Name = NULL;
207 QueryTable[0].EntryContext = NULL;
208 QueryTable[0].DefaultType = REG_NONE;
209 QueryTable[0].DefaultData = NULL;
210 QueryTable[0].DefaultLength = 0;
211
212 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
213 RegistryPath.Buffer,
214 QueryTable,
215 DevMode,
216 NULL);
217 if (! NT_SUCCESS(Status))
218 {
219 DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
220 &RegistryPath, Status);
221 Valid = FALSE;
222 }
223 else
224 {
225 DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
226 DevMode->dmBitsPerPel, DevMode->dmDisplayFrequency,
227 DevMode->dmPelsWidth, DevMode->dmPelsHeight);
228 if (0 == DevMode->dmBitsPerPel || 0 == DevMode->dmDisplayFrequency
229 || 0 == DevMode->dmPelsWidth || 0 == DevMode->dmPelsHeight)
230 {
231 DPRINT("Not all required devmode members are set\n");
232 Valid = FALSE;
233 }
234 }
235
236 ExFreePoolWithTag(RegistryPath.Buffer, TAG_RTLREGISTRY);
237
238 if (! Valid)
239 {
240 RtlZeroMemory(DevMode, sizeof(DEVMODEW));
241 }
242
243 return Valid;
244 }
245
246 static BOOL FASTCALL
247 IntPrepareDriver(VOID)
248 {
249 PFN_DrvEnableDriver GDEnableDriver;
250 DRVENABLEDATA DED;
251 UNICODE_STRING DriverFileNames;
252 PWSTR CurrentName;
253 BOOL GotDriver;
254 BOOL DoDefault;
255 ULONG DisplayNumber;
256 LARGE_INTEGER Zero;
257 BOOLEAN ret = FALSE;
258
259 Zero.QuadPart = 0;
260 if (STATUS_SUCCESS != KeWaitForSingleObject(&VideoDriverNeedsPreparation, Executive, KernelMode, TRUE, &Zero))
261 {
262 /* Concurrent access. Wait for VideoDriverPrepared event */
263 if (STATUS_SUCCESS == KeWaitForSingleObject(&VideoDriverPrepared, Executive, KernelMode, TRUE, NULL))
264 ret = PrimarySurface.PreparedDriver;
265 goto cleanup;
266 }
267 // HAX! Fixme so I can support more than one! So how many?
268 for (DisplayNumber = 0; ; DisplayNumber++)
269 {
270 DPRINT("Trying to load display driver no. %d\n", DisplayNumber);
271
272 RtlZeroMemory(&PrimarySurface, sizeof(PrimarySurface));
273
274 // if (!pPrimarySurface) pPrimarySurface = ExAllocatePoolWithTag(PagedPool, gdwDirectDrawContext + sizeof(PDEVOBJ), TAG_GDIPDEV);
275
276 PrimarySurface.VideoFileObject = DRIVER_FindMPDriver(DisplayNumber);
277
278 /* Open the miniport driver */
279 if (PrimarySurface.VideoFileObject == NULL)
280 {
281 DPRINT1("FindMPDriver failed\n");
282 goto cleanup;
283 }
284
285 /* Retrieve DDI driver names from registry */
286 RtlInitUnicodeString(&DriverFileNames, NULL);
287 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
288 {
289 DPRINT1("FindDriverFileNames failed\n");
290 continue;
291 }
292
293 /*
294 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
295 * scan all of them until a good one found.
296 */
297 CurrentName = DriverFileNames.Buffer;
298 GotDriver = FALSE;
299 while (!GotDriver &&
300 CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
301 {
302 /* Get the DDI driver's entry point */
303 GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
304 if (NULL == GDEnableDriver)
305 {
306 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
307 }
308 else
309 {
310 /* Call DDI driver's EnableDriver function */
311 RtlZeroMemory(&DED, sizeof(DED));
312
313 if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof(DED), &DED))
314 {
315 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
316 }
317 else
318 {
319 GotDriver = TRUE;
320 }
321 }
322
323 if (! GotDriver)
324 {
325 /* Skip to the next name but never get past the Unicode string */
326 while (L'\0' != *CurrentName &&
327 CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
328 {
329 CurrentName++;
330 }
331 if (CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
332 {
333 CurrentName++;
334 }
335 }
336 }
337
338 if (!GotDriver)
339 {
340 ObDereferenceObject(PrimarySurface.VideoFileObject);
341 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
342 DPRINT1("No suitable DDI driver found\n");
343 continue;
344 }
345
346 DPRINT1("Display driver %S loaded\n", CurrentName);
347
348 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
349
350 DPRINT("Building DDI Functions\n");
351
352 /* Construct DDI driver function dispatch table */
353 if (!DRIVER_BuildDDIFunctions(&DED, &PrimarySurface.DriverFunctions))
354 {
355 ObDereferenceObject(PrimarySurface.VideoFileObject);
356 DPRINT1("BuildDDIFunctions failed\n");
357 goto cleanup;
358 }
359
360 /* Allocate a phyical device handle from the driver */
361 // Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
362 PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
363 if (SetupDevMode(&PrimarySurface.DMW, DisplayNumber))
364 {
365 PrimarySurface.dhpdev = PrimarySurface.DriverFunctions.EnablePDEV(
366 &PrimarySurface.DMW,
367 L"",
368 HS_DDI_MAX,
369 PrimarySurface.ahsurf,
370 sizeof(PrimarySurface.gdiinfo),
371 &PrimarySurface.gdiinfo,
372 sizeof(PrimarySurface.devinfo),
373 &PrimarySurface.devinfo,
374 NULL,
375 L"",
376 (HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
377 DoDefault = (NULL == PrimarySurface.dhpdev);
378 if (DoDefault)
379 {
380 DPRINT1("DrvEnablePDev with registry parameters failed\n");
381 }
382 }
383 else
384 {
385 DoDefault = TRUE;
386 }
387
388 if (DoDefault)
389 {
390 RtlZeroMemory(&(PrimarySurface.DMW), sizeof(DEVMODEW));
391 PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
392 PrimarySurface.dhpdev = PrimarySurface.DriverFunctions.EnablePDEV(
393 &PrimarySurface.DMW,
394 L"",
395 HS_DDI_MAX,
396 PrimarySurface.ahsurf,
397 sizeof(PrimarySurface.gdiinfo),
398 &PrimarySurface.gdiinfo,
399 sizeof(PrimarySurface.devinfo),
400 &PrimarySurface.devinfo,
401 NULL,
402 L"",
403 (HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
404
405 if (NULL == PrimarySurface.dhpdev)
406 {
407 ObDereferenceObject(PrimarySurface.VideoFileObject);
408 DPRINT1("DrvEnablePDEV with default parameters failed\n");
409 DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
410 continue;
411 }
412
413 // Update the primary surface with what we really got
414 PrimarySurface.DMW.dmPelsWidth = PrimarySurface.gdiinfo.ulHorzRes;
415 PrimarySurface.DMW.dmPelsHeight = PrimarySurface.gdiinfo.ulVertRes;
416 PrimarySurface.DMW.dmBitsPerPel = PrimarySurface.gdiinfo.cBitsPixel;
417 PrimarySurface.DMW.dmDisplayFrequency = PrimarySurface.gdiinfo.ulVRefresh;
418 }
419
420 if (!PrimarySurface.DMW.dmDriverExtra)
421 {
422 PrimarySurface.pdmwDev = &PrimarySurface.DMW; // HAX!
423 }
424 else
425 {
426 DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
427 }
428 // Dont remove until we finish testing other drivers.
429 if (PrimarySurface.DMW.dmDriverExtra != 0)
430 {
431 DPRINT1("**** DMW extra = %u bytes. Please report to ros-dev@reactos.org ****\n", PrimarySurface.DMW.dmDriverExtra);
432 }
433
434 if (0 == PrimarySurface.gdiinfo.ulLogPixelsX)
435 {
436 DPRINT("Adjusting gdiinfo.ulLogPixelsX\n");
437 PrimarySurface.gdiinfo.ulLogPixelsX = 96;
438 }
439 if (0 == PrimarySurface.gdiinfo.ulLogPixelsY)
440 {
441 DPRINT("Adjusting gdiinfo.ulLogPixelsY\n");
442 PrimarySurface.gdiinfo.ulLogPixelsY = 96;
443 }
444
445 PrimarySurface.Pointer.Exclude.right = -1;
446
447 DPRINT("calling completePDev\n");
448
449 /* Complete initialization of the physical device */
450 PrimarySurface.DriverFunctions.CompletePDEV(
451 PrimarySurface.dhpdev,
452 (HDEV)&PrimarySurface);
453
454 DPRINT("calling DRIVER_ReferenceDriver\n");
455
456 DRIVER_ReferenceDriver(L"DISPLAY");
457
458 PrimarySurface.PreparedDriver = TRUE;
459 PrimarySurface.DisplayNumber = DisplayNumber;
460 PrimarySurface.flFlags = PDEV_DISPLAY; // Hard set,, add more flags.
461 PrimarySurface.hsemDevLock = (PERESOURCE)EngCreateSemaphore();
462 // Should be null,, but make sure for now.
463 PrimarySurface.pvGammaRamp = NULL;
464 PrimarySurface.ppdevNext = NULL; // Fixme! We need to support more than display drvs.
465 PrimarySurface.ppdevParent = NULL; // Always NULL if primary.
466 PrimarySurface.pGraphicsDevice = NULL; // Fixme!
467 PrimarySurface.pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), TAG_EDDGBL);
468 if (PrimarySurface.pEDDgpl)
469 {
470 RtlZeroMemory( PrimarySurface.pEDDgpl ,sizeof(EDD_DIRECTDRAW_GLOBAL));
471 ret = TRUE;
472 }
473 goto cleanup;
474 }
475
476 cleanup:
477 KeSetEvent(&VideoDriverPrepared, 1, FALSE);
478 return ret;
479 }
480
481 BOOL FASTCALL
482 IntPrepareDriverIfNeeded(VOID)
483 {
484 return (PrimarySurface.PreparedDriver ? TRUE : IntPrepareDriver());
485 }
486
487 static BOOL FASTCALL
488 PrepareVideoPrt(VOID)
489 {
490 PIRP Irp;
491 NTSTATUS Status;
492 IO_STATUS_BLOCK Iosb;
493 BOOL Prepare = TRUE;
494 ULONG Length = sizeof(BOOL);
495 PIO_STACK_LOCATION StackPtr;
496 LARGE_INTEGER StartOffset;
497 PFILE_OBJECT FileObject = PrimarySurface.VideoFileObject;
498 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
499
500 DPRINT("PrepareVideoPrt() called\n");
501
502 KeClearEvent(&PrimarySurface.VideoFileObject->Event);
503
504 ObReferenceObjectByPointer(FileObject, 0, IoFileObjectType, KernelMode);
505
506 StartOffset.QuadPart = 0;
507 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
508 DeviceObject,
509 (PVOID) &Prepare,
510 Length,
511 &StartOffset,
512 NULL,
513 &Iosb);
514 if (NULL == Irp)
515 {
516 return FALSE;
517 }
518
519 /* Set up IRP Data */
520 Irp->Tail.Overlay.OriginalFileObject = FileObject;
521 Irp->RequestorMode = KernelMode;
522 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
523 Irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
524 Irp->Flags |= IRP_WRITE_OPERATION;
525
526 /* Setup Stack Data */
527 StackPtr = IoGetNextIrpStackLocation(Irp);
528 StackPtr->FileObject = PrimarySurface.VideoFileObject;
529 StackPtr->Parameters.Write.Key = 0;
530
531 Status = IoCallDriver(DeviceObject, Irp);
532
533 if (STATUS_PENDING == Status)
534 {
535 KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, TRUE, 0);
536 Status = Iosb.Status;
537 }
538
539 return NT_SUCCESS(Status);
540 }
541
542
543 BOOL FASTCALL
544 IntCreatePrimarySurface(VOID)
545 {
546 SIZEL SurfSize;
547 RECTL SurfaceRect;
548 SURFOBJ *SurfObj;
549 BOOL calledFromUser;
550
551 if (! IntPrepareDriverIfNeeded())
552 {
553 return FALSE;
554 }
555
556 if (! PrepareVideoPrt())
557 {
558 return FALSE;
559 }
560
561 DPRINT("calling EnableSurface\n");
562 /* Enable the drawing surface */
563 PrimarySurface.pSurface =
564 PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.dhpdev);
565 if (NULL == PrimarySurface.pSurface)
566 {
567 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);*/
568 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.dhpdev);
569 ObDereferenceObject(PrimarySurface.VideoFileObject);
570 DPRINT1("DrvEnableSurface failed\n");
571 return FALSE;
572 }
573
574 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, TRUE);
575
576 calledFromUser = UserIsEntered(); //fixme: possibly upgrade a shared lock
577 if (!calledFromUser)
578 {
579 UserEnterExclusive();
580 }
581
582 /* attach monitor */
583 IntAttachMonitor(&PrimarySurface, PrimarySurface.DisplayNumber);
584
585 SurfObj = EngLockSurface(PrimarySurface.pSurface);
586 SurfObj->dhpdev = PrimarySurface.dhpdev;
587 SurfSize = SurfObj->sizlBitmap;
588 SurfaceRect.left = SurfaceRect.top = 0;
589 SurfaceRect.right = SurfObj->sizlBitmap.cx;
590 SurfaceRect.bottom = SurfObj->sizlBitmap.cy;
591 /* FIXME - why does EngEraseSurface() sometimes crash?
592 EngEraseSurface(SurfObj, &SurfaceRect, 0); */
593
594 /* Put the pointer in the center of the screen */
595 gpsi->ptCursor.x = (SurfaceRect.right - SurfaceRect.left) / 2;
596 gpsi->ptCursor.y = (SurfaceRect.bottom - SurfaceRect.top) / 2;
597
598 /* Give the PDEV a MovePointer function */
599 PrimarySurface.pfnMovePointer = PrimarySurface.DriverFunctions.MovePointer;
600 if (!PrimarySurface.pfnMovePointer)
601 PrimarySurface.pfnMovePointer = EngMovePointer;
602
603 EngUnlockSurface(SurfObj);
604 co_IntShowDesktop(IntGetActiveDesktop(), SurfSize.cx, SurfSize.cy);
605
606 // Init Primary Displays Device Capabilities.
607 IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
608
609 if (!calledFromUser)
610 {
611 UserLeave();
612 }
613
614 return TRUE;
615 }
616
617 VOID FASTCALL
618 IntDestroyPrimarySurface(VOID)
619 {
620 BOOL calledFromUser;
621
622 DRIVER_UnreferenceDriver(L"DISPLAY");
623
624 calledFromUser = UserIsEntered();
625 if (!calledFromUser)
626 {
627 UserEnterExclusive();
628 }
629
630 /* detach monitor */
631 IntDetachMonitor(&PrimarySurface);
632
633 if (!calledFromUser)
634 {
635 UserLeave();
636 }
637
638 /*
639 * FIXME: Hide a mouse pointer there. Also because we have to prevent
640 * memory leaks with the Eng* mouse routines.
641 */
642
643 DPRINT("Reseting display\n" );
644 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);
645 PrimarySurface.DriverFunctions.DisableSurface(PrimarySurface.dhpdev);
646 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.dhpdev);
647 PrimarySurface.PreparedDriver = FALSE;
648 KeSetEvent(&VideoDriverNeedsPreparation, 1, FALSE);
649 KeResetEvent(&VideoDriverPrepared);
650
651 DceEmptyCache();
652
653 ObDereferenceObject(PrimarySurface.VideoFileObject);
654 }
655
656 INT
657 FASTCALL
658 IntcFonts(PPDEVOBJ pDevObj)
659 {
660 ULONG_PTR Junk;
661 // Msdn DrvQueryFont:
662 // If the number of fonts in DEVINFO is -1 and iFace is zero, the driver
663 // should return the number of fonts it supports.
664 if ( pDevObj->devinfo.cFonts == -1)
665 {
666 if (pDevObj->DriverFunctions.QueryFont)
667 pDevObj->devinfo.cFonts =
668 (ULONG)pDevObj->DriverFunctions.QueryFont(pDevObj->dhpdev, 0, 0, &Junk);
669 else
670 pDevObj->devinfo.cFonts = 0;
671 }
672 return pDevObj->devinfo.cFonts;
673 }
674
675 //
676 // Support multi display/device locks.
677 //
678 VOID
679 FASTCALL
680 DC_LockDisplay(HDC hDC)
681 {
682 PERESOURCE Resource;
683 PDC dc = DC_LockDc(hDC);
684 if (!dc) return;
685 Resource = dc->ppdev->hsemDevLock;
686 DC_UnlockDc(dc);
687 if (!Resource) return;
688 KeEnterCriticalRegion();
689 ExAcquireResourceExclusiveLite( Resource , TRUE);
690 }
691
692 VOID
693 FASTCALL
694 DC_UnlockDisplay(HDC hDC)
695 {
696 PERESOURCE Resource;
697 PDC dc = DC_LockDc(hDC);
698 if (!dc) return;
699 Resource = dc->ppdev->hsemDevLock;
700 DC_UnlockDc(dc);
701 if (!Resource) return;
702 ExReleaseResourceLite( Resource );
703 KeLeaveCriticalRegion();
704 }
705
706 //
707 // Enumerate HDev
708 //
709 PPDEVOBJ FASTCALL
710 IntEnumHDev(VOID)
711 {
712 // I guess we will soon have more than one primary surface.
713 // This will do for now.
714 return &PrimarySurface;
715 }
716
717
718 VOID FASTCALL
719 IntGdiReferencePdev(PPDEVOBJ ppdev)
720 {
721 if (!hsemDriverMgmt) hsemDriverMgmt = EngCreateSemaphore(); // Hax, should be in dllmain.c
722 IntGdiAcquireSemaphore(hsemDriverMgmt);
723 ppdev->cPdevRefs++;
724 IntGdiReleaseSemaphore(hsemDriverMgmt);
725 }
726
727 VOID FASTCALL
728 IntGdiUnreferencePdev(PPDEVOBJ ppdev, DWORD CleanUpType)
729 {
730 IntGdiAcquireSemaphore(hsemDriverMgmt);
731 ppdev->cPdevRefs--;
732 if (!ppdev->cPdevRefs)
733 {
734 // Handle the destruction of ppdev or PDEVOBJ or PDEVOBJ or PDEV etc.
735 }
736 IntGdiReleaseSemaphore(hsemDriverMgmt);
737 }
738
739
740
741 INT
742 FASTCALL
743 IntGetColorManagementCaps(PPDEVOBJ pDevObj)
744 {
745 INT ret = CM_NONE;
746
747 if ( pDevObj->flFlags & PDEV_DISPLAY)
748 {
749 if (pDevObj->devinfo.iDitherFormat == BMF_8BPP ||
750 pDevObj->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP)
751 ret = CM_GAMMA_RAMP;
752 }
753 if (pDevObj->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR)
754 ret |= CM_CMYK_COLOR;
755 if (pDevObj->devinfo.flGraphicsCaps & GCAPS_ICM)
756 ret |= CM_DEVICE_ICM;
757 return ret;
758 }
759
760 INT FASTCALL
761 IntGdiGetDeviceCaps(PDC dc, INT Index)
762 {
763 INT ret = 0;
764 PPDEVOBJ ppdev = dc->ppdev;
765 /* Retrieve capability */
766 switch (Index)
767 {
768 case DRIVERVERSION:
769 ret = ppdev->gdiinfo.ulVersion;
770 break;
771
772 case TECHNOLOGY:
773 ret = ppdev->gdiinfo.ulTechnology;
774 break;
775
776 case HORZSIZE:
777 ret = ppdev->gdiinfo.ulHorzSize;
778 break;
779
780 case VERTSIZE:
781 ret = ppdev->gdiinfo.ulVertSize;
782 break;
783
784 case HORZRES:
785 ret = ppdev->gdiinfo.ulHorzRes;
786 break;
787
788 case VERTRES:
789 ret = ppdev->gdiinfo.ulVertRes;
790 break;
791
792 case LOGPIXELSX:
793 ret = ppdev->gdiinfo.ulLogPixelsX;
794 break;
795
796 case LOGPIXELSY:
797 ret = ppdev->gdiinfo.ulLogPixelsY;
798 break;
799
800 case CAPS1:
801 if ( ppdev->pGraphicsDevice &&
802 (((PGRAPHICS_DEVICE)ppdev->pGraphicsDevice)->StateFlags &
803 DISPLAY_DEVICE_MIRRORING_DRIVER))
804 ret = C1_MIRRORING;
805 break;
806
807 case BITSPIXEL:
808 ret = ppdev->gdiinfo.cBitsPixel;
809 break;
810
811 case PLANES:
812 ret = ppdev->gdiinfo.cPlanes;
813 break;
814
815 case NUMBRUSHES:
816 ret = -1;
817 break;
818
819 case NUMPENS:
820 ret = ppdev->gdiinfo.ulNumColors;
821 if ( ret != -1 ) ret *= 5;
822 break;
823
824 case NUMFONTS:
825 ret = IntcFonts(ppdev);
826 break;
827
828 case NUMCOLORS:
829 ret = ppdev->gdiinfo.ulNumColors;
830 break;
831
832 case ASPECTX:
833 ret = ppdev->gdiinfo.ulAspectX;
834 break;
835
836 case ASPECTY:
837 ret = ppdev->gdiinfo.ulAspectY;
838 break;
839
840 case ASPECTXY:
841 ret = ppdev->gdiinfo.ulAspectXY;
842 break;
843
844 case CLIPCAPS:
845 ret = CP_RECTANGLE;
846 break;
847
848 case SIZEPALETTE:
849 ret = ppdev->gdiinfo.ulNumPalReg;
850 break;
851
852 case NUMRESERVED:
853 ret = 20;
854 break;
855
856 case COLORRES:
857 ret = ppdev->gdiinfo.ulDACRed +
858 ppdev->gdiinfo.ulDACGreen +
859 ppdev->gdiinfo.ulDACBlue;
860 break;
861
862 case DESKTOPVERTRES:
863 ret = ppdev->gdiinfo.ulVertRes;
864 break;
865
866 case DESKTOPHORZRES:
867 ret = ppdev->gdiinfo.ulHorzRes;
868 break;
869
870 case BLTALIGNMENT:
871 ret = ppdev->gdiinfo.ulBltAlignment;
872 break;
873
874 case SHADEBLENDCAPS:
875 ret = ppdev->gdiinfo.flShadeBlend;
876 break;
877
878 case COLORMGMTCAPS:
879 ret = IntGetColorManagementCaps(ppdev);
880 break;
881
882 case PHYSICALWIDTH:
883 ret = ppdev->gdiinfo.szlPhysSize.cx;
884 break;
885
886 case PHYSICALHEIGHT:
887 ret = ppdev->gdiinfo.szlPhysSize.cy;
888 break;
889
890 case PHYSICALOFFSETX:
891 ret = ppdev->gdiinfo.ptlPhysOffset.x;
892 break;
893
894 case PHYSICALOFFSETY:
895 ret = ppdev->gdiinfo.ptlPhysOffset.y;
896 break;
897
898 case VREFRESH:
899 ret = ppdev->gdiinfo.ulVRefresh;
900 break;
901
902 case RASTERCAPS:
903 ret = ppdev->gdiinfo.flRaster;
904 break;
905
906 case CURVECAPS:
907 ret = (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
908 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
909 break;
910
911 case LINECAPS:
912 ret = (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
913 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
914 break;
915
916 case POLYGONALCAPS:
917 ret = (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
918 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
919 break;
920
921 case TEXTCAPS:
922 ret = ppdev->gdiinfo.flTextCaps;
923 if (ppdev->gdiinfo.ulTechnology) ret |= TC_VA_ABLE;
924 ret |= (TC_SO_ABLE|TC_UA_ABLE);
925 break;
926
927 case PDEVICESIZE:
928 case SCALINGFACTORX:
929 case SCALINGFACTORY:
930 default:
931 ret = 0;
932 break;
933 }
934
935 return ret;
936 }
937
938 INT APIENTRY
939 NtGdiGetDeviceCaps(HDC hDC,
940 INT Index)
941 {
942 PDC dc;
943 INT ret;
944
945 dc = DC_LockDc(hDC);
946 if (dc == NULL)
947 {
948 SetLastWin32Error(ERROR_INVALID_HANDLE);
949 return 0;
950 }
951
952 ret = IntGdiGetDeviceCaps(dc, Index);
953
954 DPRINT("(%04x,%d): returning %d\n", hDC, Index, ret);
955
956 DC_UnlockDc( dc );
957 return ret;
958 }
959
960 VOID
961 FASTCALL
962 IntvGetDeviceCaps(
963 PPDEVOBJ pDevObj,
964 PDEVCAPS pDevCaps)
965 {
966 ULONG Tmp = 0;
967 PGDIINFO pGdiInfo = &pDevObj->gdiinfo;
968
969 pDevCaps->ulVersion = pGdiInfo->ulVersion;
970 pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
971 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000;
972 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000;
973 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
974 pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
975 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
976 pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
977 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
978 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
979 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
980 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
981 pDevCaps->ulPlanes = pGdiInfo->cPlanes;
982
983 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
984 if (pGdiInfo->cBitsPixel == 15) pDevCaps->ulBitsPixel = 16;
985
986 Tmp = pGdiInfo->ulNumColors;
987 if ( Tmp != -1 ) Tmp *= 5;
988 pDevCaps->ulNumPens = Tmp;
989 pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
990
991 pDevCaps->ulNumFonts = IntcFonts(pDevObj);
992
993 pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
994 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend;
995 pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
996 pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
997 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
998 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
999 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
1000 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
1001 pDevCaps->ulColorRes = pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue;
1002 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
1003 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
1004 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
1005 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
1006 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes;
1007 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes;
1008 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment;
1009 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment;
1010
1011 Tmp = 0;
1012 Tmp = pGdiInfo->flTextCaps | (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
1013
1014 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps | (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
1015
1016 if (pGdiInfo->ulTechnology)
1017 pDevCaps->ulTextCaps = Tmp | TC_VA_ABLE;
1018
1019 pDevCaps->ulColorMgmtCaps = IntGetColorManagementCaps(pDevObj);
1020
1021 return;
1022 }
1023
1024 /*
1025 * @implemented
1026 */
1027 BOOL
1028 APIENTRY
1029 NtGdiGetDeviceCapsAll (
1030 IN HDC hDC,
1031 OUT PDEVCAPS pDevCaps)
1032 {
1033 PDC dc;
1034 PDEVCAPS pSafeDevCaps;
1035 NTSTATUS Status = STATUS_SUCCESS;
1036
1037 dc = DC_LockDc(hDC);
1038 if (!dc)
1039 {
1040 SetLastWin32Error(ERROR_INVALID_HANDLE);
1041 return FALSE;
1042 }
1043
1044 pSafeDevCaps = ExAllocatePoolWithTag(PagedPool, sizeof(DEVCAPS), TAG_TEMP);
1045
1046 if (!pSafeDevCaps)
1047 {
1048 DC_UnlockDc(dc);
1049 return FALSE;
1050 }
1051
1052 IntvGetDeviceCaps(dc->ppdev, pSafeDevCaps);
1053
1054 _SEH2_TRY
1055 {
1056 ProbeForWrite(pDevCaps,
1057 sizeof(DEVCAPS),
1058 1);
1059 RtlCopyMemory(pDevCaps, pSafeDevCaps, sizeof(DEVCAPS));
1060 }
1061 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1062 {
1063 Status = _SEH2_GetExceptionCode();
1064 }
1065 _SEH2_END;
1066
1067 ExFreePoolWithTag(pSafeDevCaps, TAG_TEMP);
1068 DC_UnlockDc(dc);
1069
1070 if (!NT_SUCCESS(Status))
1071 {
1072 SetLastNtError(Status);
1073 return FALSE;
1074 }
1075 return TRUE;
1076 }
1077
1078
1079 /*
1080 * @implemented
1081 */
1082 DHPDEV
1083 APIENTRY
1084 NtGdiGetDhpdev(
1085 IN HDEV hdev)
1086 {
1087 PPDEVOBJ ppdev, pGdiDevice = (PPDEVOBJ) hdev;
1088 if (!pGdiDevice) return NULL;
1089 if ( pGdiDevice < (PPDEVOBJ)MmSystemRangeStart) return NULL;
1090 ppdev = pPrimarySurface;
1091 IntGdiAcquireSemaphore(hsemDriverMgmt);
1092 do
1093 {
1094 if (pGdiDevice == ppdev) break;
1095 else
1096 ppdev = ppdev->ppdevNext;
1097 }
1098 while (ppdev != NULL);
1099 IntGdiReleaseSemaphore(hsemDriverMgmt);
1100 if (!ppdev) return NULL;
1101 return pGdiDevice->dhpdev;
1102 }
1103
1104 static NTSTATUS FASTCALL
1105 GetVideoRegistryKey(
1106 OUT PUNICODE_STRING RegistryPath,
1107 IN PCUNICODE_STRING DeviceName) /* ex: "\Device\Video0" */
1108 {
1109 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1110 NTSTATUS Status;
1111
1112 RtlInitUnicodeString(RegistryPath, NULL);
1113 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1114 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1115 QueryTable[0].Name = DeviceName->Buffer;
1116 QueryTable[0].EntryContext = RegistryPath;
1117
1118 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
1119 L"VIDEO",
1120 QueryTable,
1121 NULL,
1122 NULL);
1123 if (!NT_SUCCESS(Status))
1124 {
1125 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName, Status);
1126 return STATUS_NO_SUCH_DEVICE;
1127 }
1128
1129 DPRINT("RegistryPath %wZ\n", RegistryPath);
1130 return STATUS_SUCCESS;
1131 }
1132
1133
1134 static NTSTATUS FASTCALL
1135 GetVideoDeviceName(
1136 OUT PUNICODE_STRING VideoDeviceName,
1137 IN PCUNICODE_STRING DisplayDevice) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
1138 {
1139 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\??\\");
1140 UNICODE_STRING ObjectName;
1141 UNICODE_STRING KernelModeName = { 0, };
1142 OBJECT_ATTRIBUTES ObjectAttributes;
1143 USHORT LastSlash;
1144 ULONG Length;
1145 HANDLE LinkHandle = NULL;
1146 NTSTATUS Status;
1147
1148 RtlInitUnicodeString(VideoDeviceName, NULL);
1149
1150 /* Get device name (DisplayDevice is "\.\xxx") */
1151 for (LastSlash = DisplayDevice->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
1152 {
1153 if (DisplayDevice->Buffer[LastSlash - 1] == L'\\')
1154 break;
1155 }
1156
1157 if (LastSlash == 0)
1158 {
1159 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice);
1160 Status = STATUS_OBJECT_NAME_INVALID;
1161 goto cleanup;
1162 }
1163 ObjectName = *DisplayDevice;
1164 ObjectName.Length -= LastSlash * sizeof(WCHAR);
1165 ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
1166 ObjectName.Buffer += LastSlash;
1167
1168 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
1169 KernelModeName.MaximumLength = Prefix.Length + ObjectName.Length + sizeof(UNICODE_NULL);
1170 KernelModeName.Buffer = ExAllocatePoolWithTag(PagedPool,
1171 KernelModeName.MaximumLength,
1172 TAG_DC);
1173 if (!KernelModeName.Buffer)
1174 {
1175 Status = STATUS_NO_MEMORY;
1176 goto cleanup;
1177 }
1178 RtlCopyUnicodeString(&KernelModeName, &Prefix);
1179 Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
1180 if (!NT_SUCCESS(Status))
1181 goto cleanup;
1182
1183 /* Open \??\xxx (ex: "\??\DISPLAY1") */
1184 InitializeObjectAttributes(&ObjectAttributes,
1185 &KernelModeName,
1186 OBJ_KERNEL_HANDLE,
1187 NULL,
1188 NULL);
1189 Status = ZwOpenSymbolicLinkObject(&LinkHandle,
1190 GENERIC_READ,
1191 &ObjectAttributes);
1192 if (!NT_SUCCESS(Status))
1193 {
1194 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
1195 Status = STATUS_NO_SUCH_DEVICE;
1196 goto cleanup;
1197 }
1198
1199 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, &Length);
1200 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
1201 {
1202 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
1203 Status = STATUS_NO_SUCH_DEVICE;
1204 goto cleanup;
1205 }
1206 VideoDeviceName->MaximumLength = Length;
1207 VideoDeviceName->Buffer = ExAllocatePoolWithTag(PagedPool,
1208 VideoDeviceName->MaximumLength + sizeof(UNICODE_NULL),
1209 TAG_DC);
1210 if (!VideoDeviceName->Buffer)
1211 {
1212 Status = STATUS_NO_MEMORY;
1213 goto cleanup;
1214 }
1215 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, NULL);
1216 VideoDeviceName->Buffer[VideoDeviceName->MaximumLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
1217 if (!NT_SUCCESS(Status))
1218 {
1219 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
1220 Status = STATUS_NO_SUCH_DEVICE;
1221 goto cleanup;
1222 }
1223 Status = STATUS_SUCCESS;
1224
1225 cleanup:
1226 if (!NT_SUCCESS(Status) && VideoDeviceName->Buffer)
1227 ExFreePoolWithTag(VideoDeviceName->Buffer, TAG_DC);
1228 if (KernelModeName.Buffer)
1229 ExFreePoolWithTag(KernelModeName.Buffer, TAG_DC);
1230 if (LinkHandle)
1231 ZwClose(LinkHandle);
1232 return Status;
1233 }
1234
1235 LONG
1236 FASTCALL
1237 IntChangeDisplaySettings(
1238 IN PUNICODE_STRING pDeviceName OPTIONAL,
1239 IN LPDEVMODEW DevMode,
1240 IN DWORD dwflags,
1241 IN PVOID lParam OPTIONAL)
1242 {
1243 BOOLEAN Global = FALSE;
1244 BOOLEAN NoReset = FALSE;
1245 BOOLEAN Reset = FALSE;
1246 BOOLEAN SetPrimary = FALSE;
1247 LONG Ret = DISP_CHANGE_SUCCESSFUL;
1248 NTSTATUS Status ;
1249
1250 DPRINT1("display flags : %x\n",dwflags);
1251
1252 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
1253 {
1254 /* Check global, reset and noreset flags */
1255 if ((dwflags & CDS_GLOBAL) == CDS_GLOBAL)
1256 Global = TRUE;
1257 if ((dwflags & CDS_NORESET) == CDS_NORESET)
1258 NoReset = TRUE;
1259 dwflags &= ~(CDS_GLOBAL | CDS_NORESET);
1260 }
1261 if ((dwflags & CDS_RESET) == CDS_RESET)
1262 Reset = TRUE;
1263 if ((dwflags & CDS_SET_PRIMARY) == CDS_SET_PRIMARY)
1264 SetPrimary = TRUE;
1265 dwflags &= ~(CDS_RESET | CDS_SET_PRIMARY);
1266
1267 if (Reset && NoReset)
1268 return DISP_CHANGE_BADFLAGS;
1269
1270 if (dwflags == 0)
1271 {
1272 /* Dynamically change graphics mode */
1273 DPRINT1("flag 0 UNIMPLEMENTED\n");
1274 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
1275 return DISP_CHANGE_FAILED;
1276 }
1277
1278 if ((dwflags & CDS_TEST) == CDS_TEST)
1279 {
1280 /* Test resolution */
1281 dwflags &= ~CDS_TEST;
1282 Status = IntEnumDisplaySettings(pDeviceName, ENUM_REGISTRY_SETTINGS, DevMode, 0);
1283 if (!NT_SUCCESS(Status))
1284 Ret = DISP_CHANGE_BADMODE;
1285 return Ret;
1286 }
1287
1288 if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
1289 {
1290 DEVMODEW lpDevMode;
1291 /* Full Screen */
1292 dwflags &= ~CDS_FULLSCREEN;
1293 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
1294 Ret = DISP_CHANGE_FAILED;
1295
1296 RtlZeroMemory(&lpDevMode, sizeof(DEVMODEW));
1297 lpDevMode.dmSize = sizeof(DEVMODEW);
1298
1299 Status = IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0);
1300 if (!NT_SUCCESS(Status))
1301 return DISP_CHANGE_FAILED;
1302
1303 DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
1304 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
1305
1306
1307 if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
1308 (lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) &&
1309 (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
1310 Ret = DISP_CHANGE_SUCCESSFUL;
1311 }
1312
1313 if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
1314 {
1315 dwflags &= ~CDS_VIDEOPARAMETERS;
1316 if (lParam == NULL)
1317 Ret=DISP_CHANGE_BADPARAM;
1318 else
1319 {
1320 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
1321 Ret = DISP_CHANGE_FAILED;
1322 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
1323 }
1324
1325 }
1326
1327 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
1328 {
1329
1330 UNICODE_STRING DeviceName;
1331 UNICODE_STRING RegistryKey;
1332 UNICODE_STRING InDeviceName;
1333 OBJECT_ATTRIBUTES ObjectAttributes;
1334 HANDLE DevInstRegKey;
1335 ULONG NewValue;
1336
1337 DPRINT1("set CDS_UPDATEREGISTRY\n");
1338
1339 dwflags &= ~CDS_UPDATEREGISTRY;
1340
1341 /* Check if pDeviceName is NULL, we need to retrieve it */
1342 if (pDeviceName == NULL)
1343 {
1344 WCHAR szBuffer[MAX_DRIVER_NAME];
1345 PDC DC;
1346 PWINDOW_OBJECT Wnd=NULL;
1347 HWND hWnd;
1348 HDC hDC;
1349
1350 hWnd = IntGetDesktopWindow();
1351 if (!(Wnd = UserGetWindowObject(hWnd)))
1352 {
1353 return FALSE;
1354 }
1355
1356 hDC = UserGetWindowDC(Wnd);
1357
1358 DC = DC_LockDc(hDC);
1359 if (NULL == DC)
1360 {
1361 return FALSE;
1362 }
1363 swprintf (szBuffer, L"\\\\.\\DISPLAY%lu", DC->ppdev->DisplayNumber);
1364 DC_UnlockDc(DC);
1365
1366 RtlInitUnicodeString(&InDeviceName, szBuffer);
1367 pDeviceName = &InDeviceName;
1368 }
1369
1370 Status = GetVideoDeviceName(&DeviceName, pDeviceName);
1371 if (!NT_SUCCESS(Status))
1372 {
1373 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName, Status);
1374 return DISP_CHANGE_FAILED;
1375 }
1376 Status = GetVideoRegistryKey(&RegistryKey, &DeviceName);
1377 if (!NT_SUCCESS(Status))
1378 {
1379 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName, Status);
1380 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
1381 return DISP_CHANGE_FAILED;
1382 }
1383 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
1384
1385 InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
1386 OBJ_CASE_INSENSITIVE, NULL, NULL);
1387 Status = ZwOpenKey(&DevInstRegKey, KEY_SET_VALUE, &ObjectAttributes);
1388 if (!NT_SUCCESS(Status))
1389 {
1390 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey, Status);
1391 ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
1392 return DISP_CHANGE_FAILED;
1393 }
1394 ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
1395
1396 /* Update needed fields */
1397 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
1398 {
1399 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
1400 NewValue = DevMode->dmBitsPerPel;
1401 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1402 }
1403
1404 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
1405 {
1406 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
1407 NewValue = DevMode->dmPelsWidth;
1408 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1409 }
1410
1411 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
1412 {
1413 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
1414 NewValue = DevMode->dmPelsHeight;
1415 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1416 }
1417
1418 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_DISPLAYFREQUENCY)
1419 {
1420 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.VRefresh");
1421 NewValue = DevMode->dmDisplayFrequency;
1422 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1423 }
1424
1425 ZwClose(DevInstRegKey);
1426 if (NT_SUCCESS(Status))
1427 Ret = DISP_CHANGE_RESTART;
1428 else
1429 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
1430 Ret = DISP_CHANGE_NOTUPDATED;
1431 }
1432
1433 if (dwflags != 0)
1434 Ret = DISP_CHANGE_BADFLAGS;
1435
1436 DPRINT("IntChangeDisplaySettings returning %x\n", Ret);
1437 return Ret;
1438 }
1439
1440
1441
1442 #define SIZEOF_DEVMODEW_300 188
1443 #define SIZEOF_DEVMODEW_400 212
1444 #define SIZEOF_DEVMODEW_500 220
1445
1446 static NTSTATUS FASTCALL
1447 GetDisplayNumberFromDeviceName(
1448 IN PUNICODE_STRING pDeviceName OPTIONAL,
1449 OUT ULONG *DisplayNumber)
1450 {
1451 UNICODE_STRING DisplayString = RTL_CONSTANT_STRING(L"\\\\.\\DISPLAY");
1452 NTSTATUS Status = STATUS_SUCCESS;
1453 ULONG Length;
1454 ULONG Number;
1455 ULONG i;
1456
1457 if (DisplayNumber == NULL)
1458 return STATUS_INVALID_PARAMETER_2;
1459
1460 /* Check if DeviceName is valid */
1461 if (pDeviceName &&
1462 pDeviceName->Length > 0 && pDeviceName->Length <= DisplayString.Length)
1463 return STATUS_OBJECT_NAME_INVALID;
1464
1465 if (pDeviceName == NULL || pDeviceName->Length == 0)
1466 {
1467 PWINDOW_OBJECT DesktopObject;
1468 HDC DesktopHDC;
1469 PDC pDC;
1470
1471 DesktopObject = UserGetDesktopWindow();
1472 DesktopHDC = UserGetWindowDC(DesktopObject);
1473 pDC = DC_LockDc(DesktopHDC);
1474
1475 *DisplayNumber = pDC->ppdev->DisplayNumber;
1476
1477 DC_UnlockDc(pDC);
1478 UserReleaseDC(DesktopObject, DesktopHDC, FALSE);
1479
1480 return STATUS_SUCCESS;
1481 }
1482
1483 /* Hack to check if the first parts are equal, by faking the device name length */
1484 Length = pDeviceName->Length;
1485 pDeviceName->Length = DisplayString.Length;
1486 if (RtlEqualUnicodeString(&DisplayString, pDeviceName, FALSE) == FALSE)
1487 Status = STATUS_OBJECT_NAME_INVALID;
1488 pDeviceName->Length = Length;
1489
1490 if (NT_SUCCESS(Status))
1491 {
1492 /* Convert the last part of pDeviceName to a number */
1493 Number = 0;
1494 Length = pDeviceName->Length / sizeof(WCHAR);
1495 for (i = DisplayString.Length / sizeof(WCHAR); i < Length; i++)
1496 {
1497 WCHAR Char = pDeviceName->Buffer[i];
1498 if (Char >= L'0' && Char <= L'9')
1499 Number = Number * 10 + Char - L'0';
1500 else if (Char != L'\0')
1501 return STATUS_OBJECT_NAME_INVALID;
1502 }
1503
1504 *DisplayNumber = Number - 1;
1505 }
1506
1507 return Status;
1508 }
1509
1510 /*! \brief Enumerate possible display settings for the given display...
1511 *
1512 * \todo Make thread safe!?
1513 * \todo Don't ignore pDeviceName
1514 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
1515 */
1516 NTSTATUS
1517 FASTCALL
1518 IntEnumDisplaySettings(
1519 IN PUNICODE_STRING pDeviceName OPTIONAL,
1520 IN DWORD iModeNum,
1521 IN OUT LPDEVMODEW pDevMode,
1522 IN DWORD dwFlags)
1523 {
1524 static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
1525 static DWORD SizeOfCachedDevModes = 0;
1526 static UNICODE_STRING CachedDeviceName;
1527 PDEVMODEW CachedMode = NULL;
1528 DEVMODEW DevMode;
1529 ULONG DisplayNumber;
1530 NTSTATUS Status;
1531
1532 Status = GetDisplayNumberFromDeviceName(pDeviceName, &DisplayNumber);
1533 if (!NT_SUCCESS(Status))
1534 {
1535 return Status;
1536 }
1537
1538 if (pDevMode != NULL)
1539 {
1540 DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
1541 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
1542 if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
1543 pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
1544 pDevMode->dmSize != SIZEOF_DEVMODEW_500)
1545 {
1546 return STATUS_BUFFER_TOO_SMALL;
1547 }
1548 }
1549
1550 if (iModeNum == ENUM_CURRENT_SETTINGS)
1551 {
1552 CachedMode = &PrimarySurface.DMW;
1553 ASSERT(CachedMode->dmSize > 0);
1554 }
1555 else if (iModeNum == ENUM_REGISTRY_SETTINGS)
1556 {
1557 RtlZeroMemory(&DevMode, sizeof (DevMode));
1558 DevMode.dmSize = sizeof (DevMode);
1559 DevMode.dmDriverExtra = 0;
1560 if (SetupDevMode(&DevMode, DisplayNumber))
1561 CachedMode = &DevMode;
1562 else
1563 {
1564 return STATUS_UNSUCCESSFUL; // FIXME: what status?
1565 }
1566 /* FIXME: Maybe look for the matching devmode supplied by the
1567 * driver so we can provide driver private/extra data?
1568 */
1569 }
1570 else
1571 {
1572 BOOL IsCachedDevice = (CachedDevModes != NULL);
1573
1574 if (CachedDevModes &&
1575 ((pDeviceName == NULL && CachedDeviceName.Length > 0) ||
1576 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length == 0) ||
1577 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length > 0 && RtlEqualUnicodeString(pDeviceName, &CachedDeviceName, TRUE) == FALSE)))
1578 {
1579 IsCachedDevice = FALSE;
1580 }
1581
1582 if (iModeNum == 0 || IsCachedDevice == FALSE) /* query modes from drivers */
1583 {
1584 UNICODE_STRING DriverFileNames;
1585 LPWSTR CurrentName;
1586 DRVENABLEDATA DrvEnableData;
1587
1588 /* Free resources from last driver cache */
1589 if (IsCachedDevice == FALSE && CachedDeviceName.Buffer != NULL)
1590 {
1591 RtlFreeUnicodeString(&CachedDeviceName);
1592 }
1593
1594 /* Retrieve DDI driver names from registry */
1595 RtlInitUnicodeString(&DriverFileNames, NULL);
1596 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
1597 {
1598 DPRINT1("FindDriverFileNames failed\n");
1599 return STATUS_UNSUCCESSFUL;
1600 }
1601
1602 if (!IntPrepareDriverIfNeeded())
1603 {
1604 DPRINT1("IntPrepareDriverIfNeeded failed\n");
1605 return STATUS_UNSUCCESSFUL;
1606 }
1607
1608 /*
1609 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
1610 * scan all of them until a good one found.
1611 */
1612 CurrentName = DriverFileNames.Buffer;
1613 for (;CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR));
1614 CurrentName += wcslen(CurrentName) + 1)
1615 {
1616 INT i;
1617 PFN_DrvEnableDriver GDEnableDriver;
1618 PFN_DrvGetModes GetModes = NULL;
1619 INT SizeNeeded, SizeUsed;
1620
1621 /* Get the DDI driver's entry point */
1622 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
1623 GDEnableDriver = DRIVER_FindExistingDDIDriver(L"DISPLAY");
1624 if (NULL == GDEnableDriver)
1625 {
1626 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
1627 continue;
1628 }
1629
1630 /* Call DDI driver's EnableDriver function */
1631 RtlZeroMemory(&DrvEnableData, sizeof(DrvEnableData));
1632
1633 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData))
1634 {
1635 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
1636 continue;
1637 }
1638
1639 CachedDevModesEnd = CachedDevModes;
1640
1641 /* find DrvGetModes function */
1642 for (i = 0; i < DrvEnableData.c; i++)
1643 {
1644 PDRVFN DrvFn = DrvEnableData.pdrvfn + i;
1645
1646 if (DrvFn->iFunc == INDEX_DrvGetModes)
1647 {
1648 GetModes = (PFN_DrvGetModes)DrvFn->pfn;
1649 break;
1650 }
1651 }
1652
1653 if (GetModes == NULL)
1654 {
1655 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName);
1656 continue;
1657 }
1658
1659 /* make sure we have enough memory to hold the modes */
1660 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL);
1661 if (SizeNeeded <= 0)
1662 {
1663 DPRINT("DrvGetModes failed for %S\n", CurrentName);
1664 break;
1665 }
1666
1667 SizeUsed = (PCHAR)CachedDevModesEnd - (PCHAR)CachedDevModes;
1668 if (SizeOfCachedDevModes < SizeUsed + SizeNeeded)
1669 {
1670 PVOID NewBuffer;
1671
1672 SizeOfCachedDevModes += SizeNeeded;
1673 NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes);
1674 if (NewBuffer == NULL)
1675 {
1676 /* clean up */
1677 ExFreePool(CachedDevModes);
1678 CachedDevModes = NULL;
1679 CachedDevModesEnd = NULL;
1680 SizeOfCachedDevModes = 0;
1681
1682 if (CachedDeviceName.Buffer != NULL)
1683 RtlFreeUnicodeString(&CachedDeviceName);
1684
1685 return STATUS_NO_MEMORY;
1686 }
1687 if (CachedDevModes != NULL)
1688 {
1689 RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed);
1690 ExFreePool(CachedDevModes);
1691 }
1692 CachedDevModes = NewBuffer;
1693 CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
1694 }
1695
1696 if (!IsCachedDevice)
1697 {
1698 if (CachedDeviceName.Buffer != NULL)
1699 RtlFreeUnicodeString(&CachedDeviceName);
1700
1701 if (pDeviceName)
1702 IntSafeCopyUnicodeString(&CachedDeviceName, pDeviceName);
1703
1704 IsCachedDevice = TRUE;
1705 }
1706
1707 /* query modes */
1708 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
1709 SizeNeeded,
1710 CachedDevModesEnd);
1711 if (SizeNeeded <= 0)
1712 {
1713 DPRINT("DrvGetModes failed for %S\n", CurrentName);
1714 }
1715 else
1716 {
1717 CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded);
1718 }
1719 }
1720
1721 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
1722 }
1723
1724 /* return cached info */
1725 CachedMode = CachedDevModes;
1726 if (CachedMode >= CachedDevModesEnd)
1727 {
1728 return STATUS_NO_MORE_ENTRIES;
1729 }
1730 while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd)
1731 {
1732 assert(CachedMode->dmSize > 0);
1733 CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra);
1734 }
1735 if (CachedMode >= CachedDevModesEnd)
1736 {
1737 return STATUS_NO_MORE_ENTRIES;
1738 }
1739 }
1740
1741 ASSERT(CachedMode != NULL);
1742
1743 if (pDevMode != NULL)
1744 {
1745 RtlCopyMemory(pDevMode, CachedMode, min(pDevMode->dmSize, CachedMode->dmSize));
1746 RtlZeroMemory(pDevMode + pDevMode->dmSize, pDevMode->dmDriverExtra);
1747 RtlCopyMemory(pDevMode + min(pDevMode->dmSize, CachedMode->dmSize), CachedMode + CachedMode->dmSize, min(pDevMode->dmDriverExtra, CachedMode->dmDriverExtra));
1748 }
1749
1750 return STATUS_SUCCESS;
1751 }
1752
1753 INT
1754 APIENTRY
1755 NtGdiDrawEscape(
1756 IN HDC hdc,
1757 IN INT iEsc,
1758 IN INT cjIn,
1759 IN OPTIONAL LPSTR pjIn)
1760 {
1761 UNIMPLEMENTED;
1762 return 0;
1763 }
1764