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