6dfe195ec0cb920963a7794fd41144e262498937
[reactos.git] / 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(VOID)
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, gdwDirectDrawContext + 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.dhpdev = PrimarySurface.DriverFunctions.EnablePDEV(
324 &PrimarySurface.DMW,
325 L"",
326 HS_DDI_MAX,
327 PrimarySurface.ahsurf,
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.dhpdev);
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.dhpdev = PrimarySurface.DriverFunctions.EnablePDEV(
351 &PrimarySurface.DMW,
352 L"",
353 HS_DDI_MAX,
354 PrimarySurface.ahsurf,
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.dhpdev)
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.dhpdev,
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.pGraphicsDevice = 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(VOID)
441 {
442 return (PrimarySurface.PreparedDriver ? TRUE : IntPrepareDriver());
443 }
444
445 static BOOL FASTCALL
446 PrepareVideoPrt(VOID)
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(VOID)
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.dhpdev);
523 if (NULL == PrimarySurface.pSurface)
524 {
525 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);*/
526 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.dhpdev);
527 ObDereferenceObject(PrimarySurface.VideoFileObject);
528 DPRINT1("DrvEnableSurface failed\n");
529 return FALSE;
530 }
531
532 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, 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.dhpdev;
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(VOID)
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.dhpdev, FALSE);
603 PrimarySurface.DriverFunctions.DisableSurface(PrimarySurface.dhpdev);
604 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.dhpdev);
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->dhpdev, 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->pGraphicsDevice &&
760 (((PGRAPHICS_DEVICE)ppdev->pGraphicsDevice)->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->dhpdev;
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 = DISP_CHANGE_SUCCESSFUL;
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 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
1233 return DISP_CHANGE_FAILED;
1234 }
1235
1236 if ((dwflags & CDS_TEST) == CDS_TEST)
1237 {
1238 /* Test resolution */
1239 dwflags &= ~CDS_TEST;
1240 Status = IntEnumDisplaySettings(pDeviceName, ENUM_REGISTRY_SETTINGS, DevMode, 0);
1241 if (!NT_SUCCESS(Status))
1242 Ret = DISP_CHANGE_BADMODE;
1243 return Ret;
1244 }
1245
1246 if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
1247 {
1248 DEVMODEW lpDevMode;
1249 /* Full Screen */
1250 dwflags &= ~CDS_FULLSCREEN;
1251 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
1252 Ret = DISP_CHANGE_FAILED;
1253
1254 RtlZeroMemory(&lpDevMode, sizeof(DEVMODEW));
1255 lpDevMode.dmSize = sizeof(DEVMODEW);
1256
1257 Status = IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0);
1258 if (!NT_SUCCESS(Status))
1259 return DISP_CHANGE_FAILED;
1260
1261 DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
1262 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
1263
1264
1265 if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
1266 (lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) &&
1267 (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
1268 Ret = DISP_CHANGE_SUCCESSFUL;
1269 }
1270
1271 if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
1272 {
1273 dwflags &= ~CDS_VIDEOPARAMETERS;
1274 if (lParam == NULL)
1275 Ret=DISP_CHANGE_BADPARAM;
1276 else
1277 {
1278 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
1279 Ret = DISP_CHANGE_FAILED;
1280 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
1281 }
1282
1283 }
1284
1285 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
1286 {
1287
1288 UNICODE_STRING DeviceName;
1289 UNICODE_STRING RegistryKey;
1290 UNICODE_STRING InDeviceName;
1291 OBJECT_ATTRIBUTES ObjectAttributes;
1292 HANDLE DevInstRegKey;
1293 ULONG NewValue;
1294
1295 DPRINT1("set CDS_UPDATEREGISTRY\n");
1296
1297 dwflags &= ~CDS_UPDATEREGISTRY;
1298
1299 /* Check if pDeviceName is NULL, we need to retrieve it */
1300 if (pDeviceName == NULL)
1301 {
1302 WCHAR szBuffer[MAX_DRIVER_NAME];
1303 PDC DC;
1304 PWINDOW_OBJECT Wnd=NULL;
1305 HWND hWnd;
1306 HDC hDC;
1307
1308 hWnd = IntGetDesktopWindow();
1309 if (!(Wnd = UserGetWindowObject(hWnd)))
1310 {
1311 return FALSE;
1312 }
1313
1314 hDC = UserGetWindowDC(Wnd);
1315
1316 DC = DC_LockDc(hDC);
1317 if (NULL == DC)
1318 {
1319 return FALSE;
1320 }
1321 swprintf (szBuffer, L"\\\\.\\DISPLAY%lu", DC->ppdev->DisplayNumber);
1322 DC_UnlockDc(DC);
1323
1324 RtlInitUnicodeString(&InDeviceName, szBuffer);
1325 pDeviceName = &InDeviceName;
1326 }
1327
1328 Status = GetVideoDeviceName(&DeviceName, pDeviceName);
1329 if (!NT_SUCCESS(Status))
1330 {
1331 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName, Status);
1332 return DISP_CHANGE_FAILED;
1333 }
1334 Status = GetVideoRegistryKey(&RegistryKey, &DeviceName);
1335 if (!NT_SUCCESS(Status))
1336 {
1337 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName, Status);
1338 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
1339 return DISP_CHANGE_FAILED;
1340 }
1341 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
1342
1343 InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
1344 OBJ_CASE_INSENSITIVE, NULL, NULL);
1345 Status = ZwOpenKey(&DevInstRegKey, KEY_SET_VALUE, &ObjectAttributes);
1346 if (!NT_SUCCESS(Status))
1347 {
1348 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey, Status);
1349 ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
1350 return DISP_CHANGE_FAILED;
1351 }
1352 ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
1353
1354 /* Update needed fields */
1355 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
1356 {
1357 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
1358 NewValue = DevMode->dmBitsPerPel;
1359 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1360 }
1361
1362 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
1363 {
1364 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
1365 NewValue = DevMode->dmPelsWidth;
1366 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1367 }
1368
1369 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
1370 {
1371 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
1372 NewValue = DevMode->dmPelsHeight;
1373 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1374 }
1375
1376 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_DISPLAYFREQUENCY)
1377 {
1378 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.VRefresh");
1379 NewValue = DevMode->dmDisplayFrequency;
1380 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
1381 }
1382
1383 ZwClose(DevInstRegKey);
1384 if (NT_SUCCESS(Status))
1385 Ret = DISP_CHANGE_RESTART;
1386 else
1387 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
1388 Ret = DISP_CHANGE_NOTUPDATED;
1389 }
1390
1391 if (dwflags != 0)
1392 Ret = DISP_CHANGE_BADFLAGS;
1393
1394 DPRINT("IntChangeDisplaySettings returning %x\n", Ret);
1395 return Ret;
1396 }
1397
1398
1399
1400 #define SIZEOF_DEVMODEW_300 188
1401 #define SIZEOF_DEVMODEW_400 212
1402 #define SIZEOF_DEVMODEW_500 220
1403
1404 static NTSTATUS FASTCALL
1405 GetDisplayNumberFromDeviceName(
1406 IN PUNICODE_STRING pDeviceName OPTIONAL,
1407 OUT ULONG *DisplayNumber)
1408 {
1409 UNICODE_STRING DisplayString = RTL_CONSTANT_STRING(L"\\\\.\\DISPLAY");
1410 NTSTATUS Status = STATUS_SUCCESS;
1411 ULONG Length;
1412 ULONG Number;
1413 ULONG i;
1414
1415 if (DisplayNumber == NULL)
1416 return STATUS_INVALID_PARAMETER_2;
1417
1418 /* Check if DeviceName is valid */
1419 if (pDeviceName &&
1420 pDeviceName->Length > 0 && pDeviceName->Length <= DisplayString.Length)
1421 return STATUS_OBJECT_NAME_INVALID;
1422
1423 if (pDeviceName == NULL || pDeviceName->Length == 0)
1424 {
1425 PWINDOW_OBJECT DesktopObject;
1426 HDC DesktopHDC;
1427 PDC pDC;
1428
1429 DesktopObject = UserGetDesktopWindow();
1430 DesktopHDC = UserGetWindowDC(DesktopObject);
1431 pDC = DC_LockDc(DesktopHDC);
1432
1433 *DisplayNumber = pDC->ppdev->DisplayNumber;
1434
1435 DC_UnlockDc(pDC);
1436 UserReleaseDC(DesktopObject, DesktopHDC, FALSE);
1437
1438 return STATUS_SUCCESS;
1439 }
1440
1441 /* Hack to check if the first parts are equal, by faking the device name length */
1442 Length = pDeviceName->Length;
1443 pDeviceName->Length = DisplayString.Length;
1444 if (RtlEqualUnicodeString(&DisplayString, pDeviceName, FALSE) == FALSE)
1445 Status = STATUS_OBJECT_NAME_INVALID;
1446 pDeviceName->Length = Length;
1447
1448 if (NT_SUCCESS(Status))
1449 {
1450 /* Convert the last part of pDeviceName to a number */
1451 Number = 0;
1452 Length = pDeviceName->Length / sizeof(WCHAR);
1453 for (i = DisplayString.Length / sizeof(WCHAR); i < Length; i++)
1454 {
1455 WCHAR Char = pDeviceName->Buffer[i];
1456 if (Char >= L'0' && Char <= L'9')
1457 Number = Number * 10 + Char - L'0';
1458 else if (Char != L'\0')
1459 return STATUS_OBJECT_NAME_INVALID;
1460 }
1461
1462 *DisplayNumber = Number - 1;
1463 }
1464
1465 return Status;
1466 }
1467
1468 /*! \brief Enumerate possible display settings for the given display...
1469 *
1470 * \todo Make thread safe!?
1471 * \todo Don't ignore pDeviceName
1472 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
1473 */
1474 NTSTATUS
1475 FASTCALL
1476 IntEnumDisplaySettings(
1477 IN PUNICODE_STRING pDeviceName OPTIONAL,
1478 IN DWORD iModeNum,
1479 IN OUT LPDEVMODEW pDevMode,
1480 IN DWORD dwFlags)
1481 {
1482 static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
1483 static DWORD SizeOfCachedDevModes = 0;
1484 static UNICODE_STRING CachedDeviceName;
1485 PDEVMODEW CachedMode = NULL;
1486 DEVMODEW DevMode;
1487 ULONG DisplayNumber;
1488 NTSTATUS Status;
1489
1490 Status = GetDisplayNumberFromDeviceName(pDeviceName, &DisplayNumber);
1491 if (!NT_SUCCESS(Status))
1492 {
1493 return Status;
1494 }
1495
1496 if (pDevMode != NULL)
1497 {
1498 DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
1499 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
1500 if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
1501 pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
1502 pDevMode->dmSize != SIZEOF_DEVMODEW_500)
1503 {
1504 return STATUS_BUFFER_TOO_SMALL;
1505 }
1506 }
1507
1508 if (iModeNum == ENUM_CURRENT_SETTINGS)
1509 {
1510 CachedMode = &PrimarySurface.DMW;
1511 ASSERT(CachedMode->dmSize > 0);
1512 }
1513 else if (iModeNum == ENUM_REGISTRY_SETTINGS)
1514 {
1515 RtlZeroMemory(&DevMode, sizeof (DevMode));
1516 DevMode.dmSize = sizeof (DevMode);
1517 DevMode.dmDriverExtra = 0;
1518 if (SetupDevMode(&DevMode, DisplayNumber))
1519 CachedMode = &DevMode;
1520 else
1521 {
1522 return STATUS_UNSUCCESSFUL; // FIXME: what status?
1523 }
1524 /* FIXME: Maybe look for the matching devmode supplied by the
1525 * driver so we can provide driver private/extra data?
1526 */
1527 }
1528 else
1529 {
1530 BOOL IsCachedDevice = (CachedDevModes != NULL);
1531
1532 if (CachedDevModes &&
1533 ((pDeviceName == NULL && CachedDeviceName.Length > 0) ||
1534 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length == 0) ||
1535 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length > 0 && RtlEqualUnicodeString(pDeviceName, &CachedDeviceName, TRUE) == FALSE)))
1536 {
1537 IsCachedDevice = FALSE;
1538 }
1539
1540 if (iModeNum == 0 || IsCachedDevice == FALSE) /* query modes from drivers */
1541 {
1542 UNICODE_STRING DriverFileNames;
1543 LPWSTR CurrentName;
1544 DRVENABLEDATA DrvEnableData;
1545
1546 /* Free resources from last driver cache */
1547 if (IsCachedDevice == FALSE && CachedDeviceName.Buffer != NULL)
1548 {
1549 RtlFreeUnicodeString(&CachedDeviceName);
1550 }
1551
1552 /* Retrieve DDI driver names from registry */
1553 RtlInitUnicodeString(&DriverFileNames, NULL);
1554 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
1555 {
1556 DPRINT1("FindDriverFileNames failed\n");
1557 return STATUS_UNSUCCESSFUL;
1558 }
1559
1560 if (!IntPrepareDriverIfNeeded())
1561 {
1562 DPRINT1("IntPrepareDriverIfNeeded failed\n");
1563 return STATUS_UNSUCCESSFUL;
1564 }
1565
1566 /*
1567 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
1568 * scan all of them until a good one found.
1569 */
1570 CurrentName = DriverFileNames.Buffer;
1571 for (;CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR));
1572 CurrentName += wcslen(CurrentName) + 1)
1573 {
1574 INT i;
1575 PFN_DrvEnableDriver GDEnableDriver;
1576 PFN_DrvGetModes GetModes = NULL;
1577 INT SizeNeeded, SizeUsed;
1578
1579 /* Get the DDI driver's entry point */
1580 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
1581 GDEnableDriver = DRIVER_FindExistingDDIDriver(L"DISPLAY");
1582 if (NULL == GDEnableDriver)
1583 {
1584 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
1585 continue;
1586 }
1587
1588 /* Call DDI driver's EnableDriver function */
1589 RtlZeroMemory(&DrvEnableData, sizeof(DrvEnableData));
1590
1591 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData))
1592 {
1593 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
1594 continue;
1595 }
1596
1597 CachedDevModesEnd = CachedDevModes;
1598
1599 /* find DrvGetModes function */
1600 for (i = 0; i < DrvEnableData.c; i++)
1601 {
1602 PDRVFN DrvFn = DrvEnableData.pdrvfn + i;
1603
1604 if (DrvFn->iFunc == INDEX_DrvGetModes)
1605 {
1606 GetModes = (PFN_DrvGetModes)DrvFn->pfn;
1607 break;
1608 }
1609 }
1610
1611 if (GetModes == NULL)
1612 {
1613 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName);
1614 continue;
1615 }
1616
1617 /* make sure we have enough memory to hold the modes */
1618 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL);
1619 if (SizeNeeded <= 0)
1620 {
1621 DPRINT("DrvGetModes failed for %S\n", CurrentName);
1622 break;
1623 }
1624
1625 SizeUsed = (PCHAR)CachedDevModesEnd - (PCHAR)CachedDevModes;
1626 if (SizeOfCachedDevModes < SizeUsed + SizeNeeded)
1627 {
1628 PVOID NewBuffer;
1629
1630 SizeOfCachedDevModes += SizeNeeded;
1631 NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes);
1632 if (NewBuffer == NULL)
1633 {
1634 /* clean up */
1635 ExFreePool(CachedDevModes);
1636 CachedDevModes = NULL;
1637 CachedDevModesEnd = NULL;
1638 SizeOfCachedDevModes = 0;
1639
1640 if (CachedDeviceName.Buffer != NULL)
1641 RtlFreeUnicodeString(&CachedDeviceName);
1642
1643 return STATUS_NO_MEMORY;
1644 }
1645 if (CachedDevModes != NULL)
1646 {
1647 RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed);
1648 ExFreePool(CachedDevModes);
1649 }
1650 CachedDevModes = NewBuffer;
1651 CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
1652 }
1653
1654 if (!IsCachedDevice)
1655 {
1656 if (CachedDeviceName.Buffer != NULL)
1657 RtlFreeUnicodeString(&CachedDeviceName);
1658
1659 if (pDeviceName)
1660 IntSafeCopyUnicodeString(&CachedDeviceName, pDeviceName);
1661
1662 IsCachedDevice = TRUE;
1663 }
1664
1665 /* query modes */
1666 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
1667 SizeNeeded,
1668 CachedDevModesEnd);
1669 if (SizeNeeded <= 0)
1670 {
1671 DPRINT("DrvGetModes failed for %S\n", CurrentName);
1672 }
1673 else
1674 {
1675 CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded);
1676 }
1677 }
1678
1679 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
1680 }
1681
1682 /* return cached info */
1683 CachedMode = CachedDevModes;
1684 if (CachedMode >= CachedDevModesEnd)
1685 {
1686 return STATUS_NO_MORE_ENTRIES;
1687 }
1688 while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd)
1689 {
1690 assert(CachedMode->dmSize > 0);
1691 CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra);
1692 }
1693 if (CachedMode >= CachedDevModesEnd)
1694 {
1695 return STATUS_NO_MORE_ENTRIES;
1696 }
1697 }
1698
1699 ASSERT(CachedMode != NULL);
1700
1701 if (pDevMode != NULL)
1702 {
1703 RtlCopyMemory(pDevMode, CachedMode, min(pDevMode->dmSize, CachedMode->dmSize));
1704 RtlZeroMemory(pDevMode + pDevMode->dmSize, pDevMode->dmDriverExtra);
1705 RtlCopyMemory(pDevMode + min(pDevMode->dmSize, CachedMode->dmSize), CachedMode + CachedMode->dmSize, min(pDevMode->dmDriverExtra, CachedMode->dmDriverExtra));
1706 }
1707
1708 return STATUS_SUCCESS;
1709 }
1710
1711 INT
1712 APIENTRY
1713 NtGdiDrawEscape(
1714 IN HDC hdc,
1715 IN INT iEsc,
1716 IN INT cjIn,
1717 IN OPTIONAL LPSTR pjIn)
1718 {
1719 UNIMPLEMENTED;
1720 return 0;
1721 }
1722