0d0df02591f70d0fe6c7d0716b75832c4d3ed8e0
[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;
1791 LPVOID SafeBuf;
1792 NTSTATUS Status = STATUS_SUCCESS;
1793
1794 /* From Wine: GetObject does not SetLastError() on a null object */
1795 if (!handle) return 0;
1796
1797 if (count <= 0)
1798 {
1799 return 0;
1800 }
1801
1802 _SEH_TRY
1803 {
1804 ProbeForWrite(buffer,
1805 count,
1806 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 0;
1818 }
1819
1820 SafeBuf = ExAllocatePoolWithTag(PagedPool, count, TAG_GDIOBJ);
1821 if(!SafeBuf)
1822 {
1823 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1824 return 0;
1825 }
1826
1827 Ret = IntGdiGetObject(handle, count, SafeBuf);
1828
1829 _SEH_TRY
1830 {
1831 /* pointer already probed! */
1832 RtlCopyMemory(buffer,
1833 SafeBuf,
1834 count);
1835 }
1836 _SEH_HANDLE
1837 {
1838 Status = _SEH_GetExceptionCode();
1839 }
1840 _SEH_END;
1841
1842 ExFreePool(SafeBuf);
1843 if(!NT_SUCCESS(Status))
1844 {
1845 SetLastNtError(Status);
1846 return 0;
1847 }
1848
1849 return Ret;
1850 }
1851
1852 DWORD STDCALL
1853 NtGdiGetObjectType(HANDLE handle)
1854 {
1855 GDIOBJHDR * ptr;
1856 INT result;
1857 DWORD objectType;
1858
1859 ptr = GDIOBJ_LockObj(GdiHandleTable, handle, GDI_OBJECT_TYPE_DONTCARE);
1860 if (ptr == 0)
1861 {
1862 SetLastWin32Error(ERROR_INVALID_HANDLE);
1863 return 0;
1864 }
1865
1866 objectType = GDIOBJ_GetObjectType(handle);
1867 switch(objectType)
1868 {
1869 case GDI_OBJECT_TYPE_PEN:
1870 result = OBJ_PEN;
1871 break;
1872 case GDI_OBJECT_TYPE_BRUSH:
1873 result = OBJ_BRUSH;
1874 break;
1875 case GDI_OBJECT_TYPE_BITMAP:
1876 result = OBJ_BITMAP;
1877 break;
1878 case GDI_OBJECT_TYPE_FONT:
1879 result = OBJ_FONT;
1880 break;
1881 case GDI_OBJECT_TYPE_PALETTE:
1882 result = OBJ_PAL;
1883 break;
1884 case GDI_OBJECT_TYPE_REGION:
1885 result = OBJ_REGION;
1886 break;
1887 case GDI_OBJECT_TYPE_DC:
1888 result = OBJ_DC;
1889 break;
1890 case GDI_OBJECT_TYPE_METADC:
1891 result = OBJ_METADC;
1892 break;
1893 case GDI_OBJECT_TYPE_METAFILE:
1894 result = OBJ_METAFILE;
1895 break;
1896 case GDI_OBJECT_TYPE_ENHMETAFILE:
1897 result = OBJ_ENHMETAFILE;
1898 break;
1899 case GDI_OBJECT_TYPE_ENHMETADC:
1900 result = OBJ_ENHMETADC;
1901 break;
1902 case GDI_OBJECT_TYPE_EXTPEN:
1903 result = OBJ_EXTPEN;
1904 break;
1905 case GDI_OBJECT_TYPE_MEMDC:
1906 result = OBJ_MEMDC;
1907 break;
1908
1909 default:
1910 DPRINT1("Magic 0x%08x not implemented\n", objectType);
1911 result = 0;
1912 break;
1913 }
1914 GDIOBJ_UnlockObjByPtr(GdiHandleTable, ptr);
1915 return result;
1916 }
1917
1918 DC_GET_VAL( INT, NtGdiGetRelAbs, w.relAbsMode )
1919 DC_GET_VAL( INT, NtGdiGetROP2, w.ROPmode )
1920 DC_GET_VAL( INT, NtGdiGetStretchBltMode, w.stretchBltMode )
1921 DC_GET_VAL( UINT, NtGdiGetTextAlign, w.textAlign )
1922 DC_GET_VAL( COLORREF, NtGdiGetTextColor, w.textColor )
1923 DC_GET_VAL_EX( GetViewportExtEx, vportExtX, vportExtY, SIZE, cx, cy )
1924 DC_GET_VAL_EX( GetViewportOrgEx, vportOrgX, vportOrgY, POINT, x, y )
1925 DC_GET_VAL_EX( GetWindowExtEx, wndExtX, wndExtY, SIZE, cx, cy )
1926 DC_GET_VAL_EX( GetWindowOrgEx, wndOrgX, wndOrgY, POINT, x, y )
1927
1928 BOOL
1929 APIENTRY
1930 NtGdiResetDC(
1931 IN HDC hdc,
1932 IN LPDEVMODEW pdm,
1933 OUT PBOOL pbBanding,
1934 IN OPTIONAL VOID *pDriverInfo2,
1935 OUT VOID *ppUMdhpdev)
1936 {
1937 UNIMPLEMENTED;
1938 return 0;
1939 }
1940
1941 BOOL STDCALL
1942 NtGdiRestoreDC(HDC hDC, INT SaveLevel)
1943 {
1944 PDC dc, dcs;
1945 BOOL success;
1946
1947 DPRINT("NtGdiRestoreDC(%lx, %d)\n", hDC, SaveLevel);
1948
1949 dc = DC_LockDc(hDC);
1950 if (!dc)
1951 {
1952 SetLastWin32Error(ERROR_INVALID_HANDLE);
1953 return FALSE;
1954 }
1955
1956 if(abs(SaveLevel) > dc->saveLevel || SaveLevel == 0)
1957 {
1958 DC_UnlockDc(dc);
1959 return FALSE;
1960 }
1961
1962 /* FIXME this calc are not 100% correct I think ??*/
1963 if (SaveLevel < 0) SaveLevel = dc->saveLevel + SaveLevel + 1;
1964
1965 success=TRUE;
1966 while (dc->saveLevel >= SaveLevel)
1967 {
1968 HDC hdcs = DC_GetNextDC (dc);
1969
1970 dcs = DC_LockDc (hdcs);
1971 if (dcs == NULL)
1972 {
1973 DC_UnlockDc(dc);
1974 return FALSE;
1975 }
1976
1977 DC_SetNextDC (dc, DC_GetNextDC (dcs));
1978 dcs->hNext = 0;
1979
1980 if (--dc->saveLevel < SaveLevel)
1981 {
1982 DC_UnlockDc( dc );
1983 DC_UnlockDc( dcs );
1984
1985 NtGdiSetDCState(hDC, hdcs);
1986 //if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
1987 /* FIXME: This might not be quite right, since we're
1988 * returning FALSE but still destroying the saved DC state
1989 */
1990 success=FALSE;
1991 dc = DC_LockDc(hDC);
1992 if(!dc)
1993 {
1994 return FALSE;
1995 }
1996 }
1997 else
1998 {
1999 DC_UnlockDc( dcs );
2000 }
2001 NtGdiDeleteObjectApp (hdcs);
2002 }
2003 DC_UnlockDc( dc );
2004 return success;
2005 }
2006
2007
2008 INT STDCALL
2009 NtGdiSaveDC(HDC hDC)
2010 {
2011 HDC hdcs;
2012 PDC dc, dcs;
2013 INT ret;
2014
2015 DPRINT("NtGdiSaveDC(%lx)\n", hDC);
2016
2017 if (!(hdcs = NtGdiGetDCState(hDC)))
2018 {
2019 return 0;
2020 }
2021
2022 dcs = DC_LockDc (hdcs);
2023 if (dcs == NULL)
2024 {
2025 SetLastWin32Error(ERROR_INVALID_HANDLE);
2026 return 0;
2027 }
2028 dc = DC_LockDc (hDC);
2029 if (dc == NULL)
2030 {
2031 DC_UnlockDc(dcs);
2032 SetLastWin32Error(ERROR_INVALID_HANDLE);
2033 return 0;
2034 }
2035
2036 #if 0
2037 /* Copy path. The reason why path saving / restoring is in SaveDC/
2038 * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
2039 * functions are only in Win16 (which doesn't have paths) and that
2040 * SetDCState doesn't allow us to signal an error (which can happen
2041 * when copying paths).
2042 */
2043 if (!PATH_AssignGdiPath (&dcs->w.path, &dc->w.path))
2044 {
2045 NtGdiDeleteObjectApp (hdcs);
2046 return 0;
2047 }
2048 #endif
2049
2050 DC_SetNextDC (dcs, DC_GetNextDC (dc));
2051 DC_SetNextDC (dc, hdcs);
2052 ret = ++dc->saveLevel;
2053 DC_UnlockDc( dcs );
2054 DC_UnlockDc( dc );
2055
2056 return ret;
2057 }
2058
2059 HGDIOBJ
2060 STDCALL
2061 NtGdiSelectObject(HDC hDC, HGDIOBJ hGDIObj)
2062 {
2063 HGDIOBJ objOrg = NULL; // default to failure
2064 BITMAPOBJ *pb;
2065 PDC dc;
2066 PGDIBRUSHOBJ pen;
2067 PGDIBRUSHOBJ brush;
2068 XLATEOBJ *XlateObj;
2069 DWORD objectType;
2070 HRGN hVisRgn;
2071 BOOLEAN Failed;
2072
2073 if (!hDC || !hGDIObj)
2074 {
2075 /* From Wine:
2076 * SelectObject() with a NULL DC returns 0 and sets ERROR_INVALID_HANDLE.
2077 * Note: Under XP at least invalid ptrs can also be passed, not just NULL;
2078 * Don't test that here in case it crashes earlier win versions.
2079 */
2080 if (!hDC) SetLastWin32Error(ERROR_INVALID_HANDLE);
2081 return NULL;
2082 }
2083
2084 dc = DC_LockDc(hDC);
2085 if (NULL == dc)
2086 {
2087 SetLastWin32Error(ERROR_INVALID_HANDLE);
2088 return NULL;
2089 }
2090
2091 objectType = GDIOBJ_GetObjectType(hGDIObj);
2092
2093 switch (objectType)
2094 {
2095 case GDI_OBJECT_TYPE_PEN:
2096 pen = PENOBJ_LockPen((HPEN) hGDIObj);
2097 if (pen == NULL)
2098 {
2099 SetLastWin32Error(ERROR_INVALID_HANDLE);
2100 break;
2101 }
2102
2103 XlateObj = IntGdiCreateBrushXlate(dc, pen, &Failed);
2104 PENOBJ_UnlockPen(pen);
2105 if (Failed)
2106 {
2107 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
2108 break;
2109 }
2110
2111 objOrg = (HGDIOBJ)dc->w.hPen;
2112 dc->w.hPen = hGDIObj;
2113 if (dc->XlatePen != NULL)
2114 EngDeleteXlate(dc->XlatePen);
2115 dc->XlatePen = XlateObj;
2116 break;
2117
2118 case GDI_OBJECT_TYPE_BRUSH:
2119 brush = BRUSHOBJ_LockBrush((HPEN) hGDIObj);
2120 if (brush == NULL)
2121 {
2122 SetLastWin32Error(ERROR_INVALID_HANDLE);
2123 break;
2124 }
2125
2126 XlateObj = IntGdiCreateBrushXlate(dc, brush, &Failed);
2127 BRUSHOBJ_UnlockBrush(brush);
2128 if (Failed)
2129 {
2130 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
2131 break;
2132 }
2133
2134 objOrg = (HGDIOBJ)dc->w.hBrush;
2135 dc->w.hBrush = hGDIObj;
2136 if (dc->XlateBrush != NULL)
2137 EngDeleteXlate(dc->XlateBrush);
2138 dc->XlateBrush = XlateObj;
2139 break;
2140
2141 case GDI_OBJECT_TYPE_FONT:
2142 if(NT_SUCCESS(TextIntRealizeFont((HFONT)hGDIObj)))
2143 {
2144 objOrg = (HGDIOBJ)dc->w.hFont;
2145 dc->w.hFont = (HFONT) hGDIObj;
2146 }
2147 break;
2148
2149 case GDI_OBJECT_TYPE_BITMAP:
2150 // must be memory dc to select bitmap
2151 if (!(dc->w.flags & DC_MEMORY))
2152 {
2153 DC_UnlockDc(dc);
2154 return NULL;
2155 }
2156 pb = BITMAPOBJ_LockBitmap(hGDIObj);
2157 if (NULL == pb)
2158 {
2159 SetLastWin32Error(ERROR_INVALID_HANDLE);
2160 DC_UnlockDc(dc);
2161 return NULL;
2162 }
2163 objOrg = (HGDIOBJ)dc->w.hBitmap;
2164
2165 /* Release the old bitmap, lock the new one and convert it to a SURF */
2166 dc->w.hBitmap = hGDIObj;
2167
2168 // if we're working with a DIB, get the palette [fixme: only create if the selected palette is null]
2169 if(pb->dib)
2170 {
2171 dc->w.bitsPerPixel = pb->dib->dsBmih.biBitCount;
2172 dc->w.hPalette = pb->hDIBPalette;
2173 }
2174 else
2175 {
2176 dc->w.bitsPerPixel = BitsPerFormat(pb->SurfObj.iBitmapFormat);
2177 dc->w.hPalette = dc->DevInfo->hpalDefault;
2178 }
2179
2180 /* Reselect brush and pen to regenerate the XLATEOBJs. */
2181 NtGdiSelectObject ( hDC, dc->w.hBrush );
2182 NtGdiSelectObject ( hDC, dc->w.hPen );
2183
2184 DC_UnlockDc ( dc );
2185 hVisRgn = NtGdiCreateRectRgn ( 0, 0, pb->SurfObj.sizlBitmap.cx, pb->SurfObj.sizlBitmap.cy );
2186 BITMAPOBJ_UnlockBitmap( pb );
2187 NtGdiSelectVisRgn ( hDC, hVisRgn );
2188 NtGdiDeleteObject ( hVisRgn );
2189
2190 return objOrg;
2191
2192 case GDI_OBJECT_TYPE_REGION:
2193 DC_UnlockDc (dc);
2194 /*
2195 * The return value is one of the following values:
2196 * SIMPLEREGION
2197 * COMPLEXREGION
2198 * NULLREGION
2199 */
2200 return (HGDIOBJ) NtGdiSelectClipRgn(hDC, (HRGN) hGDIObj);
2201
2202 default:
2203 break;
2204 }
2205 DC_UnlockDc( dc );
2206 return objOrg;
2207 }
2208
2209 WORD STDCALL
2210 NtGdiSetHookFlags(HDC hDC, WORD Flags)
2211 {
2212 WORD wRet;
2213 DC *dc = DC_LockDc(hDC);
2214
2215 if (NULL == dc)
2216 {
2217 SetLastWin32Error(ERROR_INVALID_HANDLE);
2218 return 0;
2219 }
2220
2221 wRet = dc->w.flags & DC_DIRTY;
2222
2223 /* "Undocumented Windows" info is slightly confusing.
2224 */
2225
2226 DPRINT("DC %p, Flags %04x\n", hDC, Flags);
2227
2228 if (Flags & DCHF_INVALIDATEVISRGN)
2229 {
2230 dc->w.flags |= DC_DIRTY;
2231 }
2232 else if (Flags & DCHF_VALIDATEVISRGN || 0 == Flags)
2233 {
2234 dc->w.flags &= ~DC_DIRTY;
2235 }
2236
2237 DC_UnlockDc(dc);
2238
2239 return wRet;
2240 }
2241
2242 DC_SET_MODE( NtGdiSetBkMode, w.backgroundMode, TRANSPARENT, OPAQUE )
2243 DC_SET_MODE( NtGdiSetPolyFillMode, w.polyFillMode, ALTERNATE, WINDING )
2244 // DC_SET_MODE( NtGdiSetRelAbs, w.relAbsMode, ABSOLUTE, RELATIVE )
2245 DC_SET_MODE( NtGdiSetROP2, w.ROPmode, R2_BLACK, R2_WHITE )
2246 DC_SET_MODE( NtGdiSetStretchBltMode, w.stretchBltMode, BLACKONWHITE, HALFTONE )
2247
2248 // ---------------------------------------------------- Private Interface
2249
2250 HDC FASTCALL
2251 DC_AllocDC(PUNICODE_STRING Driver)
2252 {
2253 PDC NewDC;
2254 HDC hDC;
2255 PWSTR Buf = NULL;
2256
2257 if (Driver != NULL)
2258 {
2259 Buf = ExAllocatePoolWithTag(PagedPool, Driver->MaximumLength, TAG_DC);
2260 if(!Buf)
2261 {
2262 return NULL;
2263 }
2264 RtlCopyMemory(Buf, Driver->Buffer, Driver->MaximumLength);
2265 }
2266
2267 hDC = (HDC) GDIOBJ_AllocObj(GdiHandleTable, GDI_OBJECT_TYPE_DC);
2268 if (hDC == NULL)
2269 {
2270 if(Buf)
2271 {
2272 ExFreePool(Buf);
2273 }
2274 return NULL;
2275 }
2276
2277 NewDC = DC_LockDc(hDC);
2278 /* FIXME - Handle NewDC == NULL! */
2279
2280 if (Driver != NULL)
2281 {
2282 RtlCopyMemory(&NewDC->DriverName, Driver, sizeof(UNICODE_STRING));
2283 NewDC->DriverName.Buffer = Buf;
2284 }
2285
2286 NewDC->w.xformWorld2Wnd.eM11 = 1.0f;
2287 NewDC->w.xformWorld2Wnd.eM12 = 0.0f;
2288 NewDC->w.xformWorld2Wnd.eM21 = 0.0f;
2289 NewDC->w.xformWorld2Wnd.eM22 = 1.0f;
2290 NewDC->w.xformWorld2Wnd.eDx = 0.0f;
2291 NewDC->w.xformWorld2Wnd.eDy = 0.0f;
2292 NewDC->w.xformWorld2Vport = NewDC->w.xformWorld2Wnd;
2293 NewDC->w.xformVport2World = NewDC->w.xformWorld2Wnd;
2294 NewDC->w.vport2WorldValid = TRUE;
2295 NewDC->w.MapMode = MM_TEXT;
2296 NewDC->wndExtX = 1.0f;
2297 NewDC->wndExtY = 1.0f;
2298 NewDC->vportExtX = 1.0f;
2299 NewDC->vportExtY = 1.0f;
2300 NewDC->w.textColor = 0;
2301 NewDC->w.backgroundColor = 0xffffff;
2302
2303 NewDC->w.hFont = NtGdiGetStockObject(SYSTEM_FONT);
2304 TextIntRealizeFont(NewDC->w.hFont);
2305
2306 NewDC->w.hPalette = NtGdiGetStockObject(DEFAULT_PALETTE);
2307
2308 DC_UnlockDc(NewDC);
2309
2310 return hDC;
2311 }
2312
2313 HDC FASTCALL
2314 DC_FindOpenDC(PUNICODE_STRING Driver)
2315 {
2316 return NULL;
2317 }
2318
2319 /*!
2320 * Initialize some common fields in the Device Context structure.
2321 */
2322 VOID FASTCALL
2323 DC_InitDC(HDC DCHandle)
2324 {
2325 // NtGdiRealizeDefaultPalette(DCHandle);
2326
2327 NtGdiSelectObject(DCHandle, NtGdiGetStockObject( WHITE_BRUSH ));
2328 NtGdiSelectObject(DCHandle, NtGdiGetStockObject( BLACK_PEN ));
2329 //NtGdiSelectObject(DCHandle, hFont);
2330
2331 /*
2332 {
2333 int res;
2334 res = CLIPPING_UpdateGCRegion(DCToInit);
2335 ASSERT ( res != ERROR );
2336 }
2337 */
2338 }
2339
2340 VOID FASTCALL
2341 DC_FreeDC(HDC DCToFree)
2342 {
2343 if (!GDIOBJ_FreeObj(GdiHandleTable, DCToFree, GDI_OBJECT_TYPE_DC))
2344 {
2345 DPRINT("DC_FreeDC failed\n");
2346 }
2347 }
2348
2349 BOOL INTERNAL_CALL
2350 DC_Cleanup(PVOID ObjectBody)
2351 {
2352 PDC pDC = (PDC)ObjectBody;
2353 RtlFreeUnicodeString(&pDC->DriverName);
2354 return TRUE;
2355 }
2356
2357 HDC FASTCALL
2358 DC_GetNextDC (PDC pDC)
2359 {
2360 return pDC->hNext;
2361 }
2362
2363 VOID FASTCALL
2364 DC_SetNextDC (PDC pDC, HDC hNextDC)
2365 {
2366 pDC->hNext = hNextDC;
2367 }
2368
2369 VOID FASTCALL
2370 DC_UpdateXforms(PDC dc)
2371 {
2372 XFORM xformWnd2Vport;
2373 FLOAT scaleX, scaleY;
2374
2375 /* Construct a transformation to do the window-to-viewport conversion */
2376 scaleX = (dc->wndExtX ? (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX : 0.0f);
2377 scaleY = (dc->wndExtY ? (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY : 0.0f);
2378 xformWnd2Vport.eM11 = scaleX;
2379 xformWnd2Vport.eM12 = 0.0;
2380 xformWnd2Vport.eM21 = 0.0;
2381 xformWnd2Vport.eM22 = scaleY;
2382 xformWnd2Vport.eDx = (FLOAT)dc->vportOrgX - scaleX * (FLOAT)dc->wndOrgX;
2383 xformWnd2Vport.eDy = (FLOAT)dc->vportOrgY - scaleY * (FLOAT)dc->wndOrgY;
2384
2385 /* Combine with the world transformation */
2386 IntGdiCombineTransform(&dc->w.xformWorld2Vport, &dc->w.xformWorld2Wnd, &xformWnd2Vport);
2387
2388 /* Create inverse of world-to-viewport transformation */
2389 dc->w.vport2WorldValid = DC_InvertXform(&dc->w.xformWorld2Vport, &dc->w.xformVport2World);
2390 }
2391
2392 BOOL FASTCALL
2393 DC_InvertXform(const XFORM *xformSrc,
2394 XFORM *xformDest)
2395 {
2396 FLOAT determinant;
2397
2398 determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
2399 if (determinant > -1e-12 && determinant < 1e-12)
2400 {
2401 return FALSE;
2402 }
2403
2404 xformDest->eM11 = xformSrc->eM22 / determinant;
2405 xformDest->eM12 = -xformSrc->eM12 / determinant;
2406 xformDest->eM21 = -xformSrc->eM21 / determinant;
2407 xformDest->eM22 = xformSrc->eM11 / determinant;
2408 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
2409 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
2410
2411 return TRUE;
2412 }
2413
2414 VOID FASTCALL
2415 DC_SetOwnership(HDC hDC, PEPROCESS Owner)
2416 {
2417 PDC DC;
2418
2419 GDIOBJ_SetOwnership(GdiHandleTable, hDC, Owner);
2420 DC = DC_LockDc(hDC);
2421 if (NULL != DC)
2422 {
2423 if (NULL != DC->w.hClipRgn)
2424 {
2425 GDIOBJ_CopyOwnership(GdiHandleTable, hDC, DC->w.hClipRgn);
2426 }
2427 if (NULL != DC->w.hVisRgn)
2428 {
2429 GDIOBJ_CopyOwnership(GdiHandleTable, hDC, DC->w.hVisRgn);
2430 }
2431 if (NULL != DC->w.hGCClipRgn)
2432 {
2433 GDIOBJ_CopyOwnership(GdiHandleTable, hDC, DC->w.hGCClipRgn);
2434 }
2435 DC_UnlockDc(DC);
2436 }
2437 }
2438
2439 BOOL FASTCALL
2440 IntIsPrimarySurface(SURFOBJ *SurfObj)
2441 {
2442 if (PrimarySurface.Handle == NULL)
2443 {
2444 return FALSE;
2445 }
2446 return SurfObj->hsurf == PrimarySurface.Handle;
2447 }
2448
2449 /*
2450 * Returns the color of the brush or pen that is currently selected into the DC.
2451 * This function is called from GetDCBrushColor() and GetDCPenColor()
2452 */
2453 COLORREF FASTCALL
2454 IntGetDCColor(HDC hDC, ULONG Object)
2455 {
2456 /*
2457 * The previous implementation was completly incorrect. It modified the
2458 * brush that was currently selected into the device context, but in fact
2459 * the DC pen/brush color should be stored directly in the device context
2460 * (at address 0x2C of the user mode DC object memory on Windows 2K/XP).
2461 * The actual color is then used when DC_BRUSH/DC_PEN object is selected
2462 * into the device context and BRUSHOBJ for drawing is composed (belongs
2463 * to IntGdiInitBrushInstance in the current ReactOS implementation). Also
2464 * the implementation should be moved to user mode GDI32.dll when UM
2465 * mapped GDI objects will be implemented.
2466 */
2467
2468 DPRINT("WIN32K:IntGetDCColor is unimplemented\n");
2469 return 0xFFFFFF; /* The default DC color. */
2470 }
2471
2472 /*
2473 * Changes the color of the brush or pen that is currently selected into the DC.
2474 * This function is called from SetDCBrushColor() and SetDCPenColor()
2475 */
2476 COLORREF FASTCALL
2477 IntSetDCColor(HDC hDC, ULONG Object, COLORREF Color)
2478 {
2479 /* See the comment in IntGetDCColor. */
2480
2481 DPRINT("WIN32K:IntSetDCColor is unimplemented\n");
2482 return CLR_INVALID;
2483 }
2484
2485 #define SIZEOF_DEVMODEW_300 188
2486 #define SIZEOF_DEVMODEW_400 212
2487 #define SIZEOF_DEVMODEW_500 220
2488
2489 /*! \brief Enumerate possible display settings for the given display...
2490 *
2491 * \todo Make thread safe!?
2492 * \todo Don't ignore pDeviceName
2493 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
2494 */
2495 BOOL FASTCALL
2496 IntEnumDisplaySettings(
2497 IN PUNICODE_STRING pDeviceName OPTIONAL,
2498 IN DWORD iModeNum,
2499 IN OUT LPDEVMODEW pDevMode,
2500 IN DWORD dwFlags)
2501 {
2502 static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
2503 static DWORD SizeOfCachedDevModes = 0;
2504 PDEVMODEW CachedMode = NULL;
2505 DEVMODEW DevMode;
2506 INT Size, OldSize;
2507 ULONG DisplayNumber = 0; /* only default display supported */
2508
2509 DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
2510 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
2511 if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
2512 pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
2513 pDevMode->dmSize != SIZEOF_DEVMODEW_500)
2514 {
2515 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2516 return FALSE;
2517 }
2518
2519 if (iModeNum == ENUM_CURRENT_SETTINGS)
2520 {
2521 CachedMode = &PrimarySurface.DMW;
2522 ASSERT(CachedMode->dmSize > 0);
2523 }
2524 else if (iModeNum == ENUM_REGISTRY_SETTINGS)
2525 {
2526 RtlZeroMemory(&DevMode, sizeof (DevMode));
2527 DevMode.dmSize = sizeof (DevMode);
2528 DevMode.dmDriverExtra = 0;
2529 if (SetupDevMode(&DevMode, DisplayNumber))
2530 CachedMode = &DevMode;
2531 else
2532 {
2533 SetLastWin32Error(0); /* FIXME: use error code */
2534 return FALSE;
2535 }
2536 /* FIXME: Maybe look for the matching devmode supplied by the
2537 * driver so we can provide driver private/extra data?
2538 */
2539 }
2540 else
2541 {
2542 if (iModeNum == 0 || CachedDevModes == NULL) /* query modes from drivers */
2543 {
2544 UNICODE_STRING DriverFileNames;
2545 LPWSTR CurrentName;
2546 DRVENABLEDATA DrvEnableData;
2547
2548 /* Retrieve DDI driver names from registry */
2549 RtlInitUnicodeString(&DriverFileNames, NULL);
2550 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
2551 {
2552 DPRINT1("FindDriverFileNames failed\n");
2553 return FALSE;
2554 }
2555
2556 IntPrepareDriverIfNeeded();
2557
2558 /*
2559 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
2560 * scan all of them until a good one found.
2561 */
2562 CurrentName = DriverFileNames.Buffer;
2563 for (;CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR));
2564 CurrentName += wcslen(CurrentName) + 1)
2565 {
2566 INT i;
2567 PGD_ENABLEDRIVER GDEnableDriver;
2568
2569 /* Get the DDI driver's entry point */
2570 GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
2571 if (NULL == GDEnableDriver)
2572 {
2573 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
2574 continue;
2575 }
2576
2577 /* Call DDI driver's EnableDriver function */
2578 RtlZeroMemory(&DrvEnableData, sizeof (DrvEnableData));
2579
2580 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData))
2581 {
2582 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
2583 continue;
2584 }
2585
2586 CachedDevModesEnd = CachedDevModes;
2587
2588 /* find DrvGetModes function */
2589 for (i = 0; i < DrvEnableData.c; i++)
2590 {
2591 PDRVFN DrvFn = DrvEnableData.pdrvfn + i;
2592 PGD_GETMODES GetModes;
2593 INT SizeNeeded, SizeUsed;
2594
2595 if (DrvFn->iFunc != INDEX_DrvGetModes)
2596 continue;
2597
2598 GetModes = (PGD_GETMODES)DrvFn->pfn;
2599
2600 /* make sure we have enough memory to hold the modes */
2601 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL);
2602 if (SizeNeeded <= 0)
2603 {
2604 DPRINT("DrvGetModes failed for %S\n", CurrentName);
2605 break;
2606 }
2607
2608 SizeUsed = CachedDevModesEnd - CachedDevModes;
2609 if (SizeOfCachedDevModes - SizeUsed < SizeNeeded)
2610 {
2611 PVOID NewBuffer;
2612
2613 SizeOfCachedDevModes += SizeNeeded;
2614 NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes);
2615 if (NewBuffer == NULL)
2616 {
2617 /* clean up */
2618 ExFreePool(CachedDevModes);
2619 SizeOfCachedDevModes = 0;
2620 CachedDevModes = NULL;
2621 CachedDevModesEnd = NULL;
2622 SetLastWin32Error(STATUS_NO_MEMORY);
2623 return FALSE;
2624 }
2625 if (CachedDevModes != NULL)
2626 {
2627 RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed);
2628 ExFreePool(CachedDevModes);
2629 }
2630 CachedDevModes = NewBuffer;
2631 CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
2632 }
2633
2634 /* query modes */
2635 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
2636 SizeOfCachedDevModes - SizeUsed,
2637 CachedDevModesEnd);
2638 if (SizeNeeded <= 0)
2639 {
2640 DPRINT("DrvGetModes failed for %S\n", CurrentName);
2641 }
2642 else
2643 {
2644 CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded);
2645 }
2646 break;
2647 }
2648 }
2649
2650 RtlFreeUnicodeString(&DriverFileNames);
2651 }
2652
2653 /* return cached info */
2654 CachedMode = CachedDevModes;
2655 if (CachedMode >= CachedDevModesEnd)
2656 {
2657 SetLastWin32Error(STATUS_NO_MORE_ENTRIES);
2658 return FALSE;
2659 }
2660 while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd)
2661 {
2662 assert(CachedMode->dmSize > 0);
2663 CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra);
2664 }
2665 if (CachedMode >= CachedDevModesEnd)
2666 {
2667 SetLastWin32Error(STATUS_NO_MORE_ENTRIES);
2668 return FALSE;
2669 }
2670 }
2671
2672 ASSERT(CachedMode != NULL);
2673
2674 Size = OldSize = pDevMode->dmSize;
2675 if (Size > CachedMode->dmSize)
2676 Size = CachedMode->dmSize;
2677 RtlCopyMemory(pDevMode, CachedMode, Size);
2678 RtlZeroMemory((PCHAR)pDevMode + Size, OldSize - Size);
2679 pDevMode->dmSize = OldSize;
2680
2681 Size = OldSize = pDevMode->dmDriverExtra;
2682 if (Size > CachedMode->dmDriverExtra)
2683 Size = CachedMode->dmDriverExtra;
2684 RtlCopyMemory((PCHAR)pDevMode + pDevMode->dmSize,
2685 (PCHAR)CachedMode + CachedMode->dmSize, Size);
2686 RtlZeroMemory((PCHAR)pDevMode + pDevMode->dmSize + Size, OldSize - Size);
2687 pDevMode->dmDriverExtra = OldSize;
2688
2689 return TRUE;
2690 }
2691
2692 static NTSTATUS FASTCALL
2693 GetVideoDeviceName(
2694 OUT PUNICODE_STRING VideoDeviceName,
2695 IN PCUNICODE_STRING DisplayDevice) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
2696 {
2697 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\??\\");
2698 UNICODE_STRING ObjectName;
2699 UNICODE_STRING KernelModeName = { 0, };
2700 OBJECT_ATTRIBUTES ObjectAttributes;
2701 USHORT LastSlash;
2702 ULONG Length;
2703 HANDLE LinkHandle = NULL;
2704 NTSTATUS Status;
2705
2706 RtlInitUnicodeString(VideoDeviceName, NULL);
2707
2708 /* Get device name (DisplayDevice is "\.\xxx") */
2709 for (LastSlash = DisplayDevice->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
2710 {
2711 if (DisplayDevice->Buffer[LastSlash - 1] == L'\\')
2712 break;
2713 }
2714
2715 if (LastSlash == 0)
2716 {
2717 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice);
2718 Status = STATUS_OBJECT_NAME_INVALID;
2719 goto cleanup;
2720 }
2721 ObjectName = *DisplayDevice;
2722 ObjectName.Length -= LastSlash * sizeof(WCHAR);
2723 ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
2724 ObjectName.Buffer += LastSlash;
2725
2726 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
2727 KernelModeName.MaximumLength = Prefix.Length + ObjectName.Length + sizeof(UNICODE_NULL);
2728 KernelModeName.Buffer = ExAllocatePoolWithTag(PagedPool,
2729 KernelModeName.MaximumLength,
2730 TAG_DC);
2731 if (!KernelModeName.Buffer)
2732 {
2733 Status = STATUS_NO_MEMORY;
2734 goto cleanup;
2735 }
2736 RtlCopyUnicodeString(&KernelModeName, &Prefix);
2737 Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
2738 if (!NT_SUCCESS(Status))
2739 goto cleanup;
2740
2741 /* Open \??\xxx (ex: "\??\DISPLAY1") */
2742 InitializeObjectAttributes(&ObjectAttributes,
2743 &KernelModeName,
2744 OBJ_KERNEL_HANDLE,
2745 NULL,
2746 NULL);
2747 Status = ZwOpenSymbolicLinkObject(&LinkHandle,
2748 GENERIC_READ,
2749 &ObjectAttributes);
2750 if (!NT_SUCCESS(Status))
2751 {
2752 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
2753 Status = STATUS_NO_SUCH_DEVICE;
2754 goto cleanup;
2755 }
2756
2757 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, &Length);
2758 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
2759 {
2760 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
2761 Status = STATUS_NO_SUCH_DEVICE;
2762 goto cleanup;
2763 }
2764 VideoDeviceName->MaximumLength = Length;
2765 VideoDeviceName->Buffer = ExAllocatePoolWithTag(PagedPool,
2766 VideoDeviceName->MaximumLength + sizeof(UNICODE_NULL),
2767 TAG_DC);
2768 if (!VideoDeviceName->Buffer)
2769 {
2770 Status = STATUS_NO_MEMORY;
2771 goto cleanup;
2772 }
2773 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, NULL);
2774 VideoDeviceName->Buffer[VideoDeviceName->MaximumLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
2775 if (!NT_SUCCESS(Status))
2776 {
2777 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
2778 Status = STATUS_NO_SUCH_DEVICE;
2779 goto cleanup;
2780 }
2781 Status = STATUS_SUCCESS;
2782
2783 cleanup:
2784 if (!NT_SUCCESS(Status) && VideoDeviceName->Buffer)
2785 ExFreePoolWithTag(VideoDeviceName->Buffer, TAG_DC);
2786 if (KernelModeName.Buffer)
2787 ExFreePoolWithTag(KernelModeName.Buffer, TAG_DC);
2788 if (LinkHandle)
2789 ZwClose(LinkHandle);
2790 return Status;
2791 }
2792
2793 static NTSTATUS FASTCALL
2794 GetVideoRegistryKey(
2795 OUT PUNICODE_STRING RegistryPath,
2796 IN PCUNICODE_STRING DeviceName) /* ex: "\Device\Video0" */
2797 {
2798 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
2799 NTSTATUS Status;
2800
2801 RtlInitUnicodeString(RegistryPath, NULL);
2802 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2803 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
2804 QueryTable[0].Name = DeviceName->Buffer;
2805 QueryTable[0].EntryContext = RegistryPath;
2806
2807 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
2808 L"VIDEO",
2809 QueryTable,
2810 NULL,
2811 NULL);
2812 if (!NT_SUCCESS(Status))
2813 {
2814 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName, Status);
2815 return STATUS_NO_SUCH_DEVICE;
2816 }
2817
2818 DPRINT("RegistryPath %wZ\n", RegistryPath);
2819 return STATUS_SUCCESS;
2820 }
2821
2822 LONG
2823 FASTCALL
2824 IntChangeDisplaySettings(
2825 IN PUNICODE_STRING pDeviceName OPTIONAL,
2826 IN LPDEVMODEW DevMode,
2827 IN DWORD dwflags,
2828 IN PVOID lParam OPTIONAL)
2829 {
2830 BOOLEAN Global = FALSE;
2831 BOOLEAN NoReset = FALSE;
2832 BOOLEAN Reset = FALSE;
2833 BOOLEAN SetPrimary = FALSE;
2834 LONG Ret=0;
2835 NTSTATUS Status ;
2836
2837 DPRINT1("display flag : %x\n",dwflags);
2838
2839 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
2840 {
2841 /* Check global, reset and noreset flags */
2842 if ((dwflags & CDS_GLOBAL) == CDS_GLOBAL)
2843 Global = TRUE;
2844 if ((dwflags & CDS_NORESET) == CDS_NORESET)
2845 NoReset = TRUE;
2846 dwflags &= ~(CDS_GLOBAL | CDS_NORESET);
2847 }
2848 if ((dwflags & CDS_RESET) == CDS_RESET)
2849 Reset = TRUE;
2850 if ((dwflags & CDS_SET_PRIMARY) == CDS_SET_PRIMARY)
2851 SetPrimary = TRUE;
2852 dwflags &= ~(CDS_RESET | CDS_SET_PRIMARY);
2853
2854 if (Reset && NoReset)
2855 return DISP_CHANGE_BADFLAGS;
2856
2857 if (dwflags == 0)
2858 {
2859 /* Dynamically change graphics mode */
2860 DPRINT1("flag 0 UNIMPLEMENT \n");
2861 return DISP_CHANGE_FAILED;
2862 }
2863
2864 if ((dwflags & CDS_TEST) == CDS_TEST)
2865 {
2866 /* Test reslution */
2867 dwflags &= ~CDS_TEST;
2868 DPRINT1("flag CDS_TEST UNIMPLEMENT");
2869 Ret = DISP_CHANGE_FAILED;
2870 }
2871
2872 if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
2873 {
2874 DEVMODEW lpDevMode;
2875 /* Full Screen */
2876 dwflags &= ~CDS_FULLSCREEN;
2877 DPRINT1("flag CDS_FULLSCREEN partially implemented");
2878 Ret = DISP_CHANGE_FAILED;
2879
2880 lpDevMode.dmBitsPerPel =0;
2881 lpDevMode.dmPelsWidth =0;
2882 lpDevMode.dmPelsHeight =0;
2883 lpDevMode.dmDriverExtra =0;
2884
2885 lpDevMode.dmSize = sizeof(DEVMODEW);
2886 if (!IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0))
2887 return DISP_CHANGE_FAILED;
2888
2889 DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
2890 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
2891
2892
2893 if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
2894 (lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) &&
2895 (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
2896 Ret = DISP_CHANGE_SUCCESSFUL;
2897 }
2898
2899 if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
2900 {
2901 dwflags &= ~CDS_VIDEOPARAMETERS;
2902 if (lParam == NULL)
2903 Ret=DISP_CHANGE_BADPARAM;
2904 else
2905 {
2906 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENT");
2907 Ret = DISP_CHANGE_FAILED;
2908 }
2909
2910 }
2911
2912 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
2913 {
2914
2915 UNICODE_STRING DeviceName;
2916 UNICODE_STRING RegistryKey;
2917 UNICODE_STRING InDeviceName;
2918 OBJECT_ATTRIBUTES ObjectAttributes;
2919 HANDLE DevInstRegKey;
2920 ULONG NewValue;
2921
2922 DPRINT1("set CDS_UPDATEREGISTRY \n");
2923
2924 dwflags &= ~CDS_UPDATEREGISTRY;
2925
2926 /* Check if pDeviceName is NULL, we need to retrieve it */
2927 if (pDeviceName == NULL)
2928 {
2929 WCHAR szBuffer[MAX_DRIVER_NAME];
2930 PDC DC;
2931 PWINDOW_OBJECT Wnd=NULL;
2932 HWND hWnd;
2933 HDC hDC;
2934
2935 hWnd = IntGetDesktopWindow();
2936 if (!(Wnd = UserGetWindowObject(hWnd)))
2937 {
2938 return FALSE;
2939 }
2940
2941 hDC = (HDC)UserGetWindowDC(Wnd);
2942
2943 DC = DC_LockDc(hDC);
2944 if (NULL == DC)
2945 {
2946 return FALSE;
2947 }
2948 swprintf (szBuffer, L"\\\\.\\DISPLAY%lu", ((GDIDEVICE *)DC->GDIDevice)->DisplayNumber);
2949 DC_UnlockDc(DC);
2950
2951 RtlInitUnicodeString(&InDeviceName, szBuffer);
2952 pDeviceName = &InDeviceName;
2953 }
2954
2955 Status = GetVideoDeviceName(&DeviceName, pDeviceName);
2956 if (!NT_SUCCESS(Status))
2957 {
2958 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName, Status);
2959 return DISP_CHANGE_FAILED;
2960 }
2961 Status = GetVideoRegistryKey(&RegistryKey, &DeviceName);
2962 if (!NT_SUCCESS(Status))
2963 {
2964 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName, Status);
2965 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
2966 return DISP_CHANGE_FAILED;
2967 }
2968 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
2969
2970 InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
2971 OBJ_CASE_INSENSITIVE, NULL, NULL);
2972 Status = ZwOpenKey(&DevInstRegKey, GENERIC_READ | GENERIC_WRITE, &ObjectAttributes);
2973 if (!NT_SUCCESS(Status))
2974 {
2975 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey, Status);
2976 ExFreePoolWithTag(RegistryKey.Buffer, TAG_DC);
2977 return DISP_CHANGE_FAILED;
2978 }
2979 ExFreePoolWithTag(RegistryKey.Buffer, TAG_DC);
2980
2981 /* Update needed fields */
2982 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
2983 {
2984 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
2985 NewValue = DevMode->dmBitsPerPel;
2986 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
2987 }
2988
2989 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
2990 {
2991 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
2992 NewValue = DevMode->dmPelsWidth;
2993 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
2994 }
2995
2996 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
2997 {
2998 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
2999 NewValue = DevMode->dmPelsHeight;
3000 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3001 }
3002
3003 ZwClose(DevInstRegKey);
3004 if (NT_SUCCESS(Status))
3005 Ret = DISP_CHANGE_RESTART;
3006 else
3007 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
3008 Ret = DISP_CHANGE_NOTUPDATED;
3009 }
3010
3011 if (dwflags != 0)
3012 Ret = DISP_CHANGE_BADFLAGS;
3013
3014 return Ret;
3015 }
3016
3017 /* EOF */