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