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