Enable
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dc.c
1
2 /*
3 * ReactOS W32 Subsystem
4 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21 * DC.C - Device context functions
22 *
23 */
24
25 #include <w32k.h>
26 #include <bugcodes.h>
27
28 #define NDEBUG
29 #include <debug.h>
30
31 static GDIDEVICE PrimarySurface;
32 static KEVENT VideoDriverNeedsPreparation;
33 static KEVENT VideoDriverPrepared;
34
35
36 NTSTATUS FASTCALL
37 InitDcImpl(VOID)
38 {
39 KeInitializeEvent(&VideoDriverNeedsPreparation, SynchronizationEvent, TRUE);
40 KeInitializeEvent(&VideoDriverPrepared, NotificationEvent, FALSE);
41 return STATUS_SUCCESS;
42 }
43
44 /* FIXME: DCs should probably be thread safe */
45
46 // --------------------------------------------------------- File Statics
47
48 // ----------------------------------------------------- Public Functions
49
50 BOOL STDCALL
51 NtGdiCancelDC(HDC hDC)
52 {
53 UNIMPLEMENTED;
54 return FALSE;
55 }
56
57 HDC STDCALL
58 NtGdiCreateCompatibleDC(HDC hDC)
59 {
60 PDC NewDC, OrigDC;
61 PDC_ATTR nDc_Attr, oDc_Attr;
62 HBITMAP hBitmap;
63 HDC hNewDC, DisplayDC;
64 HRGN hVisRgn;
65 UNICODE_STRING DriverName;
66 DWORD Layout = 0;
67
68 DisplayDC = NULL;
69 if (hDC == NULL)
70 {
71 RtlInitUnicodeString(&DriverName, L"DISPLAY");
72 DisplayDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, TRUE);
73 if (NULL == DisplayDC)
74 {
75 return NULL;
76 }
77 hDC = DisplayDC;
78 }
79
80 /* Allocate a new DC based on the original DC's device */
81 OrigDC = DC_LockDc(hDC);
82 if (NULL == OrigDC)
83 {
84 if (NULL != DisplayDC)
85 {
86 NtGdiDeleteObjectApp(DisplayDC);
87 }
88 return NULL;
89 }
90 hNewDC = DC_AllocDC(&OrigDC->DriverName);
91 if (NULL == hNewDC)
92 {
93 DC_UnlockDc(OrigDC);
94 if (NULL != DisplayDC)
95 {
96 NtGdiDeleteObjectApp(DisplayDC);
97 }
98 return NULL;
99 }
100 NewDC = DC_LockDc( hNewDC );
101
102 oDc_Attr = OrigDC->pDc_Attr;
103 if(!oDc_Attr) oDc_Attr = &OrigDC->Dc_Attr;
104 nDc_Attr = NewDC->pDc_Attr;
105 if(!nDc_Attr) nDc_Attr = &NewDC->Dc_Attr;
106
107 /* Copy information from original DC to new DC */
108 NewDC->hSelf = hNewDC;
109
110 NewDC->PDev = OrigDC->PDev;
111
112 NewDC->w.bitsPerPixel = OrigDC->w.bitsPerPixel;
113
114 /* DriverName is copied in the AllocDC routine */
115 nDc_Attr->ptlWindowOrg = oDc_Attr->ptlWindowOrg;
116 nDc_Attr->szlWindowExt = oDc_Attr->szlWindowExt;
117 nDc_Attr->ptlViewportOrg = oDc_Attr->ptlViewportOrg;
118 nDc_Attr->szlViewportExt = oDc_Attr->szlViewportExt;
119
120 /* Create default bitmap */
121 if (!(hBitmap = IntGdiCreateBitmap( 1, 1, 1, NewDC->w.bitsPerPixel, NULL )))
122 {
123 DC_UnlockDc( OrigDC );
124 DC_UnlockDc( NewDC );
125 DC_FreeDC( hNewDC );
126 if (NULL != DisplayDC)
127 {
128 NtGdiDeleteObjectApp(DisplayDC);
129 }
130 return NULL;
131 }
132 NewDC->DC_Type = DC_TYPE_MEMORY; // Always!
133 NewDC->w.hBitmap = hBitmap;
134 NewDC->w.hFirstBitmap = hBitmap;
135 NewDC->pPDev = OrigDC->pPDev;
136
137 NewDC->PalIndexed = OrigDC->PalIndexed;
138 NewDC->w.hPalette = OrigDC->w.hPalette;
139 nDc_Attr->lTextAlign = oDc_Attr->lTextAlign;
140 nDc_Attr->ulForegroundClr = oDc_Attr->ulForegroundClr;
141 nDc_Attr->ulBackgroundClr = oDc_Attr->ulBackgroundClr;
142 nDc_Attr->lBkMode = oDc_Attr->lBkMode;
143 nDc_Attr->crForegroundClr = oDc_Attr->crForegroundClr;
144 nDc_Attr->crBackgroundClr = oDc_Attr->crBackgroundClr;
145 nDc_Attr->jBkMode = oDc_Attr->jBkMode;
146 nDc_Attr->jROP2 = oDc_Attr->jROP2;
147 nDc_Attr->dwLayout = oDc_Attr->dwLayout;
148 if (oDc_Attr->dwLayout & LAYOUT_ORIENTATIONMASK) Layout = oDc_Attr->dwLayout;
149
150 DC_UnlockDc(NewDC);
151 DC_UnlockDc(OrigDC);
152 if (NULL != DisplayDC)
153 {
154 NtGdiDeleteObjectApp(DisplayDC);
155 }
156
157 hVisRgn = NtGdiCreateRectRgn(0, 0, 1, 1);
158 IntGdiSelectVisRgn(hNewDC, hVisRgn);
159 NtGdiDeleteObject(hVisRgn);
160 if (Layout) NtGdiSetLayout( hNewDC, -1, Layout);
161
162 DC_InitDC(hNewDC);
163 return hNewDC;
164 }
165
166 static BOOLEAN FASTCALL
167 GetRegistryPath(PUNICODE_STRING RegistryPath, ULONG DisplayNumber)
168 {
169 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
170 WCHAR DeviceNameBuffer[20];
171 NTSTATUS Status;
172
173 swprintf(DeviceNameBuffer, L"\\Device\\Video%lu", DisplayNumber);
174 RtlInitUnicodeString(RegistryPath, NULL);
175 RtlZeroMemory(QueryTable, sizeof(QueryTable));
176 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
177 QueryTable[0].Name = DeviceNameBuffer;
178 QueryTable[0].EntryContext = RegistryPath;
179
180 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
181 L"VIDEO",
182 QueryTable,
183 NULL,
184 NULL);
185 if (! NT_SUCCESS(Status))
186 {
187 DPRINT1("No \\Device\\Video%lu value in DEVICEMAP\\VIDEO found\n", DisplayNumber);
188 return FALSE;
189 }
190
191 DPRINT("RegistryPath %wZ\n", RegistryPath);
192
193 return TRUE;
194 }
195
196 static BOOL FASTCALL
197 FindDriverFileNames(PUNICODE_STRING DriverFileNames, ULONG DisplayNumber)
198 {
199 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
200 UNICODE_STRING RegistryPath;
201 NTSTATUS Status;
202
203 if (! GetRegistryPath(&RegistryPath, DisplayNumber))
204 {
205 DPRINT("GetRegistryPath failed\n");
206 return FALSE;
207 }
208
209 RtlZeroMemory(QueryTable, sizeof(QueryTable));
210 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
211 QueryTable[0].Name = L"InstalledDisplayDrivers";
212 QueryTable[0].EntryContext = DriverFileNames;
213
214 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
215 RegistryPath.Buffer,
216 QueryTable,
217 NULL,
218 NULL);
219 RtlFreeUnicodeString(&RegistryPath);
220 if (! NT_SUCCESS(Status))
221 {
222 DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
223 return FALSE;
224 }
225
226 DPRINT("DriverFileNames %S\n", DriverFileNames->Buffer);
227
228 return TRUE;
229 }
230
231 static NTSTATUS STDCALL
232 DevModeCallback(IN PWSTR ValueName,
233 IN ULONG ValueType,
234 IN PVOID ValueData,
235 IN ULONG ValueLength,
236 IN PVOID Context,
237 IN PVOID EntryContext)
238 {
239 PDEVMODEW DevMode = (PDEVMODEW) Context;
240
241 DPRINT("Found registry value for name %S: type %d, length %d\n",
242 ValueName, ValueType, ValueLength);
243
244 if (REG_DWORD == ValueType && sizeof(DWORD) == ValueLength)
245 {
246 if (0 == _wcsicmp(ValueName, L"DefaultSettings.BitsPerPel"))
247 {
248 DevMode->dmBitsPerPel = *((DWORD *) ValueData);
249 }
250 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.Flags"))
251 {
252 DevMode->dmDisplayFlags = *((DWORD *) ValueData);
253 }
254 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.VRefresh"))
255 {
256 DevMode->dmDisplayFrequency = *((DWORD *) ValueData);
257 }
258 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XPanning"))
259 {
260 DevMode->dmPanningWidth = *((DWORD *) ValueData);
261 }
262 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XResolution"))
263 {
264 DevMode->dmPelsWidth = *((DWORD *) ValueData);
265 }
266 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YPanning"))
267 {
268 DevMode->dmPanningHeight = *((DWORD *) ValueData);
269 }
270 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YResolution"))
271 {
272 DevMode->dmPelsHeight = *((DWORD *) ValueData);
273 }
274 }
275
276 return STATUS_SUCCESS;
277 }
278
279 static BOOL FASTCALL
280 SetupDevMode(PDEVMODEW DevMode, ULONG DisplayNumber)
281 {
282 UNICODE_STRING RegistryPath;
283 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
284 NTSTATUS Status;
285 BOOLEAN Valid = TRUE;
286
287 if (!GetRegistryPath(&RegistryPath, DisplayNumber))
288 {
289 DPRINT("GetRegistryPath failed\n");
290 return FALSE;
291 }
292
293 RtlZeroMemory(QueryTable, sizeof(QueryTable));
294 QueryTable[0].QueryRoutine = DevModeCallback;
295 QueryTable[0].Flags = 0;
296 QueryTable[0].Name = NULL;
297 QueryTable[0].EntryContext = NULL;
298 QueryTable[0].DefaultType = REG_NONE;
299 QueryTable[0].DefaultData = NULL;
300 QueryTable[0].DefaultLength = 0;
301
302 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
303 RegistryPath.Buffer,
304 QueryTable,
305 DevMode,
306 NULL);
307 if (! NT_SUCCESS(Status))
308 {
309 DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
310 &RegistryPath, Status);
311 Valid = FALSE;
312 }
313 else
314 {
315 DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
316 DevMode->dmBitsPerPel, DevMode->dmDisplayFrequency,
317 DevMode->dmPelsWidth, DevMode->dmPelsHeight);
318 if (0 == DevMode->dmBitsPerPel || 0 == DevMode->dmDisplayFrequency
319 || 0 == DevMode->dmPelsWidth || 0 == DevMode->dmPelsHeight)
320 {
321 DPRINT("Not all required devmode members are set\n");
322 Valid = FALSE;
323 }
324 }
325
326 RtlFreeUnicodeString(&RegistryPath);
327
328 if (! Valid)
329 {
330 RtlZeroMemory(DevMode, sizeof(DEVMODEW));
331 }
332
333 return Valid;
334 }
335
336 static BOOL FASTCALL
337 IntPrepareDriver()
338 {
339 PGD_ENABLEDRIVER GDEnableDriver;
340 DRVENABLEDATA DED;
341 UNICODE_STRING DriverFileNames;
342 PWSTR CurrentName;
343 BOOL GotDriver;
344 BOOL DoDefault;
345 ULONG DisplayNumber;
346 LARGE_INTEGER Zero;
347 BOOLEAN ret = FALSE;
348
349 Zero.QuadPart = 0;
350 if (STATUS_SUCCESS != KeWaitForSingleObject(&VideoDriverNeedsPreparation, Executive, KernelMode, TRUE, &Zero))
351 {
352 /* Concurrent access. Wait for VideoDriverPrepared event */
353 if (STATUS_SUCCESS == KeWaitForSingleObject(&VideoDriverPrepared, Executive, KernelMode, TRUE, NULL))
354 ret = PrimarySurface.PreparedDriver;
355 goto cleanup;
356 }
357 // HAX! Fixme so I can support more than one! So how many?
358 for (DisplayNumber = 0; ; DisplayNumber++)
359 {
360 DPRINT("Trying to load display driver no. %d\n", DisplayNumber);
361
362 RtlZeroMemory(&PrimarySurface, sizeof(PrimarySurface));
363
364 PrimarySurface.VideoFileObject = DRIVER_FindMPDriver(DisplayNumber);
365
366 /* Open the miniport driver */
367 if (PrimarySurface.VideoFileObject == NULL)
368 {
369 DPRINT1("FindMPDriver failed\n");
370 goto cleanup;
371 }
372
373 /* Retrieve DDI driver names from registry */
374 RtlInitUnicodeString(&DriverFileNames, NULL);
375 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
376 {
377 DPRINT1("FindDriverFileNames failed\n");
378 continue;
379 }
380
381 /*
382 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
383 * scan all of them until a good one found.
384 */
385 CurrentName = DriverFileNames.Buffer;
386 GotDriver = FALSE;
387 while (!GotDriver &&
388 CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
389 {
390 /* Get the DDI driver's entry point */
391 GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
392 if (NULL == GDEnableDriver)
393 {
394 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
395 }
396 else
397 {
398 /* Call DDI driver's EnableDriver function */
399 RtlZeroMemory(&DED, sizeof(DED));
400
401 if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof(DED), &DED))
402 {
403 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
404 }
405 else
406 {
407 GotDriver = TRUE;
408 }
409 }
410
411 if (! GotDriver)
412 {
413 /* Skip to the next name but never get past the Unicode string */
414 while (L'\0' != *CurrentName &&
415 CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
416 {
417 CurrentName++;
418 }
419 if (CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
420 {
421 CurrentName++;
422 }
423 }
424 }
425
426 if (!GotDriver)
427 {
428 ObDereferenceObject(PrimarySurface.VideoFileObject);
429 RtlFreeUnicodeString(&DriverFileNames);
430 DPRINT1("No suitable DDI driver found\n");
431 continue;
432 }
433
434 DPRINT("Display driver %S loaded\n", CurrentName);
435
436 RtlFreeUnicodeString(&DriverFileNames);
437
438 DPRINT("Building DDI Functions\n");
439
440 /* Construct DDI driver function dispatch table */
441 if (!DRIVER_BuildDDIFunctions(&DED, &PrimarySurface.DriverFunctions))
442 {
443 ObDereferenceObject(PrimarySurface.VideoFileObject);
444 DPRINT1("BuildDDIFunctions failed\n");
445 goto cleanup;
446 }
447
448 /* Allocate a phyical device handle from the driver */
449 // Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
450 PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
451 if (SetupDevMode(&PrimarySurface.DMW, DisplayNumber))
452 {
453 PrimarySurface.hPDev = PrimarySurface.DriverFunctions.EnablePDEV(
454 &PrimarySurface.DMW,
455 L"",
456 HS_DDI_MAX,
457 PrimarySurface.FillPatterns,
458 sizeof(PrimarySurface.GDIInfo),
459 (ULONG *) &PrimarySurface.GDIInfo,
460 sizeof(PrimarySurface.DevInfo),
461 &PrimarySurface.DevInfo,
462 NULL,
463 L"",
464 (HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
465 DoDefault = (NULL == PrimarySurface.hPDev);
466 if (DoDefault)
467 {
468 DPRINT1("DrvEnablePDev with registry parameters failed\n");
469 }
470 }
471 else
472 {
473 DoDefault = TRUE;
474 }
475
476 if (DoDefault)
477 {
478 RtlZeroMemory(&(PrimarySurface.DMW), sizeof(DEVMODEW));
479 PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
480 PrimarySurface.hPDev = PrimarySurface.DriverFunctions.EnablePDEV(
481 &PrimarySurface.DMW,
482 L"",
483 HS_DDI_MAX,
484 PrimarySurface.FillPatterns,
485 sizeof(PrimarySurface.GDIInfo),
486 (ULONG *) &PrimarySurface.GDIInfo,
487 sizeof(PrimarySurface.DevInfo),
488 &PrimarySurface.DevInfo,
489 NULL,
490 L"",
491 (HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
492
493 if (NULL == PrimarySurface.hPDev)
494 {
495 ObDereferenceObject(PrimarySurface.VideoFileObject);
496 DPRINT1("DrvEnablePDEV with default parameters failed\n");
497 DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
498 continue;
499 }
500
501 // Update the primary surface with what we really got
502 PrimarySurface.DMW.dmPelsWidth = PrimarySurface.GDIInfo.ulHorzRes;
503 PrimarySurface.DMW.dmPelsHeight = PrimarySurface.GDIInfo.ulVertRes;
504 PrimarySurface.DMW.dmBitsPerPel = PrimarySurface.GDIInfo.cBitsPixel;
505 PrimarySurface.DMW.dmDisplayFrequency = PrimarySurface.GDIInfo.ulVRefresh;
506 }
507
508 if (!PrimarySurface.DMW.dmDriverExtra)
509 {
510 PrimarySurface.pdmwDev = &PrimarySurface.DMW; // HAX!
511 }
512 else
513 {
514 DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
515 }
516 // Dont remove until we finish testing other drivers.
517 DPRINT1("DMW extra %x !!!!!!\n",PrimarySurface.DMW.dmDriverExtra);
518
519 if (0 == PrimarySurface.GDIInfo.ulLogPixelsX)
520 {
521 DPRINT("Adjusting GDIInfo.ulLogPixelsX\n");
522 PrimarySurface.GDIInfo.ulLogPixelsX = 96;
523 }
524 if (0 == PrimarySurface.GDIInfo.ulLogPixelsY)
525 {
526 DPRINT("Adjusting GDIInfo.ulLogPixelsY\n");
527 PrimarySurface.GDIInfo.ulLogPixelsY = 96;
528 }
529
530 PrimarySurface.Pointer.Exclude.right = -1;
531
532 DPRINT("calling completePDev\n");
533
534 /* Complete initialization of the physical device */
535 PrimarySurface.DriverFunctions.CompletePDEV(
536 PrimarySurface.hPDev,
537 (HDEV)&PrimarySurface);
538
539 DPRINT("calling DRIVER_ReferenceDriver\n");
540
541 DRIVER_ReferenceDriver(L"DISPLAY");
542
543 PrimarySurface.PreparedDriver = TRUE;
544 PrimarySurface.DisplayNumber = DisplayNumber;
545 PrimarySurface.flFlags = PDEV_DISPLAY; // Hard set,, add more flags.
546 PrimarySurface.hsemDevLock = (PERESOURCE)EngCreateSemaphore();
547 // Should be null,, but make sure for now.
548 PrimarySurface.pvGammaRamp = NULL;
549 PrimarySurface.ppdevNext = NULL; // Fixme! We need to support more than display drvs.
550 PrimarySurface.ppdevParent = NULL; // Always NULL if primary.
551 PrimarySurface.pGraphicsDev = NULL; // Fixme!
552 ret = TRUE;
553 goto cleanup;
554 }
555
556 cleanup:
557 KeSetEvent(&VideoDriverPrepared, 1, FALSE);
558 return ret;
559 }
560
561 static BOOL FASTCALL
562 IntPrepareDriverIfNeeded()
563 {
564 return (PrimarySurface.PreparedDriver ? TRUE : IntPrepareDriver());
565 }
566
567 static BOOL FASTCALL
568 PrepareVideoPrt()
569 {
570 PIRP Irp;
571 NTSTATUS Status;
572 IO_STATUS_BLOCK Iosb;
573 BOOL Prepare = TRUE;
574 ULONG Length = sizeof(BOOL);
575 PIO_STACK_LOCATION StackPtr;
576 LARGE_INTEGER StartOffset;
577 PFILE_OBJECT FileObject = PrimarySurface.VideoFileObject;
578 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
579
580 DPRINT("PrepareVideoPrt() called\n");
581
582 KeClearEvent(&PrimarySurface.VideoFileObject->Event);
583
584 ObReferenceObjectByPointer(FileObject, 0, IoFileObjectType, KernelMode);
585
586 StartOffset.QuadPart = 0;
587 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
588 DeviceObject,
589 (PVOID) &Prepare,
590 Length,
591 &StartOffset,
592 NULL,
593 &Iosb);
594 if (NULL == Irp)
595 {
596 return FALSE;
597 }
598
599 /* Set up IRP Data */
600 Irp->Tail.Overlay.OriginalFileObject = FileObject;
601 Irp->RequestorMode = KernelMode;
602 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
603 Irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
604 Irp->Flags |= IRP_WRITE_OPERATION;
605
606 /* Setup Stack Data */
607 StackPtr = IoGetNextIrpStackLocation(Irp);
608 StackPtr->FileObject = PrimarySurface.VideoFileObject;
609 StackPtr->Parameters.Write.Key = 0;
610
611 Status = IoCallDriver(DeviceObject, Irp);
612
613 if (STATUS_PENDING == Status)
614 {
615 KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, TRUE, 0);
616 Status = Iosb.Status;
617 }
618
619 return NT_SUCCESS(Status);
620 }
621
622 BOOL FASTCALL
623 IntCreatePrimarySurface()
624 {
625 SIZEL SurfSize;
626 RECTL SurfaceRect;
627 SURFOBJ *SurfObj;
628 BOOL calledFromUser;
629
630 if (! IntPrepareDriverIfNeeded())
631 {
632 return FALSE;
633 }
634
635 if (! PrepareVideoPrt())
636 {
637 return FALSE;
638 }
639
640 DPRINT("calling EnableSurface\n");
641 /* Enable the drawing surface */
642 PrimarySurface.pSurface =
643 PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.hPDev);
644 if (NULL == PrimarySurface.pSurface)
645 {
646 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, FALSE);*/
647 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.hPDev);
648 ObDereferenceObject(PrimarySurface.VideoFileObject);
649 DPRINT1("DrvEnableSurface failed\n");
650 return FALSE;
651 }
652
653 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, TRUE);
654
655 calledFromUser = UserIsEntered(); //fixme: possibly upgrade a shared lock
656 if (!calledFromUser){
657 UserEnterExclusive();
658 }
659
660 /* attach monitor */
661 IntAttachMonitor(&PrimarySurface, PrimarySurface.DisplayNumber);
662
663 SurfObj = EngLockSurface(PrimarySurface.pSurface);
664 SurfObj->dhpdev = PrimarySurface.hPDev;
665 SurfSize = SurfObj->sizlBitmap;
666 SurfaceRect.left = SurfaceRect.top = 0;
667 SurfaceRect.right = SurfObj->sizlBitmap.cx;
668 SurfaceRect.bottom = SurfObj->sizlBitmap.cy;
669 /* FIXME - why does EngEraseSurface() sometimes crash?
670 EngEraseSurface(SurfObj, &SurfaceRect, 0); */
671
672 /* Put the pointer in the center of the screen */
673 GDIDEV(SurfObj)->Pointer.Pos.x = (SurfaceRect.right - SurfaceRect.left) / 2;
674 GDIDEV(SurfObj)->Pointer.Pos.y = (SurfaceRect.bottom - SurfaceRect.top) / 2;
675
676 EngUnlockSurface(SurfObj);
677 co_IntShowDesktop(IntGetActiveDesktop(), SurfSize.cx, SurfSize.cy);
678
679 if (!calledFromUser){
680 UserLeave();
681 }
682
683 return TRUE;
684 }
685
686 VOID FASTCALL
687 IntDestroyPrimarySurface()
688 {
689 BOOL calledFromUser;
690
691 DRIVER_UnreferenceDriver(L"DISPLAY");
692
693 calledFromUser = UserIsEntered();
694 if (!calledFromUser){
695 UserEnterExclusive();
696 }
697
698 /* detach monitor */
699 IntDetachMonitor(&PrimarySurface);
700
701 if (!calledFromUser){
702 UserLeave();
703 }
704
705 /*
706 * FIXME: Hide a mouse pointer there. Also because we have to prevent
707 * memory leaks with the Eng* mouse routines.
708 */
709
710 DPRINT("Reseting display\n" );
711 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, FALSE);
712 PrimarySurface.DriverFunctions.DisableSurface(PrimarySurface.hPDev);
713 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.hPDev);
714 PrimarySurface.PreparedDriver = FALSE;
715 KeSetEvent(&VideoDriverNeedsPreparation, 1, FALSE);
716 KeResetEvent(&VideoDriverPrepared);
717
718 DceEmptyCache();
719
720 ObDereferenceObject(PrimarySurface.VideoFileObject);
721 }
722
723 HDC FASTCALL
724 IntGdiCreateDC(PUNICODE_STRING Driver,
725 PUNICODE_STRING Device,
726 PVOID pUMdhpdev,
727 CONST PDEVMODEW InitData,
728 BOOL CreateAsIC)
729 {
730 HDC hNewDC;
731 PDC NewDC;
732 PDC_ATTR nDc_Attr;
733 HDC hDC = NULL;
734 HRGN hVisRgn;
735 UNICODE_STRING StdDriver;
736 BOOL calledFromUser;
737
738 RtlInitUnicodeString(&StdDriver, L"DISPLAY");
739
740 DPRINT("DriverName: %wZ, DeviceName: %wZ\n", Driver, Device);
741
742 if (NULL == Driver || 0 == RtlCompareUnicodeString(Driver, &StdDriver, TRUE))
743 {
744 if (CreateAsIC)
745 {
746 if (! IntPrepareDriverIfNeeded())
747 {
748 /* Here, we have two possibilities:
749 * a) return NULL, and hope that the caller
750 * won't call us in a loop
751 * b) bugcheck, but caller is unable to
752 * react on the problem
753 */
754 /*DPRINT1("Unable to prepare graphics driver, returning NULL ic\n");
755 return NULL;*/
756 KeBugCheck(VIDEO_DRIVER_INIT_FAILURE);
757 }
758 }
759 else
760 {
761 calledFromUser = UserIsEntered();
762 if (!calledFromUser){
763 UserEnterExclusive();
764 }
765
766 if (! co_IntGraphicsCheck(TRUE))
767 {
768 if (!calledFromUser){
769 UserLeave();
770 }
771 DPRINT1("Unable to initialize graphics, returning NULL dc\n");
772 return NULL;
773 }
774
775 if (!calledFromUser){
776 UserLeave();
777 }
778
779 }
780 }
781
782 /* Check for existing DC object */
783 if ((hNewDC = DC_FindOpenDC(Driver)) != NULL)
784 {
785 hDC = hNewDC;
786 return NtGdiCreateCompatibleDC(hDC);
787 }
788
789 /* Allocate a DC object */
790 if ((hNewDC = DC_AllocDC(Driver)) == NULL)
791 {
792 return NULL;
793 }
794
795 NewDC = DC_LockDc( hNewDC );
796 if ( !NewDC )
797 {
798 DC_FreeDC( hNewDC );
799 return NULL;
800 }
801
802 nDc_Attr = NewDC->pDc_Attr;
803 if(!nDc_Attr) nDc_Attr = &NewDC->Dc_Attr;
804
805 NewDC->DC_Type = DC_TYPE_DIRECT;
806
807 NewDC->PDev = PrimarySurface.hPDev;
808 if(pUMdhpdev) pUMdhpdev = NewDC->PDev; // set DHPDEV for device.
809 NewDC->pPDev = (PVOID)&PrimarySurface;
810 NewDC->w.hBitmap = (HBITMAP)PrimarySurface.pSurface;
811
812 NewDC->w.bitsPerPixel = ((PGDIDEVICE)NewDC->pPDev)->GDIInfo.cBitsPixel *
813 ((PGDIDEVICE)NewDC->pPDev)->GDIInfo.cPlanes;
814 DPRINT("Bits per pel: %u\n", NewDC->w.bitsPerPixel);
815
816 NewDC->flGraphics = PrimarySurface.DevInfo.flGraphicsCaps;
817 NewDC->flGraphics2 = PrimarySurface.DevInfo.flGraphicsCaps2;
818
819 if (!CreateAsIC)
820 {
821 NewDC->PalIndexed = NtGdiGetStockObject(DEFAULT_PALETTE);
822 NewDC->w.hPalette = PrimarySurface.DevInfo.hpalDefault;
823 nDc_Attr->jROP2 = R2_COPYPEN;
824
825 NewDC->erclWindow.top = NewDC->erclWindow.left = 0;
826 NewDC->erclWindow.right = ((PGDIDEVICE)NewDC->pPDev)->GDIInfo.ulHorzRes;
827 NewDC->erclWindow.bottom = ((PGDIDEVICE)NewDC->pPDev)->GDIInfo.ulVertRes;
828
829 DC_UnlockDc( NewDC );
830
831 hVisRgn = NtGdiCreateRectRgn(0, 0, ((PGDIDEVICE)NewDC->pPDev)->GDIInfo.ulHorzRes,
832 ((PGDIDEVICE)NewDC->pPDev)->GDIInfo.ulVertRes);
833 IntGdiSelectVisRgn(hNewDC, hVisRgn);
834 NtGdiDeleteObject(hVisRgn);
835
836 /* Initialize the DC state */
837 DC_InitDC(hNewDC);
838 NtGdiSetTextColor(hNewDC, RGB(0, 0, 0));
839 NtGdiSetTextAlign(hNewDC, TA_TOP);
840 NtGdiSetBkColor(hNewDC, RGB(255, 255, 255));
841 NtGdiSetBkMode(hNewDC, OPAQUE);
842 }
843 else
844 {
845 /* From MSDN2:
846 The CreateIC function creates an information context for the specified device.
847 The information context provides a fast way to get information about the
848 device without creating a device context (DC). However, GDI drawing functions
849 cannot accept a handle to an information context.
850 */
851 NewDC->DC_Type = DC_TYPE_INFO;
852 DC_UnlockDc( NewDC );
853 }
854 return hNewDC;
855 }
856
857 HDC STDCALL
858 NtGdiOpenDCW( PUNICODE_STRING Device,
859 DEVMODEW *InitData,
860 PUNICODE_STRING pustrLogAddr,
861 ULONG iType,
862 HANDLE hspool,
863 VOID *pDriverInfo2,
864 VOID *pUMdhpdev )
865 {
866 UNICODE_STRING SafeDevice;
867 DEVMODEW SafeInitData;
868 PVOID Dhpdev;
869 HDC Ret;
870 NTSTATUS Status = STATUS_SUCCESS;
871
872 if(InitData)
873 {
874 _SEH_TRY
875 {
876 if (pUMdhpdev)
877 {
878 ProbeForWrite(pUMdhpdev,
879 sizeof(PVOID),
880 1);
881 }
882 ProbeForRead(InitData,
883 sizeof(DEVMODEW),
884 1);
885 RtlCopyMemory(&SafeInitData,
886 InitData,
887 sizeof(DEVMODEW));
888 }
889 _SEH_HANDLE
890 {
891 Status = _SEH_GetExceptionCode();
892 }
893 _SEH_END;
894 if(!NT_SUCCESS(Status))
895 {
896 SetLastNtError(Status);
897 return NULL;
898 }
899 /* FIXME - InitData can have some more bytes! */
900 }
901
902 if(Device)
903 {
904 Status = IntSafeCopyUnicodeString(&SafeDevice, Device);
905 if(!NT_SUCCESS(Status))
906 {
907 SetLastNtError(Status);
908 return NULL;
909 }
910 }
911
912 Ret = IntGdiCreateDC(Device ? &SafeDevice : NULL,
913 NULL,
914 pUMdhpdev ? &Dhpdev : NULL,
915 InitData ? &SafeInitData : NULL,
916 (BOOL) iType); // FALSE 0 DCW, TRUE 1 ICW
917
918 if (pUMdhpdev) pUMdhpdev = Dhpdev;
919
920 return Ret;
921
922 }
923
924 //
925 //
926 //
927 BOOL
928 FASTCALL
929 IntGdiDeleteDC(HDC hDC, BOOL Force)
930 {
931 PDC DCToDelete = DC_LockDc(hDC);
932
933 if (DCToDelete == NULL)
934 {
935 SetLastWin32Error(ERROR_INVALID_HANDLE);
936 return FALSE;
937 }
938
939 if(!Force)
940 {
941 if (DCToDelete->DC_Flags & DC_FLAG_PERMANENT)
942 {
943 DPRINT1("No! You Naughty Application!\n");
944 DC_UnlockDc( DCToDelete );
945 return UserReleaseDC(NULL, hDC, FALSE);
946 }
947 }
948
949 /* First delete all saved DCs */
950 while (DCToDelete->saveLevel)
951 {
952 PDC savedDC;
953 HDC savedHDC;
954
955 savedHDC = DC_GetNextDC (DCToDelete);
956 savedDC = DC_LockDc (savedHDC);
957 if (savedDC == NULL)
958 {
959 break;
960 }
961 DC_SetNextDC (DCToDelete, DC_GetNextDC (savedDC));
962 DCToDelete->saveLevel--;
963 DC_UnlockDc( savedDC );
964 NtGdiDeleteObjectApp (savedHDC);
965 }
966
967 /* Free GDI resources allocated to this DC */
968 if (!(DCToDelete->w.flags & DC_SAVED))
969 {
970 /*
971 NtGdiSelectPen (DCHandle, STOCK_BLACK_PEN);
972 NtGdiSelectBrush (DCHandle, STOCK_WHITE_BRUSH);
973 NtGdiSelectFont (DCHandle, STOCK_SYSTEM_FONT);
974 DC_LockDC (DCHandle); NtGdiSelectXxx does not recognize stock objects yet */
975 if (DCToDelete->DC_Type == DC_TYPE_MEMORY)
976 {
977 NtGdiDeleteObject (DCToDelete->w.hFirstBitmap);
978 }
979 if (DCToDelete->XlateBrush != NULL)
980 EngDeleteXlate(DCToDelete->XlateBrush);
981 if (DCToDelete->XlatePen != NULL)
982 EngDeleteXlate(DCToDelete->XlatePen);
983 }
984 if (DCToDelete->w.hClipRgn)
985 {
986 NtGdiDeleteObject (DCToDelete->w.hClipRgn);
987 }
988 if (DCToDelete->w.hVisRgn)
989 {
990 NtGdiDeleteObject (DCToDelete->w.hVisRgn);
991 }
992 if (NULL != DCToDelete->CombinedClip)
993 {
994 IntEngDeleteClipRegion(DCToDelete->CombinedClip);
995 }
996 if (DCToDelete->w.hGCClipRgn)
997 {
998 NtGdiDeleteObject (DCToDelete->w.hGCClipRgn);
999 }
1000 #if 0 /* FIXME */
1001 PATH_DestroyGdiPath (&DCToDelete->w.path);
1002 #endif
1003
1004 DC_UnlockDc( DCToDelete );
1005 DC_FreeDC ( hDC );
1006 return TRUE;
1007 }
1008
1009 BOOL
1010 STDCALL
1011 NtGdiDeleteObjectApp(HANDLE DCHandle)
1012 {
1013
1014 if (GDI_HANDLE_IS_STOCKOBJ(DCHandle)) return TRUE;
1015
1016 if (GDI_HANDLE_GET_TYPE(DCHandle) != GDI_OBJECT_TYPE_DC)
1017 return NtGdiDeleteObject((HGDIOBJ) DCHandle);
1018
1019 if(IsObjectDead((HGDIOBJ)DCHandle)) return TRUE;
1020
1021 if (!GDIOBJ_OwnedByCurrentProcess(GdiHandleTable, DCHandle))
1022 {
1023 SetLastWin32Error(ERROR_INVALID_HANDLE);
1024 return FALSE;
1025 }
1026
1027 return IntGdiDeleteDC(DCHandle, FALSE);
1028 }
1029
1030 INT
1031 APIENTRY
1032 NtGdiDrawEscape(
1033 IN HDC hdc,
1034 IN INT iEsc,
1035 IN INT cjIn,
1036 IN OPTIONAL LPSTR pjIn)
1037 {
1038 UNIMPLEMENTED;
1039 return 0;
1040 }
1041
1042 ULONG
1043 APIENTRY
1044 NtGdiEnumObjects(
1045 IN HDC hdc,
1046 IN INT iObjectType,
1047 IN ULONG cjBuf,
1048 OUT OPTIONAL PVOID pvBuf)
1049 {
1050 UNIMPLEMENTED;
1051 return 0;
1052 }
1053
1054 HANDLE
1055 STDCALL
1056 NtGdiGetDCObject(HDC hDC, INT ObjectType)
1057 {
1058 HGDIOBJ SelObject;
1059 DC *dc;
1060 PDC_ATTR Dc_Attr;
1061
1062 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
1063 if(!hDC) return NULL;
1064
1065 if(!(dc = DC_LockDc(hDC)))
1066 {
1067 SetLastWin32Error(ERROR_INVALID_HANDLE);
1068 return NULL;
1069 }
1070 Dc_Attr = dc->pDc_Attr;
1071 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
1072 switch(ObjectType)
1073 {
1074 case GDI_OBJECT_TYPE_EXTPEN:
1075 case GDI_OBJECT_TYPE_PEN:
1076 SelObject = Dc_Attr->hpen;
1077 break;
1078 case GDI_OBJECT_TYPE_BRUSH:
1079 SelObject = Dc_Attr->hbrush;
1080 break;
1081 case GDI_OBJECT_TYPE_PALETTE:
1082 SelObject = dc->w.hPalette;
1083 break;
1084 case GDI_OBJECT_TYPE_FONT:
1085 SelObject = Dc_Attr->hlfntNew;
1086 break;
1087 case GDI_OBJECT_TYPE_BITMAP:
1088 SelObject = dc->w.hBitmap;
1089 break;
1090 case GDI_OBJECT_TYPE_COLORSPACE:
1091 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
1092 SelObject = NULL;
1093 break;
1094 default:
1095 SelObject = NULL;
1096 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1097 break;
1098 }
1099
1100 DC_UnlockDc(dc);
1101 return SelObject;
1102 }
1103
1104 BOOL FASTCALL
1105 IntGdiGetDCOrgEx(DC *dc, LPPOINT Point)
1106 {
1107 Point->x = dc->w.DCOrgX;
1108 Point->y = dc->w.DCOrgY;
1109
1110 return TRUE;
1111 }
1112
1113 BOOL STDCALL
1114 NtGdiGetDCPoint( HDC hDC, UINT iPoint, PPOINTL Point)
1115 {
1116 BOOL Ret = TRUE;
1117 DC *dc;
1118 POINTL SafePoint;
1119 SIZE Size;
1120 NTSTATUS Status = STATUS_SUCCESS;
1121
1122 if(!Point)
1123 {
1124 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1125 return FALSE;
1126 }
1127
1128 RtlZeroMemory(&SafePoint, sizeof(POINT));
1129
1130 dc = DC_LockDc(hDC);
1131 if(!dc)
1132 {
1133 SetLastWin32Error(ERROR_INVALID_HANDLE);
1134 return FALSE;
1135 }
1136
1137 switch (iPoint)
1138 {
1139 case GdiGetViewPortExt:
1140 IntGetViewportExtEx(dc, &Size);
1141 SafePoint.x = Size.cx;
1142 SafePoint.y = Size.cy;
1143 break;
1144 case GdiGetWindowExt:
1145 IntGetWindowExtEx(dc, &Size);
1146 SafePoint.x = Size.cx;
1147 SafePoint.y = Size.cy;
1148 break;
1149 case GdiGetViewPortOrg:
1150 IntGetViewportOrgEx(dc, &SafePoint);
1151 break;
1152 case GdiGetWindowOrg:
1153 IntGetWindowOrgEx(dc, &SafePoint);
1154 break;
1155 case GdiGetDCOrg:
1156 Ret = IntGdiGetDCOrgEx(dc, &SafePoint);
1157 break;
1158 case GdiGetAspectRatioFilter:
1159 default:
1160 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1161 Ret = FALSE;
1162 break;
1163 }
1164
1165 if (Ret)
1166 {
1167 _SEH_TRY
1168 {
1169 ProbeForWrite(Point,
1170 sizeof(POINT),
1171 1);
1172 *Point = SafePoint;
1173 }
1174 _SEH_HANDLE
1175 {
1176 Status = _SEH_GetExceptionCode();
1177 }
1178 _SEH_END;
1179 }
1180
1181 if(!NT_SUCCESS(Status))
1182 {
1183 SetLastNtError(Status);
1184 DC_UnlockDc(dc);
1185 return FALSE;
1186 }
1187
1188 DC_UnlockDc(dc);
1189 return Ret;
1190 }
1191
1192 VOID
1193 FASTCALL
1194 IntGdiCopyToSaveState(PDC dc, PDC newdc)
1195 {
1196 PDC_ATTR Dc_Attr, nDc_Attr;
1197
1198 Dc_Attr = dc->pDc_Attr;
1199 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
1200 nDc_Attr = newdc->pDc_Attr;
1201 if(!nDc_Attr) nDc_Attr = &newdc->Dc_Attr;
1202
1203 newdc->w.flags = dc->w.flags | DC_SAVED;
1204 nDc_Attr->dwLayout = Dc_Attr->dwLayout;
1205 nDc_Attr->hpen = Dc_Attr->hpen;
1206 nDc_Attr->hbrush = Dc_Attr->hbrush;
1207 nDc_Attr->hlfntNew = Dc_Attr->hlfntNew;
1208 newdc->w.hBitmap = dc->w.hBitmap;
1209 newdc->w.hFirstBitmap = dc->w.hFirstBitmap;
1210 newdc->PalIndexed = dc->PalIndexed;
1211 newdc->w.hPalette = dc->w.hPalette;
1212 newdc->w.totalExtent = dc->w.totalExtent;
1213 newdc->w.bitsPerPixel = dc->w.bitsPerPixel;
1214 nDc_Attr->jROP2 = Dc_Attr->jROP2;
1215 nDc_Attr->jFillMode = Dc_Attr->jFillMode;
1216 nDc_Attr->jStretchBltMode = Dc_Attr->jStretchBltMode;
1217 nDc_Attr->lRelAbs = Dc_Attr->lRelAbs;
1218 nDc_Attr->jBkMode = Dc_Attr->jBkMode;
1219 nDc_Attr->lBkMode = Dc_Attr->lBkMode;
1220 nDc_Attr->crBackgroundClr = Dc_Attr->crBackgroundClr;
1221 nDc_Attr->crForegroundClr = Dc_Attr->crForegroundClr;
1222 nDc_Attr->ulBackgroundClr = Dc_Attr->ulBackgroundClr;
1223 nDc_Attr->ulForegroundClr = Dc_Attr->ulForegroundClr;
1224 nDc_Attr->ptlBrushOrigin = Dc_Attr->ptlBrushOrigin;
1225 nDc_Attr->lTextAlign = Dc_Attr->lTextAlign;
1226 nDc_Attr->lTextExtra = Dc_Attr->lTextExtra;
1227 nDc_Attr->cBreak = Dc_Attr->cBreak;
1228 nDc_Attr->lBreakExtra = Dc_Attr->lBreakExtra;
1229 nDc_Attr->iMapMode = Dc_Attr->iMapMode;
1230 nDc_Attr->iGraphicsMode = Dc_Attr->iGraphicsMode;
1231 #if 0
1232 /* Apparently, the DC origin is not changed by [GS]etDCState */
1233 newdc->w.DCOrgX = dc->w.DCOrgX;
1234 newdc->w.DCOrgY = dc->w.DCOrgY;
1235 #endif
1236 nDc_Attr->ptlCurrent = Dc_Attr->ptlCurrent;
1237 nDc_Attr->ptfxCurrent = Dc_Attr->ptfxCurrent;
1238 newdc->w.ArcDirection = dc->w.ArcDirection;
1239 newdc->w.xformWorld2Wnd = dc->w.xformWorld2Wnd;
1240 newdc->w.xformWorld2Vport = dc->w.xformWorld2Vport;
1241 newdc->w.xformVport2World = dc->w.xformVport2World;
1242 newdc->w.vport2WorldValid = dc->w.vport2WorldValid;
1243 nDc_Attr->ptlWindowOrg = Dc_Attr->ptlWindowOrg;
1244 nDc_Attr->szlWindowExt = Dc_Attr->szlWindowExt;
1245 nDc_Attr->ptlViewportOrg = Dc_Attr->ptlViewportOrg;
1246 nDc_Attr->szlViewportExt = Dc_Attr->szlViewportExt;
1247
1248 newdc->saveLevel = 0;
1249 newdc->DC_Type = dc->DC_Type;
1250
1251 #if 0
1252 PATH_InitGdiPath( &newdc->w.path );
1253 #endif
1254
1255 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
1256
1257 newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
1258 if (dc->w.hClipRgn)
1259 {
1260 newdc->w.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1261 NtGdiCombineRgn( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
1262 }
1263 }
1264
1265
1266 VOID
1267 FASTCALL
1268 IntGdiCopyFromSaveState(PDC dc, PDC dcs, HDC hDC)
1269 {
1270 PDC_ATTR Dc_Attr, sDc_Attr;
1271
1272 Dc_Attr = dc->pDc_Attr;
1273 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
1274 sDc_Attr = dcs->pDc_Attr;
1275 if(!sDc_Attr) sDc_Attr = &dcs->Dc_Attr;
1276
1277 dc->w.flags = dcs->w.flags & ~DC_SAVED;
1278
1279 dc->w.hFirstBitmap = dcs->w.hFirstBitmap;
1280
1281 Dc_Attr->dwLayout = sDc_Attr->dwLayout;
1282 dc->w.totalExtent = dcs->w.totalExtent;
1283 Dc_Attr->jROP2 = sDc_Attr->jROP2;
1284 Dc_Attr->jFillMode = sDc_Attr->jFillMode;
1285 Dc_Attr->jStretchBltMode = sDc_Attr->jStretchBltMode;
1286 Dc_Attr->lRelAbs = sDc_Attr->lRelAbs;
1287 Dc_Attr->jBkMode = sDc_Attr->jBkMode;
1288 Dc_Attr->crBackgroundClr = sDc_Attr->crBackgroundClr;
1289 Dc_Attr->crForegroundClr = sDc_Attr->crForegroundClr;
1290 Dc_Attr->lBkMode = sDc_Attr->lBkMode;
1291 Dc_Attr->ulBackgroundClr = sDc_Attr->ulBackgroundClr;
1292 Dc_Attr->ulForegroundClr = sDc_Attr->ulForegroundClr;
1293 Dc_Attr->ptlBrushOrigin = sDc_Attr->ptlBrushOrigin;
1294
1295 Dc_Attr->lTextAlign = sDc_Attr->lTextAlign;
1296 Dc_Attr->lTextExtra = sDc_Attr->lTextExtra;
1297 Dc_Attr->cBreak = sDc_Attr->cBreak;
1298 Dc_Attr->lBreakExtra = sDc_Attr->lBreakExtra;
1299 Dc_Attr->iMapMode = sDc_Attr->iMapMode;
1300 Dc_Attr->iGraphicsMode = sDc_Attr->iGraphicsMode;
1301 #if 0
1302 /* Apparently, the DC origin is not changed by [GS]etDCState */
1303 dc->w.DCOrgX = dcs->w.DCOrgX;
1304 dc->w.DCOrgY = dcs->w.DCOrgY;
1305 #endif
1306 Dc_Attr->ptlCurrent = sDc_Attr->ptlCurrent;
1307 Dc_Attr->ptfxCurrent = sDc_Attr->ptfxCurrent;
1308 dc->w.ArcDirection = dcs->w.ArcDirection;
1309 dc->w.xformWorld2Wnd = dcs->w.xformWorld2Wnd;
1310 dc->w.xformWorld2Vport = dcs->w.xformWorld2Vport;
1311 dc->w.xformVport2World = dcs->w.xformVport2World;
1312 dc->w.vport2WorldValid = dcs->w.vport2WorldValid;
1313 Dc_Attr->ptlWindowOrg = sDc_Attr->ptlWindowOrg;
1314 Dc_Attr->szlWindowExt = sDc_Attr->szlWindowExt;
1315 Dc_Attr->ptlViewportOrg = sDc_Attr->ptlViewportOrg;
1316 Dc_Attr->szlViewportExt = sDc_Attr->szlViewportExt;
1317 dc->PalIndexed = dcs->PalIndexed;
1318
1319 if (dc->DC_Type != DC_TYPE_MEMORY)
1320 {
1321 dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
1322 }
1323
1324 #if 0
1325 if (dcs->w.hClipRgn)
1326 {
1327 if (!dc->w.hClipRgn)
1328 {
1329 dc->w.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1330 }
1331 NtGdiCombineRgn( dc->w.hClipRgn, dcs->w.hClipRgn, 0, RGN_COPY );
1332 }
1333 else
1334 {
1335 if (dc->w.hClipRgn)
1336 {
1337 NtGdiDeleteObject( dc->w.hClipRgn );
1338 }
1339 dc->w.hClipRgn = 0;
1340 }
1341 {
1342 int res;
1343 res = CLIPPING_UpdateGCRegion( dc );
1344 ASSERT ( res != ERROR );
1345 }
1346 DC_UnlockDc ( dc );
1347 #else
1348 IntGdiExtSelectClipRgn(dc, dcs->w.hClipRgn, RGN_COPY);
1349 DC_UnlockDc ( dc );
1350 #endif
1351 if(!hDC) return; // Not a MemoryDC or SaveLevel DC, return.
1352
1353 NtGdiSelectBitmap( hDC, dcs->w.hBitmap );
1354 NtGdiSelectBrush( hDC, sDc_Attr->hbrush );
1355 NtGdiSelectFont( hDC, sDc_Attr->hlfntNew );
1356 NtGdiSelectPen( hDC, sDc_Attr->hpen );
1357
1358 NtGdiSetBkColor( hDC, sDc_Attr->crBackgroundClr);
1359 NtGdiSetTextColor( hDC, sDc_Attr->crForegroundClr);
1360
1361 NtUserSelectPalette( hDC, dcs->w.hPalette, FALSE );
1362
1363 #if 0
1364 GDISelectPalette16( hDC, dcs->w.hPalette, FALSE );
1365 #endif
1366 }
1367
1368 HDC STDCALL
1369 IntGdiGetDCState(HDC hDC)
1370 {
1371 PDC newdc, dc;
1372 HDC hnewdc;
1373
1374 dc = DC_LockDc(hDC);
1375 if (dc == NULL)
1376 {
1377 SetLastWin32Error(ERROR_INVALID_HANDLE);
1378 return 0;
1379 }
1380
1381 hnewdc = DC_AllocDC(NULL);
1382 if (hnewdc == NULL)
1383 {
1384 DC_UnlockDc(dc);
1385 return 0;
1386 }
1387 newdc = DC_LockDc( hnewdc );
1388 /* FIXME - newdc can be NULL!!!! Don't assert here!!! */
1389 ASSERT( newdc );
1390
1391 newdc->hSelf = hnewdc;
1392 IntGdiCopyToSaveState( dc, newdc);
1393
1394 DC_UnlockDc( newdc );
1395 DC_UnlockDc( dc );
1396 return hnewdc;
1397 }
1398
1399
1400 VOID
1401 STDCALL
1402 IntGdiSetDCState ( HDC hDC, HDC hDCSave )
1403 {
1404 PDC dc, dcs;
1405
1406 dc = DC_LockDc ( hDC );
1407 if ( dc )
1408 {
1409 dcs = DC_LockDc ( hDCSave );
1410 if ( dcs )
1411 {
1412 if ( dcs->w.flags & DC_SAVED )
1413 {
1414 IntGdiCopyFromSaveState( dc, dcs, dc->hSelf);
1415 }
1416 else
1417 {
1418 DC_UnlockDc(dc);
1419 }
1420 DC_UnlockDc ( dcs );
1421 }
1422 else
1423 {
1424 DC_UnlockDc ( dc );
1425 SetLastWin32Error(ERROR_INVALID_HANDLE);
1426 }
1427 }
1428 else
1429 SetLastWin32Error(ERROR_INVALID_HANDLE);
1430 }
1431
1432 INT FASTCALL
1433 IntGdiGetDeviceCaps(PDC dc, INT Index)
1434 {
1435 INT ret = 0;
1436 POINT pt;
1437
1438 /* Retrieve capability */
1439 switch (Index)
1440 {
1441 case DRIVERVERSION:
1442 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVersion;
1443 break;
1444
1445 case TECHNOLOGY:
1446 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulTechnology;
1447 break;
1448
1449 case HORZSIZE:
1450 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize;
1451 break;
1452
1453 case VERTSIZE:
1454 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize;
1455 break;
1456
1457 case HORZRES:
1458 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes;
1459 break;
1460
1461 case VERTRES:
1462 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes;
1463 break;
1464
1465 case LOGPIXELSX:
1466 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulLogPixelsX;
1467 break;
1468
1469 case LOGPIXELSY:
1470 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulLogPixelsY;
1471 break;
1472
1473 case BITSPIXEL:
1474 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.cBitsPixel;
1475 break;
1476
1477 case PLANES:
1478 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.cPlanes;
1479 break;
1480
1481 case NUMBRUSHES:
1482 UNIMPLEMENTED; /* FIXME */
1483 break;
1484
1485 case NUMPENS:
1486 UNIMPLEMENTED; /* FIXME */
1487 break;
1488
1489 case NUMFONTS:
1490 UNIMPLEMENTED; /* FIXME */
1491 break;
1492
1493 case NUMCOLORS:
1494 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulNumColors;
1495 break;
1496
1497 case ASPECTX:
1498 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulAspectX;
1499 break;
1500
1501 case ASPECTY:
1502 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulAspectY;
1503 break;
1504
1505 case ASPECTXY:
1506 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulAspectXY;
1507 break;
1508
1509 case PDEVICESIZE:
1510 UNIMPLEMENTED; /* FIXME */
1511 break;
1512
1513 case CLIPCAPS:
1514 UNIMPLEMENTED; /* FIXME */
1515 break;
1516
1517 case SIZEPALETTE:
1518 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulNumPalReg; /* FIXME not sure */
1519 break;
1520
1521 case NUMRESERVED:
1522 ret = 0;
1523 break;
1524
1525 case COLORRES:
1526 UNIMPLEMENTED; /* FIXME */
1527 break;
1528
1529 case PHYSICALWIDTH:
1530 if(IntGdiEscape(dc, GETPHYSPAGESIZE, 0, NULL, (LPVOID)&pt) > 0)
1531 {
1532 ret = pt.x;
1533 }
1534 else
1535 {
1536 ret = 0;
1537 }
1538 break;
1539
1540 case PHYSICALHEIGHT:
1541 if(IntGdiEscape(dc, GETPHYSPAGESIZE, 0, NULL, (LPVOID)&pt) > 0)
1542 {
1543 ret = pt.y;
1544 }
1545 else
1546 {
1547 ret = 0;
1548 }
1549 break;
1550
1551 case PHYSICALOFFSETX:
1552 if(IntGdiEscape(dc, GETPRINTINGOFFSET, 0, NULL, (LPVOID)&pt) > 0)
1553 {
1554 ret = pt.x;
1555 }
1556 else
1557 {
1558 ret = 0;
1559 }
1560 break;
1561
1562 case PHYSICALOFFSETY:
1563 if(IntGdiEscape(dc, GETPRINTINGOFFSET, 0, NULL, (LPVOID)&pt) > 0)
1564 {
1565 ret = pt.y;
1566 }
1567 else
1568 {
1569 ret = 0;
1570 }
1571 break;
1572
1573 case VREFRESH:
1574 UNIMPLEMENTED; /* FIXME */
1575 break;
1576
1577 case SCALINGFACTORX:
1578 if(IntGdiEscape(dc, GETSCALINGFACTOR, 0, NULL, (LPVOID)&pt) > 0)
1579 {
1580 ret = pt.x;
1581 }
1582 else
1583 {
1584 ret = 0;
1585 }
1586 break;
1587
1588 case SCALINGFACTORY:
1589 if(IntGdiEscape(dc, GETSCALINGFACTOR, 0, NULL, (LPVOID)&pt) > 0)
1590 {
1591 ret = pt.y;
1592 }
1593 else
1594 {
1595 ret = 0;
1596 }
1597 break;
1598
1599 case RASTERCAPS:
1600 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.flRaster;
1601 break;
1602
1603 case CURVECAPS:
1604 UNIMPLEMENTED; /* FIXME */
1605 break;
1606
1607 case LINECAPS:
1608 UNIMPLEMENTED; /* FIXME */
1609 break;
1610
1611 case POLYGONALCAPS:
1612 UNIMPLEMENTED; /* FIXME */
1613 break;
1614
1615 case TEXTCAPS:
1616 ret = ((PGDIDEVICE)dc->pPDev)->GDIInfo.flTextCaps;
1617 break;
1618
1619 default:
1620 ret = 0;
1621 break;
1622 }
1623
1624 return ret;
1625 }
1626
1627 INT STDCALL
1628 NtGdiGetDeviceCaps(HDC hDC,
1629 INT Index)
1630 {
1631 PDC dc;
1632 INT ret;
1633
1634 dc = DC_LockDc(hDC);
1635 if (dc == NULL)
1636 {
1637 SetLastWin32Error(ERROR_INVALID_HANDLE);
1638 return 0;
1639 }
1640
1641 ret = IntGdiGetDeviceCaps(dc, Index);
1642
1643 DPRINT("(%04x,%d): returning %d\n", hDC, Index, ret);
1644
1645 DC_UnlockDc( dc );
1646 return ret;
1647 }
1648
1649 INT
1650 FASTCALL
1651 IntGdiGetObject(IN HANDLE Handle,
1652 IN INT cbCount,
1653 IN LPVOID lpBuffer)
1654 {
1655 PVOID pGdiObject;
1656 INT Result = 0;
1657 DWORD dwObjectType;
1658
1659 pGdiObject = GDIOBJ_LockObj(GdiHandleTable, Handle, GDI_OBJECT_TYPE_DONTCARE);
1660 if (!pGdiObject)
1661 {
1662 SetLastWin32Error(ERROR_INVALID_HANDLE);
1663 return 0;
1664 }
1665
1666 dwObjectType = GDIOBJ_GetObjectType(Handle);
1667 switch (dwObjectType)
1668 {
1669 case GDI_OBJECT_TYPE_PEN:
1670 case GDI_OBJECT_TYPE_EXTPEN:
1671 Result = PEN_GetObject((PGDIBRUSHOBJ) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
1672 break;
1673
1674 case GDI_OBJECT_TYPE_BRUSH:
1675 Result = BRUSH_GetObject((PGDIBRUSHOBJ ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
1676 break;
1677
1678 case GDI_OBJECT_TYPE_BITMAP:
1679 Result = BITMAP_GetObject((BITMAPOBJ *) pGdiObject, cbCount, lpBuffer);
1680 break;
1681 case GDI_OBJECT_TYPE_FONT:
1682 Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
1683 #if 0
1684 // Fix the LOGFONT structure for the stock fonts
1685 if (FIRST_STOCK_HANDLE <= Handle && Handle <= LAST_STOCK_HANDLE)
1686 {
1687 FixStockFontSizeW(Handle, cbCount, lpBuffer);
1688 }
1689 #endif
1690 break;
1691
1692 case GDI_OBJECT_TYPE_PALETTE:
1693 Result = PALETTE_GetObject((PPALGDI) pGdiObject, cbCount, lpBuffer);
1694 break;
1695
1696 default:
1697 DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType);
1698 break;
1699 }
1700
1701 GDIOBJ_UnlockObjByPtr(GdiHandleTable, pGdiObject);
1702
1703 return Result;
1704 }
1705
1706 INT
1707 NTAPI
1708 NtGdiExtGetObjectW(IN HANDLE hGdiObj,
1709 IN INT cbCount,
1710 OUT LPVOID lpBuffer)
1711 {
1712 INT iRetCount = 0;
1713 INT cbCopyCount;
1714 union
1715 {
1716 BITMAP bitmap;
1717 DIBSECTION dibsection;
1718 LOGPEN logpen;
1719 LOGBRUSH logbrush;
1720 LOGFONTW logfontw;
1721 EXTLOGFONTW extlogfontw;
1722 ENUMLOGFONTEXDVW enumlogfontexdvw;
1723 } Object;
1724
1725 // Normalize to the largest supported object size
1726 cbCount = min((UINT)cbCount, sizeof(Object));
1727
1728 // Now do the actual call
1729 iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL);
1730 cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
1731
1732 // Make sure we have a buffer and a copy size
1733 if ((cbCopyCount) && (lpBuffer))
1734 {
1735 // Enter SEH for buffer transfer
1736 _SEH_TRY
1737 {
1738 // Probe the buffer and copy it
1739 ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
1740 RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
1741 }
1742 _SEH_HANDLE
1743 {
1744 // Clear the return value.
1745 // Do *NOT* set last error here!
1746 iRetCount = 0;
1747 }
1748 _SEH_END;
1749 }
1750 // Return the count
1751 return iRetCount;
1752 }
1753
1754 BOOL
1755 APIENTRY
1756 NtGdiResetDC(
1757 IN HDC hdc,
1758 IN LPDEVMODEW pdm,
1759 OUT PBOOL pbBanding,
1760 IN OPTIONAL VOID *pDriverInfo2,
1761 OUT VOID *ppUMdhpdev)
1762 {
1763 UNIMPLEMENTED;
1764 return 0;
1765 }
1766
1767 BOOL STDCALL
1768 NtGdiRestoreDC(HDC hDC, INT SaveLevel)
1769 {
1770 PDC dc, dcs;
1771 BOOL success;
1772
1773 DPRINT("NtGdiRestoreDC(%lx, %d)\n", hDC, SaveLevel);
1774
1775 dc = DC_LockDc(hDC);
1776 if (!dc)
1777 {
1778 SetLastWin32Error(ERROR_INVALID_HANDLE);
1779 return FALSE;
1780 }
1781
1782 if (SaveLevel < 0)
1783 SaveLevel = dc->saveLevel + SaveLevel + 1;
1784
1785 if(SaveLevel < 0 || dc->saveLevel<SaveLevel)
1786 {
1787 DC_UnlockDc(dc);
1788 return FALSE;
1789 }
1790
1791 success=TRUE;
1792 while (dc->saveLevel >= SaveLevel)
1793 {
1794 HDC hdcs = DC_GetNextDC (dc);
1795
1796 dcs = DC_LockDc (hdcs);
1797 if (dcs == NULL)
1798 {
1799 DC_UnlockDc(dc);
1800 return FALSE;
1801 }
1802
1803 DC_SetNextDC (dc, DC_GetNextDC (dcs));
1804 dcs->hNext = 0;
1805
1806 if (--dc->saveLevel < SaveLevel)
1807 {
1808 DC_UnlockDc( dc );
1809 DC_UnlockDc( dcs );
1810
1811 IntGdiSetDCState(hDC, hdcs);
1812
1813 if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
1814 {
1815 /* FIXME: This might not be quite right, since we're
1816 * returning FALSE but still destroying the saved DC state */
1817 success = FALSE;
1818 }
1819 dc = DC_LockDc(hDC);
1820 if(!dc)
1821 {
1822 return FALSE;
1823 }
1824 }
1825 else
1826 {
1827 DC_UnlockDc( dcs );
1828 }
1829 NtGdiDeleteObjectApp (hdcs);
1830 }
1831 DC_UnlockDc( dc );
1832 return success;
1833 }
1834
1835
1836 INT STDCALL
1837 NtGdiSaveDC(HDC hDC)
1838 {
1839 HDC hdcs;
1840 PDC dc, dcs;
1841 INT ret;
1842
1843 DPRINT("NtGdiSaveDC(%lx)\n", hDC);
1844
1845 if (!(hdcs = IntGdiGetDCState(hDC)))
1846 {
1847 return 0;
1848 }
1849
1850 dcs = DC_LockDc (hdcs);
1851 if (dcs == NULL)
1852 {
1853 SetLastWin32Error(ERROR_INVALID_HANDLE);
1854 return 0;
1855 }
1856 dc = DC_LockDc (hDC);
1857 if (dc == NULL)
1858 {
1859 DC_UnlockDc(dcs);
1860 SetLastWin32Error(ERROR_INVALID_HANDLE);
1861 return 0;
1862 }
1863
1864 #if 0
1865 /* Copy path. The reason why path saving / restoring is in SaveDC/
1866 * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
1867 * functions are only in Win16 (which doesn't have paths) and that
1868 * SetDCState doesn't allow us to signal an error (which can happen
1869 * when copying paths).
1870 */
1871 if (!PATH_AssignGdiPath (&dcs->w.path, &dc->w.path))
1872 {
1873 NtGdiDeleteObjectApp (hdcs);
1874
1875 return 0;
1876 }
1877 #endif
1878
1879 DC_SetNextDC (dcs, DC_GetNextDC (dc));
1880 DC_SetNextDC (dc, hdcs);
1881 ret = ++dc->saveLevel;
1882 DC_UnlockDc( dcs );
1883 DC_UnlockDc( dc );
1884
1885 return ret;
1886 }
1887
1888 /*
1889 * @implemented
1890 */
1891 HBITMAP
1892 APIENTRY
1893 NtGdiSelectBitmap(
1894 IN HDC hDC,
1895 IN HBITMAP hBmp)
1896 {
1897 PDC pDC;
1898 PDC_ATTR pDc_Attr;
1899 HBITMAP hOrgBmp;
1900 PBITMAPOBJ pBmp;
1901 HRGN hVisRgn;
1902 BOOLEAN bFailed;
1903 PGDIBRUSHOBJ pBrush;
1904
1905 if (hDC == NULL || hBmp == NULL) return NULL;
1906
1907 pDC = DC_LockDc(hDC);
1908 if (!pDC)
1909 {
1910 return NULL;
1911 }
1912
1913 pDc_Attr = pDC->pDc_Attr;
1914 if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
1915
1916 /* must be memory dc to select bitmap */
1917 if (pDC->DC_Type != DC_TYPE_MEMORY)
1918 {
1919 DC_UnlockDc(pDC);
1920 return NULL;
1921 }
1922
1923 pBmp = BITMAPOBJ_LockBitmap(hBmp);
1924 if (!pBmp)
1925 {
1926 DC_UnlockDc(pDC);
1927 return NULL;
1928 }
1929 hOrgBmp = pDC->w.hBitmap;
1930
1931 /* Release the old bitmap, lock the new one and convert it to a SURF */
1932 pDC->w.hBitmap = hBmp;
1933
1934 // if we're working with a DIB, get the palette [fixme: only create if the selected palette is null]
1935 if(pBmp->dib)
1936 {
1937 pDC->w.bitsPerPixel = pBmp->dib->dsBmih.biBitCount;
1938 pDC->w.hPalette = pBmp->hDIBPalette;
1939 }
1940 else
1941 {
1942 pDC->w.bitsPerPixel = BitsPerFormat(pBmp->SurfObj.iBitmapFormat);
1943 pDC->w.hPalette = ((GDIDEVICE *)pDC->pPDev)->DevInfo.hpalDefault;
1944 }
1945
1946 /* Regenerate the XLATEOBJs. */
1947 pBrush = BRUSHOBJ_LockBrush(pDc_Attr->hbrush);
1948 if (pBrush)
1949 {
1950 if (pDC->XlateBrush)
1951 {
1952 EngDeleteXlate(pDC->XlateBrush);
1953 }
1954 pDC->XlateBrush = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
1955 BRUSHOBJ_UnlockBrush(pBrush);
1956 }
1957
1958 pBrush = PENOBJ_LockPen(pDc_Attr->hpen);
1959 if (pBrush)
1960 {
1961 if (pDC->XlatePen)
1962 {
1963 EngDeleteXlate(pDC->XlatePen);
1964 }
1965 pDC->XlatePen = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
1966 PENOBJ_UnlockPen(pBrush);
1967 }
1968
1969 DC_UnlockDc(pDC);
1970
1971 hVisRgn = NtGdiCreateRectRgn(0, 0, pBmp->SurfObj.sizlBitmap.cx, pBmp->SurfObj.sizlBitmap.cy);
1972 BITMAPOBJ_UnlockBitmap(pBmp);
1973 IntGdiSelectVisRgn(hDC, hVisRgn);
1974 NtGdiDeleteObject(hVisRgn);
1975
1976 return hOrgBmp;
1977 }
1978
1979 /*
1980 * @implemented
1981 */
1982 HBRUSH
1983 APIENTRY
1984 NtGdiSelectBrush(
1985 IN HDC hDC,
1986 IN HBRUSH hBrush)
1987 {
1988 PDC pDC;
1989 PDC_ATTR pDc_Attr;
1990 HBRUSH hOrgBrush;
1991 PGDIBRUSHOBJ pBrush;
1992 XLATEOBJ *XlateObj;
1993 BOOLEAN bFailed;
1994
1995 if (hDC == NULL || hBrush == NULL) return NULL;
1996
1997 pDC = DC_LockDc(hDC);
1998 if (!pDC)
1999 {
2000 return NULL;
2001 }
2002
2003 pDc_Attr = pDC->pDc_Attr;
2004 if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
2005
2006 pBrush = BRUSHOBJ_LockBrush(hBrush);
2007 if (pBrush == NULL)
2008 {
2009 SetLastWin32Error(ERROR_INVALID_HANDLE);
2010 return NULL;
2011 }
2012
2013 XlateObj = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
2014 BRUSHOBJ_UnlockBrush(pBrush);
2015 if(bFailed)
2016 {
2017 return NULL;
2018 }
2019
2020 hOrgBrush = pDc_Attr->hbrush;
2021 pDc_Attr->hbrush = hBrush;
2022 if (pDC->XlateBrush != NULL)
2023 {
2024 EngDeleteXlate(pDC->XlateBrush);
2025 }
2026 pDC->XlateBrush = XlateObj;
2027
2028 DC_UnlockDc(pDC);
2029 return hOrgBrush;
2030 }
2031
2032 /*
2033 * @implemented
2034 */
2035 HFONT
2036 APIENTRY
2037 NtGdiSelectFont(
2038 IN HDC hDC,
2039 IN HFONT hFont)
2040 {
2041 PDC pDC;
2042 PDC_ATTR pDc_Attr;
2043 HFONT hOrgFont = NULL;
2044
2045 if (hDC == NULL || hFont == NULL) return NULL;
2046
2047 pDC = DC_LockDc(hDC);
2048 if (!pDC)
2049 {
2050 return NULL;
2051 }
2052
2053 pDc_Attr = pDC->pDc_Attr;
2054 if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
2055
2056 /* FIXME: what if not successful? */
2057 if(NT_SUCCESS(TextIntRealizeFont((HFONT)hFont)))
2058 {
2059 hOrgFont = pDc_Attr->hlfntNew;
2060 pDc_Attr->hlfntNew = hFont;
2061 }
2062
2063 DC_UnlockDc(pDC);
2064
2065 return hOrgFont;
2066 }
2067
2068 /*
2069 * @implemented
2070 */
2071 HPEN
2072 APIENTRY
2073 NtGdiSelectPen(
2074 IN HDC hDC,
2075 IN HPEN hPen)
2076 {
2077 PDC pDC;
2078 PDC_ATTR pDc_Attr;
2079 HPEN hOrgPen = NULL;
2080 PGDIBRUSHOBJ pPen;
2081 XLATEOBJ *XlateObj;
2082 BOOLEAN bFailed;
2083
2084 if (hDC == NULL || hPen == NULL) return NULL;
2085
2086 pDC = DC_LockDc(hDC);
2087 if (!pDC)
2088 {
2089 return NULL;
2090 }
2091
2092 pDc_Attr = pDC->pDc_Attr;
2093 if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
2094
2095 pPen = PENOBJ_LockPen(hPen);
2096 if (pPen == NULL)
2097 {
2098 return NULL;
2099 }
2100
2101 XlateObj = IntGdiCreateBrushXlate(pDC, pPen, &bFailed);
2102 PENOBJ_UnlockPen(pPen);
2103 if (bFailed)
2104 {
2105 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
2106 return NULL;
2107 }
2108
2109 hOrgPen = pDc_Attr->hpen;
2110 pDc_Attr->hpen = hPen;
2111 if (pDC->XlatePen != NULL)
2112 {
2113 EngDeleteXlate(pDC->XlatePen);
2114 }
2115 pDC->XlatePen = XlateObj;
2116
2117 DC_UnlockDc(pDC);
2118
2119 return hOrgPen;
2120 }
2121
2122 WORD STDCALL
2123 IntGdiSetHookFlags(HDC hDC, WORD Flags)
2124 {
2125 WORD wRet;
2126 DC *dc = DC_LockDc(hDC);
2127
2128 if (NULL == dc)
2129 {
2130 SetLastWin32Error(ERROR_INVALID_HANDLE);
2131 return 0;
2132 }
2133
2134 wRet = dc->w.flags & DC_DIRTY;
2135
2136 /* "Undocumented Windows" info is slightly confusing.
2137 */
2138
2139 DPRINT("DC %p, Flags %04x\n", hDC, Flags);
2140
2141 if (Flags & DCHF_INVALIDATEVISRGN)
2142 {
2143 dc->w.flags |= DC_DIRTY;
2144 }
2145 else if (Flags & DCHF_VALIDATEVISRGN || 0 == Flags)
2146 {
2147 dc->w.flags &= ~DC_DIRTY;
2148 }
2149
2150 DC_UnlockDc(dc);
2151
2152 return wRet;
2153 }
2154
2155
2156 BOOL
2157 STDCALL
2158 NtGdiGetDCDword(
2159 HDC hDC,
2160 UINT u,
2161 DWORD *Result
2162 )
2163 {
2164 BOOL Ret = TRUE;
2165 PDC dc;
2166 PDC_ATTR Dc_Attr;
2167
2168 DWORD SafeResult = 0;
2169 NTSTATUS Status = STATUS_SUCCESS;
2170
2171 if(!Result)
2172 {
2173 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2174 return FALSE;
2175 }
2176
2177 dc = DC_LockDc(hDC);
2178 if(!dc)
2179 {
2180 SetLastWin32Error(ERROR_INVALID_HANDLE);
2181 return FALSE;
2182 }
2183 Dc_Attr = dc->pDc_Attr;
2184 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
2185
2186 switch (u)
2187 {
2188 case GdiGetJournal:
2189 break;
2190 case GdiGetRelAbs:
2191 SafeResult = Dc_Attr->lRelAbs;
2192 break;
2193 case GdiGetBreakExtra:
2194 SafeResult = Dc_Attr->lBreakExtra;
2195 break;
2196 case GdiGerCharBreak:
2197 SafeResult = Dc_Attr->cBreak;
2198 break;
2199 case GdiGetArcDirection:
2200 SafeResult = dc->w.ArcDirection;
2201 break;
2202 case GdiGetEMFRestorDc:
2203 break;
2204 case GdiGetFontLanguageInfo:
2205 break;
2206 case GdiGetIsMemDc:
2207 SafeResult = dc->DC_Type;
2208 break;
2209 case GdiGetMapMode:
2210 SafeResult = Dc_Attr->iMapMode;
2211 break;
2212 case GdiGetTextCharExtra:
2213 SafeResult = Dc_Attr->lTextExtra;
2214 break;
2215 default:
2216 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2217 Ret = FALSE;
2218 break;
2219 }
2220
2221 if (Ret)
2222 {
2223 _SEH_TRY
2224 {
2225 ProbeForWrite(Result,
2226 sizeof(DWORD),
2227 1);
2228 *Result = SafeResult;
2229 }
2230 _SEH_HANDLE
2231 {
2232 Status = _SEH_GetExceptionCode();
2233 }
2234 _SEH_END;
2235 }
2236
2237 if(!NT_SUCCESS(Status))
2238 {
2239 SetLastNtError(Status);
2240 DC_UnlockDc(dc);
2241 return FALSE;
2242 }
2243
2244 DC_UnlockDc(dc);
2245 return Ret;
2246 }
2247
2248 BOOL
2249 STDCALL
2250 NtGdiGetAndSetDCDword(
2251 HDC hDC,
2252 UINT u,
2253 DWORD dwIn,
2254 DWORD *Result
2255 )
2256 {
2257 BOOL Ret = TRUE;
2258 PDC dc;
2259 PDC_ATTR Dc_Attr;
2260
2261 DWORD SafeResult = 0;
2262 NTSTATUS Status = STATUS_SUCCESS;
2263
2264 if(!Result)
2265 {
2266 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2267 return FALSE;
2268 }
2269
2270 dc = DC_LockDc(hDC);
2271 if(!dc)
2272 {
2273 SetLastWin32Error(ERROR_INVALID_HANDLE);
2274 return FALSE;
2275 }
2276 Dc_Attr = dc->pDc_Attr;
2277 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
2278
2279 switch (u)
2280 {
2281 case GdtGetSetCopyCount:
2282 break;
2283 case GdiGetSetTextAlign:
2284 SafeResult = Dc_Attr->lTextAlign;
2285 Dc_Attr->lTextAlign = dwIn;
2286 // Dc_Attr->flTextAlign = dwIn; // Flags!
2287 break;
2288 case GdiGetSetRelAbs:
2289 SafeResult = Dc_Attr->lRelAbs;
2290 Dc_Attr->lRelAbs = dwIn;
2291 break;
2292 case GdiGetSetTextCharExtra:
2293 SafeResult = Dc_Attr->lTextExtra;
2294 Dc_Attr->lTextExtra = dwIn;
2295 break;
2296 case GdiGetSetSelectFont:
2297 break;
2298 case GdiGetSetMapperFlagsInternal:
2299 break;
2300 case GdiGetSetMapMode:
2301 SafeResult = IntGdiSetMapMode( dc, dwIn);
2302 break;
2303 case GdiGetSetArcDirection:
2304 if (dwIn != AD_COUNTERCLOCKWISE && dwIn != AD_CLOCKWISE)
2305 {
2306 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2307 Ret = FALSE;
2308 }
2309 SafeResult = dc->w.ArcDirection;
2310 dc->w.ArcDirection = dwIn;
2311 break;
2312 default:
2313 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2314 Ret = FALSE;
2315 break;
2316 }
2317
2318 if (Ret)
2319 {
2320 _SEH_TRY
2321 {
2322 ProbeForWrite(Result,
2323 sizeof(DWORD),
2324 1);
2325 *Result = SafeResult;
2326 }
2327 _SEH_HANDLE
2328 {
2329 Status = _SEH_GetExceptionCode();
2330 }
2331 _SEH_END;
2332 }
2333
2334 if(!NT_SUCCESS(Status))
2335 {
2336 SetLastNtError(Status);
2337 DC_UnlockDc(dc);
2338 return FALSE;
2339 }
2340
2341 DC_UnlockDc(dc);
2342 return Ret;
2343 }
2344
2345 // ---------------------------------------------------- Private Interface
2346
2347 HDC FASTCALL
2348 DC_AllocDC(PUNICODE_STRING Driver)
2349 {
2350 PDC NewDC;
2351 PDC_ATTR Dc_Attr;
2352 HDC hDC;
2353 PWSTR Buf = NULL;
2354
2355 if (Driver != NULL)
2356 {
2357 Buf = ExAllocatePoolWithTag(PagedPool, Driver->MaximumLength, TAG_DC);
2358 if(!Buf)
2359 {
2360 return NULL;
2361 }
2362 RtlCopyMemory(Buf, Driver->Buffer, Driver->MaximumLength);
2363 }
2364
2365 hDC = (HDC) GDIOBJ_AllocObj(GdiHandleTable, GDI_OBJECT_TYPE_DC);
2366 if (hDC == NULL)
2367 {
2368 if(Buf)
2369 {
2370 ExFreePool(Buf);
2371 }
2372 return NULL;
2373 }
2374
2375 DC_AllocateDcAttr(hDC);
2376
2377 NewDC = DC_LockDc(hDC);
2378 /* FIXME - Handle NewDC == NULL! */
2379 if (Driver != NULL)
2380 {
2381 RtlCopyMemory(&NewDC->DriverName, Driver, sizeof(UNICODE_STRING));
2382 NewDC->DriverName.Buffer = Buf;
2383 }
2384 Dc_Attr = NewDC->pDc_Attr;
2385 if(!Dc_Attr) Dc_Attr = &NewDC->Dc_Attr;
2386
2387 NewDC->hHmgr = (HGDIOBJ) hDC; // Save the handle for this DC object.
2388 NewDC->w.xformWorld2Wnd.eM11 = 1.0f;
2389 NewDC->w.xformWorld2Wnd.eM12 = 0.0f;
2390 NewDC->w.xformWorld2Wnd.eM21 = 0.0f;
2391 NewDC->w.xformWorld2Wnd.eM22 = 1.0f;
2392 NewDC->w.xformWorld2Wnd.eDx = 0.0f;
2393 NewDC->w.xformWorld2Wnd.eDy = 0.0f;
2394 NewDC->w.xformWorld2Vport = NewDC->w.xformWorld2Wnd;
2395 NewDC->w.xformVport2World = NewDC->w.xformWorld2Wnd;
2396 NewDC->w.vport2WorldValid = TRUE;
2397
2398 // Setup syncing bits for the dcattr data packets.
2399 Dc_Attr->flXform = DEVICE_TO_PAGE_INVALID;
2400
2401 Dc_Attr->ulDirty_ = 0; // Server side
2402
2403 Dc_Attr->iMapMode = MM_TEXT;
2404
2405 Dc_Attr->szlWindowExt.cx = 1; // Float to Int,,, WRONG!
2406 Dc_Attr->szlWindowExt.cy = 1;
2407 Dc_Attr->szlViewportExt.cx = 1;
2408 Dc_Attr->szlViewportExt.cy = 1;
2409
2410 Dc_Attr->crForegroundClr = 0;
2411 Dc_Attr->ulForegroundClr = 0;
2412
2413 Dc_Attr->ulBackgroundClr = 0xffffff;
2414 Dc_Attr->crBackgroundClr = 0xffffff;
2415
2416 Dc_Attr->ulPenClr = RGB( 0, 0, 0 );
2417 Dc_Attr->crPenClr = RGB( 0, 0, 0 );
2418
2419 Dc_Attr->ulBrushClr = RGB( 255, 255, 255 ); // Do this way too.
2420 Dc_Attr->crBrushClr = RGB( 255, 255, 255 );
2421
2422 Dc_Attr->hlfntNew = NtGdiGetStockObject(SYSTEM_FONT);
2423 TextIntRealizeFont(Dc_Attr->hlfntNew);
2424
2425 NewDC->w.hPalette = NtGdiGetStockObject(DEFAULT_PALETTE);
2426
2427 DC_UnlockDc(NewDC);
2428
2429 return hDC;
2430 }
2431
2432 HDC FASTCALL
2433 DC_FindOpenDC(PUNICODE_STRING Driver)
2434 {
2435 return NULL;
2436 }
2437
2438 /*!
2439 * Initialize some common fields in the Device Context structure.
2440 */
2441 VOID FASTCALL
2442 DC_InitDC(HDC DCHandle)
2443 {
2444 // NtGdiRealizeDefaultPalette(DCHandle);
2445
2446 NtGdiSelectBrush(DCHandle, NtGdiGetStockObject( WHITE_BRUSH ));
2447 NtGdiSelectPen(DCHandle, NtGdiGetStockObject( BLACK_PEN ));
2448 //NtGdiSelectFont(DCHandle, hFont);
2449
2450 /*
2451 {
2452 int res;
2453 res = CLIPPING_UpdateGCRegion(DCToInit);
2454 ASSERT ( res != ERROR );
2455 }
2456 */
2457 }
2458
2459 VOID
2460 FASTCALL
2461 DC_AllocateDcAttr(HDC hDC)
2462 {
2463 PVOID NewMem = NULL;
2464 PDC pDC;
2465 HANDLE Pid = NtCurrentProcess();
2466 ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE it will allocate that size
2467
2468 NTSTATUS Status = ZwAllocateVirtualMemory(Pid,
2469 &NewMem,
2470 0,
2471 &MemSize,
2472 MEM_COMMIT|MEM_RESERVE,
2473 PAGE_READWRITE);
2474 KeEnterCriticalRegion();
2475 {
2476 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hDC);
2477 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
2478
2479 if (NT_SUCCESS(Status))
2480 {
2481 RtlZeroMemory(NewMem, MemSize);
2482 Entry->UserData = NewMem;
2483 DPRINT("DC_ATTR allocated! 0x%x\n",NewMem);
2484 }
2485 else
2486 {
2487 DPRINT("DC_ATTR not allocated!\n");
2488 }
2489 }
2490 KeLeaveCriticalRegion();
2491 pDC = DC_LockDc(hDC);
2492 if(NewMem)
2493 {
2494 pDC->pDc_Attr = NewMem; // Store pointer
2495 }
2496 DC_UnlockDc(pDC);
2497 }
2498
2499 VOID
2500 FASTCALL
2501 DC_FreeDcAttr(HDC DCToFree )
2502 {
2503 HANDLE Pid = NtCurrentProcess();
2504 PDC pDC = DC_LockDc(DCToFree);
2505 if (pDC->pDc_Attr == &pDC->Dc_Attr) return; // Internal DC object!
2506 pDC->pDc_Attr = NULL;
2507 DC_UnlockDc(pDC);
2508
2509 KeEnterCriticalRegion();
2510 {
2511 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)DCToFree);
2512 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
2513 if(Entry->UserData)
2514 {
2515 ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE;
2516 NTSTATUS Status = ZwFreeVirtualMemory(Pid,
2517 &Entry->UserData,
2518 &MemSize,
2519 MEM_RELEASE);
2520 if (NT_SUCCESS(Status))
2521 {
2522 DPRINT("DC_FreeDC DC_ATTR 0x%x\n", Entry->UserData);
2523 Entry->UserData = NULL;
2524 }
2525 }
2526 }
2527 KeLeaveCriticalRegion();
2528 }
2529
2530 VOID FASTCALL
2531 DC_FreeDC(HDC DCToFree)
2532 {
2533 DC_FreeDcAttr(DCToFree);
2534 if(!IsObjectDead( DCToFree ))
2535 {
2536 if (!GDIOBJ_FreeObj(GdiHandleTable, DCToFree, GDI_OBJECT_TYPE_DC))
2537 {
2538 DPRINT1("DC_FreeDC failed\n");
2539 }
2540 }
2541 else
2542 {
2543 DPRINT1("Attempted to Delete 0x%x currently being destroyed!!!\n",DCToFree);
2544 }
2545 }
2546
2547 BOOL INTERNAL_CALL
2548 DC_Cleanup(PVOID ObjectBody)
2549 {
2550 PDC pDC = (PDC)ObjectBody;
2551 RtlFreeUnicodeString(&pDC->DriverName);
2552 return TRUE;
2553 }
2554
2555 HDC FASTCALL
2556 DC_GetNextDC (PDC pDC)
2557 {
2558 return pDC->hNext;
2559 }
2560
2561 VOID FASTCALL
2562 DC_SetNextDC (PDC pDC, HDC hNextDC)
2563 {
2564 pDC->hNext = hNextDC;
2565 }
2566
2567 VOID FASTCALL
2568 DC_UpdateXforms(PDC dc)
2569 {
2570 XFORM xformWnd2Vport;
2571 FLOAT scaleX, scaleY;
2572 PDC_ATTR Dc_Attr = dc->pDc_Attr;
2573 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
2574
2575 /* Construct a transformation to do the window-to-viewport conversion */
2576 scaleX = (Dc_Attr->szlWindowExt.cx ? (FLOAT)Dc_Attr->szlViewportExt.cx / (FLOAT)Dc_Attr->szlWindowExt.cx : 0.0f);
2577 scaleY = (Dc_Attr->szlWindowExt.cy ? (FLOAT)Dc_Attr->szlViewportExt.cy / (FLOAT)Dc_Attr->szlWindowExt.cy : 0.0f);
2578 xformWnd2Vport.eM11 = scaleX;
2579 xformWnd2Vport.eM12 = 0.0;
2580 xformWnd2Vport.eM21 = 0.0;
2581 xformWnd2Vport.eM22 = scaleY;
2582 xformWnd2Vport.eDx = (FLOAT)Dc_Attr->ptlViewportOrg.x - scaleX * (FLOAT)Dc_Attr->ptlWindowOrg.x;
2583 xformWnd2Vport.eDy = (FLOAT)Dc_Attr->ptlViewportOrg.y - scaleY * (FLOAT)Dc_Attr->ptlWindowOrg.y;
2584
2585 /* Combine with the world transformation */
2586 IntGdiCombineTransform(&dc->w.xformWorld2Vport, &dc->w.xformWorld2Wnd, &xformWnd2Vport);
2587
2588 /* Create inverse of world-to-viewport transformation */
2589 dc->w.vport2WorldValid = DC_InvertXform(&dc->w.xformWorld2Vport, &dc->w.xformVport2World);
2590 }
2591
2592 BOOL FASTCALL
2593 DC_InvertXform(const XFORM *xformSrc,
2594 XFORM *xformDest)
2595 {
2596 FLOAT determinant;
2597
2598 determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
2599 if (determinant > -1e-12 && determinant < 1e-12)
2600 {
2601 return FALSE;
2602 }
2603
2604 xformDest->eM11 = xformSrc->eM22 / determinant;
2605 xformDest->eM12 = -xformSrc->eM12 / determinant;
2606 xformDest->eM21 = -xformSrc->eM21 / determinant;
2607 xformDest->eM22 = xformSrc->eM11 / determinant;
2608 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
2609 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
2610
2611 return TRUE;
2612 }
2613
2614 VOID FASTCALL
2615 DC_SetOwnership(HDC hDC, PEPROCESS Owner)
2616 {
2617 PDC DC;
2618
2619 GDIOBJ_SetOwnership(GdiHandleTable, hDC, Owner);
2620 DC = DC_LockDc(hDC);
2621 if (NULL != DC)
2622 {
2623 if (NULL != DC->w.hClipRgn)
2624 {
2625 GDIOBJ_CopyOwnership(GdiHandleTable, hDC, DC->w.hClipRgn);
2626 }
2627 if (NULL != DC->w.hVisRgn)
2628 {
2629 GDIOBJ_CopyOwnership(GdiHandleTable, hDC, DC->w.hVisRgn);
2630 }
2631 if (NULL != DC->w.hGCClipRgn)
2632 {
2633 GDIOBJ_CopyOwnership(GdiHandleTable, hDC, DC->w.hGCClipRgn);
2634 }
2635 DC_UnlockDc(DC);
2636 }
2637 }
2638
2639 //
2640 // Support multi display/device locks.
2641 //
2642 VOID
2643 FASTCALL
2644 DC_LockDisplay(HDC hDC)
2645 {
2646 PERESOURCE Resource;
2647 PDC dc = DC_LockDc(hDC);
2648 if (!dc) return;
2649 Resource = ((PGDIDEVICE)dc->pPDev)->hsemDevLock;
2650 DC_UnlockDc(dc);
2651 if (!Resource) return;
2652 KeEnterCriticalRegion();
2653 ExAcquireResourceExclusiveLite( Resource , TRUE);
2654 }
2655
2656 VOID
2657 FASTCALL
2658 DC_UnlockDisplay(HDC hDC)
2659 {
2660 PERESOURCE Resource;
2661 PDC dc = DC_LockDc(hDC);
2662 if (!dc) return;
2663 Resource = ((PGDIDEVICE)dc->pPDev)->hsemDevLock;
2664 DC_UnlockDc(dc);
2665 if (!Resource) return;
2666 ExReleaseResourceLite( Resource );
2667 KeLeaveCriticalRegion();
2668 }
2669
2670 BOOL FASTCALL
2671 IntIsPrimarySurface(SURFOBJ *SurfObj)
2672 {
2673 if (PrimarySurface.pSurface == NULL)
2674 {
2675 return FALSE;
2676 }
2677 return SurfObj->hsurf == PrimarySurface.pSurface;
2678 }
2679
2680 //
2681 // Enumerate HDev
2682 //
2683 PGDIDEVICE FASTCALL
2684 IntEnumHDev(VOID)
2685 {
2686 // I guess we will soon have more than one primary surface.
2687 // This will do for now.
2688 return &PrimarySurface;
2689 }
2690
2691 #define SIZEOF_DEVMODEW_300 188
2692 #define SIZEOF_DEVMODEW_400 212
2693 #define SIZEOF_DEVMODEW_500 220
2694
2695 static NTSTATUS FASTCALL
2696 GetDisplayNumberFromDeviceName(
2697 IN PUNICODE_STRING pDeviceName OPTIONAL,
2698 OUT ULONG *DisplayNumber)
2699 {
2700 UNICODE_STRING DisplayString = RTL_CONSTANT_STRING(L"\\\\.\\DISPLAY");
2701 NTSTATUS Status = STATUS_SUCCESS;
2702 ULONG Length;
2703 ULONG Number;
2704 ULONG i;
2705
2706 if (DisplayNumber == NULL)
2707 return STATUS_INVALID_PARAMETER_2;
2708
2709 if (pDeviceName && pDeviceName->Length <= DisplayString.Length)
2710 return STATUS_OBJECT_NAME_INVALID;
2711
2712 if (pDeviceName == NULL || pDeviceName->Length == 0)
2713 {
2714 PWINDOW_OBJECT DesktopObject;
2715 HDC DesktopHDC;
2716 PDC pDC;
2717
2718 DesktopObject = UserGetDesktopWindow();
2719 DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
2720 pDC = DC_LockDc(DesktopHDC);
2721
2722 *DisplayNumber = ((GDIDEVICE *)pDC->pPDev)->DisplayNumber;
2723
2724 DC_UnlockDc(pDC);
2725 UserReleaseDC(DesktopObject, DesktopHDC, FALSE);
2726
2727 return STATUS_SUCCESS;
2728 }
2729
2730 /* Hack to check if the first parts are equal, by faking the device name length */
2731 Length = pDeviceName->Length;
2732 pDeviceName->Length = DisplayString.Length;
2733 if (RtlEqualUnicodeString(&DisplayString, pDeviceName, FALSE) == FALSE)
2734 Status = STATUS_OBJECT_NAME_INVALID;
2735 pDeviceName->Length = Length;
2736
2737 if (NT_SUCCESS(Status))
2738 {
2739 /* Convert the last part of pDeviceName to a number */
2740 Number = 0;
2741 Length = pDeviceName->Length / sizeof(WCHAR);
2742 for (i = DisplayString.Length / sizeof(WCHAR); i < Length; i++)
2743 {
2744 WCHAR Char = pDeviceName->Buffer[i];
2745 if (Char >= L'0' && Char <= L'9')
2746 Number = Number * 10 + Char - L'0';
2747 else if (Char != L'\0')
2748 return STATUS_OBJECT_NAME_INVALID;
2749 }
2750
2751 *DisplayNumber = Number - 1;
2752 }
2753
2754 return Status;
2755 }
2756
2757 /*! \brief Enumerate possible display settings for the given display...
2758 *
2759 * \todo Make thread safe!?
2760 * \todo Don't ignore pDeviceName
2761 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
2762 */
2763 BOOL FASTCALL
2764 IntEnumDisplaySettings(
2765 IN PUNICODE_STRING pDeviceName OPTIONAL,
2766 IN DWORD iModeNum,
2767 IN OUT LPDEVMODEW pDevMode,
2768 IN DWORD dwFlags)
2769 {
2770 static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
2771 static DWORD SizeOfCachedDevModes = 0;
2772 static UNICODE_STRING CachedDeviceName;
2773 PDEVMODEW CachedMode = NULL;
2774 DEVMODEW DevMode;
2775 ULONG DisplayNumber;
2776
2777 if (!NT_SUCCESS(GetDisplayNumberFromDeviceName(pDeviceName, &DisplayNumber)))
2778 {
2779 SetLastWin32Error(STATUS_NO_SUCH_DEVICE);
2780 return FALSE;
2781 }
2782
2783 DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
2784 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
2785 if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
2786 pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
2787 pDevMode->dmSize != SIZEOF_DEVMODEW_500)
2788 {
2789 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2790 return FALSE;
2791 }
2792
2793 if (iModeNum == ENUM_CURRENT_SETTINGS)
2794 {
2795 CachedMode = &PrimarySurface.DMW;
2796 ASSERT(CachedMode->dmSize > 0);
2797 }
2798 else if (iModeNum == ENUM_REGISTRY_SETTINGS)
2799 {
2800 RtlZeroMemory(&DevMode, sizeof (DevMode));
2801 DevMode.dmSize = sizeof (DevMode);
2802 DevMode.dmDriverExtra = 0;
2803 if (SetupDevMode(&DevMode, DisplayNumber))
2804 CachedMode = &DevMode;
2805 else
2806 {
2807 SetLastWin32Error(0); /* FIXME: use error code */
2808 return FALSE;
2809 }
2810 /* FIXME: Maybe look for the matching devmode supplied by the
2811 * driver so we can provide driver private/extra data?
2812 */
2813 }
2814 else
2815 {
2816 BOOL IsCachedDevice = (CachedDevModes != NULL);
2817
2818 if (CachedDevModes &&
2819 ((pDeviceName == NULL && CachedDeviceName.Length > 0) ||
2820 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length == 0) ||
2821 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length > 0 && RtlEqualUnicodeString(pDeviceName, &CachedDeviceName, TRUE) == FALSE)))
2822 {
2823 IsCachedDevice = FALSE;
2824 }
2825
2826 if (iModeNum == 0 || IsCachedDevice == FALSE) /* query modes from drivers */
2827 {
2828 UNICODE_STRING DriverFileNames;
2829 LPWSTR CurrentName;
2830 DRVENABLEDATA DrvEnableData;
2831
2832 /* Free resources from last driver cache */
2833 if (IsCachedDevice == FALSE && CachedDeviceName.Buffer != NULL)
2834 {
2835 RtlFreeUnicodeString(&CachedDeviceName);
2836 }
2837
2838 /* Retrieve DDI driver names from registry */
2839 RtlInitUnicodeString(&DriverFileNames, NULL);
2840 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
2841 {
2842 DPRINT1("FindDriverFileNames failed\n");
2843 return FALSE;
2844 }
2845
2846 if (!IntPrepareDriverIfNeeded())
2847 {
2848 DPRINT1("IntPrepareDriverIfNeeded failed\n");
2849 return FALSE;
2850 }
2851
2852 /*
2853 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
2854 * scan all of them until a good one found.
2855 */
2856 CurrentName = DriverFileNames.Buffer;
2857 for (;CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR));
2858 CurrentName += wcslen(CurrentName) + 1)
2859 {
2860 INT i;
2861 PGD_ENABLEDRIVER GDEnableDriver;
2862 PGD_GETMODES GetModes = NULL;
2863 INT SizeNeeded, SizeUsed;
2864
2865 /* Get the DDI driver's entry point */
2866 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
2867 GDEnableDriver = DRIVER_FindExistingDDIDriver(L"DISPLAY");
2868 if (NULL == GDEnableDriver)
2869 {
2870 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
2871 continue;
2872 }
2873
2874 /* Call DDI driver's EnableDriver function */
2875 RtlZeroMemory(&DrvEnableData, sizeof(DrvEnableData));
2876
2877 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData))
2878 {
2879 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
2880 continue;
2881 }
2882
2883 CachedDevModesEnd = CachedDevModes;
2884
2885 /* find DrvGetModes function */
2886 for (i = 0; i < DrvEnableData.c; i++)
2887 {
2888 PDRVFN DrvFn = DrvEnableData.pdrvfn + i;
2889
2890 if (DrvFn->iFunc == INDEX_DrvGetModes)
2891 {
2892 GetModes = (PGD_GETMODES)DrvFn->pfn;
2893 break;
2894 }
2895 }
2896
2897 if (GetModes == NULL)
2898 {
2899 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName);
2900 continue;
2901 }
2902
2903 /* make sure we have enough memory to hold the modes */
2904 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL);
2905 if (SizeNeeded <= 0)
2906 {
2907 DPRINT("DrvGetModes failed for %S\n", CurrentName);
2908 break;
2909 }
2910
2911 SizeUsed = (PCHAR)CachedDevModesEnd - (PCHAR)CachedDevModes;
2912 if (SizeOfCachedDevModes < SizeUsed + SizeNeeded)
2913 {
2914 PVOID NewBuffer;
2915
2916 SizeOfCachedDevModes += SizeNeeded;
2917 NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes);
2918 if (NewBuffer == NULL)
2919 {
2920 /* clean up */
2921 ExFreePool(CachedDevModes);
2922 CachedDevModes = NULL;
2923 CachedDevModesEnd = NULL;
2924 SizeOfCachedDevModes = 0;
2925
2926 if (CachedDeviceName.Buffer != NULL)
2927 RtlFreeUnicodeString(&CachedDeviceName);
2928
2929 SetLastWin32Error(STATUS_NO_MEMORY);
2930 return FALSE;
2931 }
2932 if (CachedDevModes != NULL)
2933 {
2934 RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed);
2935 ExFreePool(CachedDevModes);
2936 }
2937 CachedDevModes = NewBuffer;
2938 CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
2939 }
2940
2941 if (!IsCachedDevice)
2942 {
2943 if (CachedDeviceName.Buffer != NULL)
2944 RtlFreeUnicodeString(&CachedDeviceName);
2945
2946 if (pDeviceName)
2947 IntSafeCopyUnicodeString(&CachedDeviceName, pDeviceName);
2948
2949 IsCachedDevice = TRUE;
2950 }
2951
2952 /* query modes */
2953 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
2954 SizeNeeded,
2955 CachedDevModesEnd);
2956 if (SizeNeeded <= 0)
2957 {
2958 DPRINT("DrvGetModes failed for %S\n", CurrentName);
2959 }
2960 else
2961 {
2962 CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded);
2963 }
2964 }
2965
2966 RtlFreeUnicodeString(&DriverFileNames);
2967 }
2968
2969 /* return cached info */
2970 CachedMode = CachedDevModes;
2971 if (CachedMode >= CachedDevModesEnd)
2972 {
2973 SetLastWin32Error(STATUS_NO_MORE_ENTRIES);
2974 return FALSE;
2975 }
2976 while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd)
2977 {
2978 assert(CachedMode->dmSize > 0);
2979 CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra);
2980 }
2981 if (CachedMode >= CachedDevModesEnd)
2982 {
2983 SetLastWin32Error(STATUS_NO_MORE_ENTRIES);
2984 return FALSE;
2985 }
2986 }
2987
2988 ASSERT(CachedMode != NULL);
2989
2990 RtlCopyMemory(pDevMode, CachedMode, min(pDevMode->dmSize, CachedMode->dmSize));
2991 RtlZeroMemory(pDevMode + pDevMode->dmSize, pDevMode->dmDriverExtra);
2992 RtlCopyMemory(pDevMode + min(pDevMode->dmSize, CachedMode->dmSize), CachedMode + CachedMode->dmSize, min(pDevMode->dmDriverExtra, CachedMode->dmDriverExtra));
2993
2994 return TRUE;
2995 }
2996
2997 static NTSTATUS FASTCALL
2998 GetVideoDeviceName(
2999 OUT PUNICODE_STRING VideoDeviceName,
3000 IN PCUNICODE_STRING DisplayDevice) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
3001 {
3002 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\??\\");
3003 UNICODE_STRING ObjectName;
3004 UNICODE_STRING KernelModeName = { 0, };
3005 OBJECT_ATTRIBUTES ObjectAttributes;
3006 USHORT LastSlash;
3007 ULONG Length;
3008 HANDLE LinkHandle = NULL;
3009 NTSTATUS Status;
3010
3011 RtlInitUnicodeString(VideoDeviceName, NULL);
3012
3013 /* Get device name (DisplayDevice is "\.\xxx") */
3014 for (LastSlash = DisplayDevice->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
3015 {
3016 if (DisplayDevice->Buffer[LastSlash - 1] == L'\\')
3017 break;
3018 }
3019
3020 if (LastSlash == 0)
3021 {
3022 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice);
3023 Status = STATUS_OBJECT_NAME_INVALID;
3024 goto cleanup;
3025 }
3026 ObjectName = *DisplayDevice;
3027 ObjectName.Length -= LastSlash * sizeof(WCHAR);
3028 ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
3029 ObjectName.Buffer += LastSlash;
3030
3031 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
3032 KernelModeName.MaximumLength = Prefix.Length + ObjectName.Length + sizeof(UNICODE_NULL);
3033 KernelModeName.Buffer = ExAllocatePoolWithTag(PagedPool,
3034 KernelModeName.MaximumLength,
3035 TAG_DC);
3036 if (!KernelModeName.Buffer)
3037 {
3038 Status = STATUS_NO_MEMORY;
3039 goto cleanup;
3040 }
3041 RtlCopyUnicodeString(&KernelModeName, &Prefix);
3042 Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
3043 if (!NT_SUCCESS(Status))
3044 goto cleanup;
3045
3046 /* Open \??\xxx (ex: "\??\DISPLAY1") */
3047 InitializeObjectAttributes(&ObjectAttributes,
3048 &KernelModeName,
3049 OBJ_KERNEL_HANDLE,
3050 NULL,
3051 NULL);
3052 Status = ZwOpenSymbolicLinkObject(&LinkHandle,
3053 GENERIC_READ,
3054 &ObjectAttributes);
3055 if (!NT_SUCCESS(Status))
3056 {
3057 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
3058 Status = STATUS_NO_SUCH_DEVICE;
3059 goto cleanup;
3060 }
3061
3062 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, &Length);
3063 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
3064 {
3065 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
3066 Status = STATUS_NO_SUCH_DEVICE;
3067 goto cleanup;
3068 }
3069 VideoDeviceName->MaximumLength = Length;
3070 VideoDeviceName->Buffer = ExAllocatePoolWithTag(PagedPool,
3071 VideoDeviceName->MaximumLength + sizeof(UNICODE_NULL),
3072 TAG_DC);
3073 if (!VideoDeviceName->Buffer)
3074 {
3075 Status = STATUS_NO_MEMORY;
3076 goto cleanup;
3077 }
3078 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, NULL);
3079 VideoDeviceName->Buffer[VideoDeviceName->MaximumLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
3080 if (!NT_SUCCESS(Status))
3081 {
3082 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
3083 Status = STATUS_NO_SUCH_DEVICE;
3084 goto cleanup;
3085 }
3086 Status = STATUS_SUCCESS;
3087
3088 cleanup:
3089 if (!NT_SUCCESS(Status) && VideoDeviceName->Buffer)
3090 ExFreePoolWithTag(VideoDeviceName->Buffer, TAG_DC);
3091 if (KernelModeName.Buffer)
3092 ExFreePoolWithTag(KernelModeName.Buffer, TAG_DC);
3093 if (LinkHandle)
3094 ZwClose(LinkHandle);
3095 return Status;
3096 }
3097
3098 static NTSTATUS FASTCALL
3099 GetVideoRegistryKey(
3100 OUT PUNICODE_STRING RegistryPath,
3101 IN PCUNICODE_STRING DeviceName) /* ex: "\Device\Video0" */
3102 {
3103 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
3104 NTSTATUS Status;
3105
3106 RtlInitUnicodeString(RegistryPath, NULL);
3107 RtlZeroMemory(QueryTable, sizeof(QueryTable));
3108 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
3109 QueryTable[0].Name = DeviceName->Buffer;
3110 QueryTable[0].EntryContext = RegistryPath;
3111
3112 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
3113 L"VIDEO",
3114 QueryTable,
3115 NULL,
3116 NULL);
3117 if (!NT_SUCCESS(Status))
3118 {
3119 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName, Status);
3120 return STATUS_NO_SUCH_DEVICE;
3121 }
3122
3123 DPRINT("RegistryPath %wZ\n", RegistryPath);
3124 return STATUS_SUCCESS;
3125 }
3126
3127 LONG
3128 FASTCALL
3129 IntChangeDisplaySettings(
3130 IN PUNICODE_STRING pDeviceName OPTIONAL,
3131 IN LPDEVMODEW DevMode,
3132 IN DWORD dwflags,
3133 IN PVOID lParam OPTIONAL)
3134 {
3135 BOOLEAN Global = FALSE;
3136 BOOLEAN NoReset = FALSE;
3137 BOOLEAN Reset = FALSE;
3138 BOOLEAN SetPrimary = FALSE;
3139 LONG Ret=0;
3140 NTSTATUS Status ;
3141
3142 DPRINT1("display flags : %x\n",dwflags);
3143
3144 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
3145 {
3146 /* Check global, reset and noreset flags */
3147 if ((dwflags & CDS_GLOBAL) == CDS_GLOBAL)
3148 Global = TRUE;
3149 if ((dwflags & CDS_NORESET) == CDS_NORESET)
3150 NoReset = TRUE;
3151 dwflags &= ~(CDS_GLOBAL | CDS_NORESET);
3152 }
3153 if ((dwflags & CDS_RESET) == CDS_RESET)
3154 Reset = TRUE;
3155 if ((dwflags & CDS_SET_PRIMARY) == CDS_SET_PRIMARY)
3156 SetPrimary = TRUE;
3157 dwflags &= ~(CDS_RESET | CDS_SET_PRIMARY);
3158
3159 if (Reset && NoReset)
3160 return DISP_CHANGE_BADFLAGS;
3161
3162 if (dwflags == 0)
3163 {
3164 /* Dynamically change graphics mode */
3165 DPRINT1("flag 0 UNIMPLEMENTED\n");
3166 return DISP_CHANGE_FAILED;
3167 }
3168
3169 if ((dwflags & CDS_TEST) == CDS_TEST)
3170 {
3171 /* Test reslution */
3172 dwflags &= ~CDS_TEST;
3173 DPRINT1("flag CDS_TEST UNIMPLEMENTED\n");
3174 Ret = DISP_CHANGE_FAILED;
3175 }
3176
3177 if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
3178 {
3179 DEVMODEW lpDevMode;
3180 /* Full Screen */
3181 dwflags &= ~CDS_FULLSCREEN;
3182 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
3183 Ret = DISP_CHANGE_FAILED;
3184
3185 RtlZeroMemory(&lpDevMode, sizeof(DEVMODEW));
3186 lpDevMode.dmSize = sizeof(DEVMODEW);
3187
3188 if (!IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0))
3189 return DISP_CHANGE_FAILED;
3190
3191 DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
3192 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
3193
3194
3195 if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
3196 (lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) &&
3197 (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
3198 Ret = DISP_CHANGE_SUCCESSFUL;
3199 }
3200
3201 if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
3202 {
3203 dwflags &= ~CDS_VIDEOPARAMETERS;
3204 if (lParam == NULL)
3205 Ret=DISP_CHANGE_BADPARAM;
3206 else
3207 {
3208 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
3209 Ret = DISP_CHANGE_FAILED;
3210 }
3211
3212 }
3213
3214 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
3215 {
3216
3217 UNICODE_STRING DeviceName;
3218 UNICODE_STRING RegistryKey;
3219 UNICODE_STRING InDeviceName;
3220 OBJECT_ATTRIBUTES ObjectAttributes;
3221 HANDLE DevInstRegKey;
3222 ULONG NewValue;
3223
3224 DPRINT1("set CDS_UPDATEREGISTRY\n");
3225
3226 dwflags &= ~CDS_UPDATEREGISTRY;
3227
3228 /* Check if pDeviceName is NULL, we need to retrieve it */
3229 if (pDeviceName == NULL)
3230 {
3231 WCHAR szBuffer[MAX_DRIVER_NAME];
3232 PDC DC;
3233 PWINDOW_OBJECT Wnd=NULL;
3234 HWND hWnd;
3235 HDC hDC;
3236
3237 hWnd = IntGetDesktopWindow();
3238 if (!(Wnd = UserGetWindowObject(hWnd)))
3239 {
3240 return FALSE;
3241 }
3242
3243 hDC = (HDC)UserGetWindowDC(Wnd);
3244
3245 DC = DC_LockDc(hDC);
3246 if (NULL == DC)
3247 {
3248 return FALSE;
3249 }
3250 swprintf (szBuffer, L"\\\\.\\DISPLAY%lu", ((GDIDEVICE *)DC->pPDev)->DisplayNumber);
3251 DC_UnlockDc(DC);
3252
3253 RtlInitUnicodeString(&InDeviceName, szBuffer);
3254 pDeviceName = &InDeviceName;
3255 }
3256
3257 Status = GetVideoDeviceName(&DeviceName, pDeviceName);
3258 if (!NT_SUCCESS(Status))
3259 {
3260 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName, Status);
3261 return DISP_CHANGE_FAILED;
3262 }
3263 Status = GetVideoRegistryKey(&RegistryKey, &DeviceName);
3264 if (!NT_SUCCESS(Status))
3265 {
3266 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName, Status);
3267 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
3268 return DISP_CHANGE_FAILED;
3269 }
3270 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
3271
3272 InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
3273 OBJ_CASE_INSENSITIVE, NULL, NULL);
3274 Status = ZwOpenKey(&DevInstRegKey, GENERIC_READ | GENERIC_WRITE, &ObjectAttributes);
3275 if (!NT_SUCCESS(Status))
3276 {
3277 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey, Status);
3278 ExFreePoolWithTag(RegistryKey.Buffer, TAG_DC);
3279 return DISP_CHANGE_FAILED;
3280 }
3281 ExFreePoolWithTag(RegistryKey.Buffer, TAG_DC);
3282
3283 /* Update needed fields */
3284 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
3285 {
3286 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
3287 NewValue = DevMode->dmBitsPerPel;
3288 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3289 }
3290
3291 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
3292 {
3293 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
3294 NewValue = DevMode->dmPelsWidth;
3295 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3296 }
3297
3298 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
3299 {
3300 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
3301 NewValue = DevMode->dmPelsHeight;
3302 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3303 }
3304
3305 ZwClose(DevInstRegKey);
3306 if (NT_SUCCESS(Status))
3307 Ret = DISP_CHANGE_RESTART;
3308 else
3309 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
3310 Ret = DISP_CHANGE_NOTUPDATED;
3311 }
3312
3313 if (dwflags != 0)
3314 Ret = DISP_CHANGE_BADFLAGS;
3315
3316 return Ret;
3317 }
3318
3319 DWORD
3320 APIENTRY
3321 NtGdiGetBoundsRect(
3322 IN HDC hdc,
3323 OUT LPRECT prc,
3324 IN DWORD f)
3325 {
3326 DPRINT1("stub");
3327 return DCB_RESET; /* bounding rectangle always empty */
3328 }
3329
3330 DWORD
3331 APIENTRY
3332 NtGdiSetBoundsRect(
3333 IN HDC hdc,
3334 IN LPRECT prc,
3335 IN DWORD f)
3336 {
3337 DPRINT1("stub");
3338 return DCB_DISABLE; /* bounding rectangle always empty */
3339 }
3340
3341 BOOL
3342 STDCALL
3343 NtGdiGetAspectRatioFilterEx(HDC hDC,
3344 LPSIZE AspectRatio)
3345 {
3346 UNIMPLEMENTED;
3347 return FALSE;
3348 }
3349
3350 /*
3351 * @implemented
3352 */
3353 DHPDEV
3354 NtGdiGetDhpdev(
3355 IN HDEV hdev)
3356 {
3357 PGDIDEVICE pPDev, pGdiDevice = (PGDIDEVICE) hdev;
3358 if (!pGdiDevice) return NULL;
3359 if ( pGdiDevice < (PGDIDEVICE)MmSystemRangeStart) return NULL;
3360 pPDev = &PrimarySurface;
3361 KeEnterCriticalRegion();
3362 do
3363 {
3364 if (pGdiDevice == pPDev) break;
3365 else
3366 pPDev = pPDev->ppdevNext;
3367 } while (pPDev != NULL);
3368 KeLeaveCriticalRegion();
3369 if (!pPDev) return NULL;
3370 return pGdiDevice->hPDev;
3371 }
3372
3373 /* EOF */