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