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