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