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