xref: /reactos/win32ss/gdi/gdi32/objects/dc.c (revision 682f85ad)
1 #include <precomp.h>
2 
3 #define NDEBUG
4 #include <debug.h>
5 
6 HDC
7 FASTCALL
8 IntCreateDICW(
9     LPCWSTR lpwszDriver,
10     LPCWSTR lpwszDevice,
11     LPCWSTR lpwszOutput,
12     PDEVMODEW lpInitData,
13     ULONG iType)
14 {
15     UNICODE_STRING Device, Output;
16     HDC hdc = NULL;
17     BOOL Display = FALSE, Default = FALSE;
18     HANDLE UMdhpdev = 0;
19 
20     HANDLE hspool = NULL;
21 
22     if ( !ghSpooler && !LoadTheSpoolerDrv())
23     {
24         DPRINT1("WinSpooler.Drv Did not load!\n");
25     }
26     else
27     {
28         DPRINT("WinSpooler.Drv Loaded! hMod -> 0x%p\n", ghSpooler);
29     }
30 
31     if ((!lpwszDevice) && (!lpwszDriver))
32     {
33         Default = TRUE;  // Ask Win32k to set Default device.
34         Display = TRUE;   // Most likely to be DISPLAY.
35     }
36     else
37     {
38         if ((lpwszDevice) && (wcslen(lpwszDevice) != 0))  // First
39         {
40             if (!_wcsnicmp(lpwszDevice, L"\\\\.\\DISPLAY",11)) Display = TRUE;
41             RtlInitUnicodeString(&Device, lpwszDevice);
42         }
43         else
44         {
45             if (lpwszDriver) // Second
46             {
47                 if ((!_wcsnicmp(lpwszDriver, L"DISPLAY",7)) ||
48                         (!_wcsnicmp(lpwszDriver, L"\\\\.\\DISPLAY",11))) Display = TRUE;
49                 RtlInitUnicodeString(&Device, lpwszDriver);
50             }
51         }
52     }
53 
54     if (lpwszOutput) RtlInitUnicodeString(&Output, lpwszOutput);
55 
56     // Handle Print device or something else.
57     if (!Display)
58     {
59         // WIP - GDI Print Commit coming in soon.
60         DPRINT1("Not a DISPLAY device! %wZ\n", &Device);
61         return NULL; // Return NULL until then.....
62     }
63 
64     hdc = NtGdiOpenDCW((Default ? NULL : &Device),
65                        (PDEVMODEW) lpInitData,
66                        (lpwszOutput ? &Output : NULL),
67                        iType,             // DCW 0 and ICW 1.
68                        Display,
69                        hspool,
70                        &UMdhpdev );
71 #if 0
72 // Handle something other than a normal dc object.
73     if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
74     {
75         PDC_ATTR Dc_Attr;
76         PLDC pLDC;
77 
78         GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID*)&Dc_Attr);
79 
80         pLDC = LocalAlloc(LMEM_ZEROINIT, sizeof(LDC));
81 
82         Dc_Attr->pvLDC = pLDC;
83         pLDC->hDC = hdc;
84         pLDC->iType = LDC_LDC; // 1 (init) local DC, 2 EMF LDC
85         DbgPrint("DC_ATTR Allocated -> 0x%x\n",Dc_Attr);
86     }
87 #endif
88     return hdc;
89 }
90 
91 
92 /*
93  * @implemented
94  */
95 HDC
96 WINAPI
97 CreateCompatibleDC(
98     _In_ HDC hdc)
99 {
100     HDC hdcNew;
101 // PDC_ATTR pdcattr;
102 
103     hdcNew = NtGdiCreateCompatibleDC(hdc);
104 #if 0
105     if ( hdc && hdcNew)
106     {
107         if (GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID*)&pdcattr))
108         {
109             if (pdcattr->pvLIcm) IcmCompatibleDC(hdcNew, hdc, pdcattr);
110         }
111     }
112 #endif
113 
114     return hdcNew;
115 }
116 
117 /*
118  * @implemented
119  */
120 HDC
121 WINAPI
122 CreateDCA (
123     LPCSTR lpszDriver,
124     LPCSTR lpszDevice,
125     LPCSTR lpszOutput,
126     CONST DEVMODEA * lpdvmInit)
127 {
128     ANSI_STRING DriverA, DeviceA, OutputA;
129     UNICODE_STRING DriverU, DeviceU, OutputU;
130     LPDEVMODEW dvmInitW = NULL;
131     HDC hdc;
132 
133     /*
134      * If needed, convert to Unicode
135      * any string parameter.
136      */
137 
138     if (lpszDriver != NULL)
139     {
140         RtlInitAnsiString(&DriverA, (LPSTR)lpszDriver);
141         RtlAnsiStringToUnicodeString(&DriverU, &DriverA, TRUE);
142     }
143     else
144     {
145         DriverU.Buffer = NULL;
146     }
147 
148     if (lpszDevice != NULL)
149     {
150         RtlInitAnsiString(&DeviceA, (LPSTR)lpszDevice);
151         RtlAnsiStringToUnicodeString(&DeviceU, &DeviceA, TRUE);
152     }
153     else
154     {
155         DeviceU.Buffer = NULL;
156     }
157 
158     if (lpszOutput != NULL)
159     {
160         RtlInitAnsiString(&OutputA, (LPSTR)lpszOutput);
161         RtlAnsiStringToUnicodeString(&OutputU, &OutputA, TRUE);
162     }
163     else
164     {
165         OutputU.Buffer = NULL;
166     }
167 
168     if (lpdvmInit != NULL)
169         dvmInitW = GdiConvertToDevmodeW((LPDEVMODEA)lpdvmInit);
170 
171     hdc = IntCreateDICW(DriverU.Buffer,
172                         DeviceU.Buffer,
173                         OutputU.Buffer,
174                         lpdvmInit ? dvmInitW : NULL,
175                         0);
176     HEAP_free(dvmInitW);
177 
178     /* Free Unicode parameters. */
179     RtlFreeUnicodeString(&DriverU);
180     RtlFreeUnicodeString(&DeviceU);
181     RtlFreeUnicodeString(&OutputU);
182 
183     /* Return the DC handle. */
184     return hdc;
185 }
186 
187 
188 /*
189  * @implemented
190  */
191 HDC
192 WINAPI
193 CreateDCW (
194     LPCWSTR lpwszDriver,
195     LPCWSTR lpwszDevice,
196     LPCWSTR lpwszOutput,
197     CONST DEVMODEW *lpInitData)
198 {
199     return IntCreateDICW(lpwszDriver,
200                          lpwszDevice,
201                          lpwszOutput,
202                          (PDEVMODEW)lpInitData,
203                          0);
204 }
205 
206 
207 /*
208  * @implemented
209  */
210 HDC
211 WINAPI
212 CreateICW(
213     LPCWSTR lpszDriver,
214     LPCWSTR lpszDevice,
215     LPCWSTR lpszOutput,
216     CONST DEVMODEW *lpdvmInit)
217 {
218     return IntCreateDICW(lpszDriver,
219                          lpszDevice,
220                          lpszOutput,
221                          (PDEVMODEW)lpdvmInit,
222                          1);
223 }
224 
225 
226 /*
227  * @implemented
228  */
229 HDC
230 WINAPI
231 CreateICA(
232     LPCSTR lpszDriver,
233     LPCSTR lpszDevice,
234     LPCSTR lpszOutput,
235     CONST DEVMODEA *lpdvmInit)
236 {
237     NTSTATUS Status;
238     LPWSTR lpszDriverW, lpszDeviceW, lpszOutputW;
239     LPDEVMODEW dvmInitW = NULL;
240     HDC hdc = 0;
241 
242     Status = HEAP_strdupA2W(&lpszDriverW, lpszDriver);
243     if (!NT_SUCCESS(Status))
244         SetLastError(RtlNtStatusToDosError(Status));
245     else
246     {
247         Status = HEAP_strdupA2W(&lpszDeviceW, lpszDevice);
248         if (!NT_SUCCESS(Status))
249             SetLastError(RtlNtStatusToDosError(Status));
250         else
251         {
252             Status = HEAP_strdupA2W(&lpszOutputW, lpszOutput);
253             if (!NT_SUCCESS(Status))
254                 SetLastError(RtlNtStatusToDosError(Status));
255             else
256             {
257                 if (lpdvmInit)
258                     dvmInitW = GdiConvertToDevmodeW((LPDEVMODEA)lpdvmInit);
259 
260                 hdc = IntCreateDICW(lpszDriverW,
261                                     lpszDeviceW,
262                                     lpszOutputW,
263                                     lpdvmInit ? dvmInitW : NULL,
264                                     1 );
265                 HEAP_free(dvmInitW);
266                 HEAP_free(lpszOutputW);
267             }
268             HEAP_free(lpszDeviceW);
269         }
270         HEAP_free(lpszDriverW);
271     }
272 
273     return hdc;
274 }
275 
276 
277 /*
278  * @implemented
279  */
280 BOOL
281 WINAPI
282 DeleteDC(HDC hdc)
283 {
284     BOOL bResult = TRUE;
285     PLDC pLDC = NULL;
286     HANDLE hPrinter = NULL;
287     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
288 
289     pLDC = GdiGetLDC(hdc);
290 
291     if (hType != GDILoObjType_LO_DC_TYPE)
292     {
293         return METADC_DeleteDC(hdc);
294     }
295 
296     bResult = NtGdiDeleteObjectApp(hdc);
297 
298     if (bResult && pLDC)
299     {
300         DPRINT1("Delete the Local DC structure\n");
301         LocalFree( pLDC );
302     }
303 
304     if (hPrinter)
305         fpClosePrinter(hPrinter);
306 
307     return bResult;
308 }
309 
310 
311 /*
312  * @unimplemented
313  */
314 INT
315 WINAPI
316 SaveDC(IN HDC hdc)
317 {
318     HANDLE_METADC0P(INT, SaveDC, 0, hdc);
319     return NtGdiSaveDC(hdc);
320 }
321 
322 
323 /*
324  * @unimplemented
325  */
326 BOOL
327 WINAPI
328 RestoreDC(IN HDC hdc,
329           IN INT iLevel)
330 {
331     HANDLE_METADC(BOOL, RestoreDC, FALSE, hdc, iLevel);
332     return NtGdiRestoreDC(hdc, iLevel);
333 }
334 
335 
336 /*
337  * @implemented
338  */
339 BOOL
340 WINAPI
341 CancelDC(HDC hDC)
342 {
343     PDC_ATTR pDc_Attr;
344 
345     if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC &&
346             GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
347     {
348         PLDC pLDC = GdiGetLDC(hDC);
349         if ( !pLDC )
350         {
351             SetLastError(ERROR_INVALID_HANDLE);
352             return FALSE;
353         }
354         /* If a document has started set it to die. */
355         if (pLDC->Flags & LDC_INIT_DOCUMENT) pLDC->Flags |= LDC_KILL_DOCUMENT;
356 
357         return NtGdiCancelDC(hDC);
358     }
359 
360     if (GdiGetHandleUserData((HGDIOBJ) hDC, GDI_OBJECT_TYPE_DC, (PVOID) &pDc_Attr))
361     {
362         pDc_Attr->ulDirty_ &= ~DC_PLAYMETAFILE;
363         return TRUE;
364     }
365 
366     return FALSE;
367 }
368 
369 INT
370 WINAPI
371 GetArcDirection(
372     _In_ HDC hdc)
373 {
374     return GetDCDWord( hdc, GdiGetArcDirection, 0);
375 }
376 
377 
378 INT
379 WINAPI
380 SetArcDirection(
381     _In_ HDC hdc,
382     _In_ INT nDirection)
383 {
384     return GetAndSetDCDWord(hdc, GdiGetSetArcDirection, nDirection, 0, 0, 0);
385 }
386 
387 /*
388  * @unimplemented
389  */
390 BOOL
391 WINAPI
392 GdiReleaseDC(HDC hdc)
393 {
394     return 0;
395 }
396 
397 
398 /*
399  * @implemented
400  */
401 BOOL
402 WINAPI
403 GdiCleanCacheDC(HDC hdc)
404 {
405     if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_DC_TYPE)
406         return TRUE;
407     SetLastError(ERROR_INVALID_HANDLE);
408     return FALSE;
409 }
410 
411 /*
412  * @implemented
413  */
414 HDC
415 WINAPI
416 GdiConvertAndCheckDC(HDC hdc)
417 {
418     PLDC pldc;
419     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
420     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
421         return hdc;
422     pldc = GdiGetLDC(hdc);
423     if (pldc)
424     {
425         if (pldc->Flags & LDC_SAPCALLBACK) GdiSAPCallback(pldc);
426         if (pldc->Flags & LDC_KILL_DOCUMENT) return NULL;
427         if (pldc->Flags & LDC_STARTPAGE) StartPage(hdc);
428         return hdc;
429     }
430     SetLastError(ERROR_INVALID_HANDLE);
431     return NULL;
432 }
433 
434 
435 /*
436  * @implemented
437  *
438  */
439 HGDIOBJ
440 WINAPI
441 GetCurrentObject(
442     _In_ HDC hdc,
443     _In_ UINT uObjectType)
444 {
445     PDC_ATTR pdcattr = NULL;
446 
447     /* Check if this is a user mode object */
448     if ((uObjectType == OBJ_PEN) ||
449         (uObjectType == OBJ_EXTPEN) ||
450         (uObjectType == OBJ_BRUSH) ||
451         (uObjectType == OBJ_COLORSPACE))
452     {
453         /* Get the DC attribute */
454         pdcattr = GdiGetDcAttr(hdc);
455         if (pdcattr == NULL)
456         {
457             return NULL;
458         }
459     }
460 
461     /* Check what object was requested */
462     switch (uObjectType)
463     {
464         case OBJ_EXTPEN:
465         case OBJ_PEN:
466             return pdcattr->hpen;
467 
468         case OBJ_BRUSH:
469             return pdcattr->hbrush;
470 
471         case OBJ_COLORSPACE:
472             return pdcattr->hColorSpace;
473 
474         case OBJ_PAL:
475             uObjectType = GDI_OBJECT_TYPE_PALETTE;
476             break;
477 
478         case OBJ_FONT:
479             uObjectType = GDI_OBJECT_TYPE_FONT;
480             break;
481 
482         case OBJ_BITMAP:
483             uObjectType = GDI_OBJECT_TYPE_BITMAP;
484             break;
485 
486         /* All others are invalid */
487         default:
488             SetLastError(ERROR_INVALID_PARAMETER);
489             return NULL;
490     }
491 
492     /* Pass the request to win32k */
493     return NtGdiGetDCObject(hdc, uObjectType);
494 }
495 
496 
497 /*
498  * @implemented
499  */
500 int
501 WINAPI
502 EnumObjects(HDC hdc,
503             int nObjectType,
504             GOBJENUMPROC lpObjectFunc,
505             LPARAM lParam)
506 {
507     ULONG ObjectsCount;
508     ULONG Size;
509     PVOID Buffer = NULL;
510     DWORD_PTR EndOfBuffer;
511     int Result = 0;
512 
513     switch (nObjectType)
514     {
515     case OBJ_BRUSH:
516         Size = sizeof(LOGBRUSH);
517         break;
518 
519     case OBJ_PEN:
520         Size = sizeof(LOGPEN);
521         break;
522 
523     default:
524         SetLastError(ERROR_INVALID_PARAMETER);
525         return 0;
526     }
527 
528     ObjectsCount = NtGdiEnumObjects(hdc, nObjectType, 0, NULL);
529     if (!ObjectsCount) return 0;
530 
531     Buffer = HeapAlloc(GetProcessHeap(), 0, ObjectsCount * Size);
532     if (!Buffer)
533     {
534         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
535         return 0;
536     }
537 
538     if (!NtGdiEnumObjects(hdc, nObjectType, ObjectsCount * Size, Buffer))
539     {
540         HeapFree(GetProcessHeap(), 0, Buffer);
541         return 0;
542     }
543 
544     EndOfBuffer = (DWORD_PTR)Buffer + (ObjectsCount * Size);
545     while ((DWORD_PTR)Buffer < EndOfBuffer)
546     {
547         Result = lpObjectFunc(Buffer, lParam);
548         if (!Result) break;
549         Buffer = (PVOID)((DWORD_PTR)Buffer + Size);
550     }
551 
552     HeapFree(GetProcessHeap(), 0, Buffer);
553     return Result;
554 }
555 
556 
557 /*
558  * @implemented
559  *
560  */
561 int
562 WINAPI
563 GetDeviceCaps(
564     _In_ HDC hdc,
565     _In_ int nIndex)
566 {
567     PDC_ATTR pdcattr;
568     PDEVCAPS pDevCaps = GdiDevCaps; // Primary display device capabilities.
569     DPRINT("Device CAPS1\n");
570 
571     HANDLE_METADC(INT, GetDeviceCaps, 0, hdc, nIndex);
572 
573     /* Get the DC attribute */
574     pdcattr = GdiGetDcAttr(hdc);
575     if (pdcattr == NULL)
576     {
577         SetLastError(ERROR_INVALID_PARAMETER);
578         return 0;
579     }
580 
581     if (!(pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY))
582         return NtGdiGetDeviceCaps(hdc, nIndex);
583 
584     switch (nIndex)
585     {
586     case DRIVERVERSION:
587         return pDevCaps->ulVersion;
588 
589     case TECHNOLOGY:
590         return pDevCaps->ulTechnology;
591 
592     case HORZSIZE:
593         return pDevCaps->ulHorzSize;
594 
595     case VERTSIZE:
596         return pDevCaps->ulVertSize;
597 
598     case HORZRES:
599         return pDevCaps->ulHorzRes;
600 
601     case VERTRES:
602         return pDevCaps->ulVertRes;
603 
604     case LOGPIXELSX:
605         return pDevCaps->ulLogPixelsX;
606 
607     case LOGPIXELSY:
608         return pDevCaps->ulLogPixelsY;
609 
610     case BITSPIXEL:
611         return pDevCaps->ulBitsPixel;
612 
613     case PLANES:
614         return pDevCaps->ulPlanes;
615 
616     case NUMBRUSHES:
617         return -1;
618 
619     case NUMPENS:
620         return pDevCaps->ulNumPens;
621 
622     case NUMFONTS:
623         return pDevCaps->ulNumFonts;
624 
625     case NUMCOLORS:
626         return pDevCaps->ulNumColors;
627 
628     case ASPECTX:
629         return pDevCaps->ulAspectX;
630 
631     case ASPECTY:
632         return pDevCaps->ulAspectY;
633 
634     case ASPECTXY:
635         return pDevCaps->ulAspectXY;
636 
637     case CLIPCAPS:
638         return CP_RECTANGLE;
639 
640     case SIZEPALETTE:
641         return pDevCaps->ulSizePalette;
642 
643     case NUMRESERVED:
644         return 20;
645 
646     case COLORRES:
647         return pDevCaps->ulColorRes;
648 
649     case DESKTOPVERTRES:
650         return pDevCaps->ulVertRes;
651 
652     case DESKTOPHORZRES:
653         return pDevCaps->ulHorzRes;
654 
655     case BLTALIGNMENT:
656         return pDevCaps->ulBltAlignment;
657 
658     case SHADEBLENDCAPS:
659         return pDevCaps->ulShadeBlend;
660 
661     case COLORMGMTCAPS:
662         return pDevCaps->ulColorMgmtCaps;
663 
664     case PHYSICALWIDTH:
665         return pDevCaps->ulPhysicalWidth;
666 
667     case PHYSICALHEIGHT:
668         return pDevCaps->ulPhysicalHeight;
669 
670     case PHYSICALOFFSETX:
671         return pDevCaps->ulPhysicalOffsetX;
672 
673     case PHYSICALOFFSETY:
674         return pDevCaps->ulPhysicalOffsetY;
675 
676     case VREFRESH:
677         return pDevCaps->ulVRefresh;
678 
679     case RASTERCAPS:
680         return pDevCaps->ulRasterCaps;
681 
682     case CURVECAPS:
683         return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
684                 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
685 
686     case LINECAPS:
687         return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
688                 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
689 
690     case POLYGONALCAPS:
691         return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
692                 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
693 
694     case TEXTCAPS:
695         return pDevCaps->ulTextCaps;
696 
697     case PDEVICESIZE:
698     case SCALINGFACTORX:
699     case SCALINGFACTORY:
700     default:
701         return 0;
702     }
703     return 0;
704 }
705 
706 /*
707  * @implemented
708  */
709 DWORD
710 WINAPI
711 GetRelAbs(
712     _In_ HDC hdc,
713     _In_ DWORD dwIgnore)
714 {
715     return GetDCDWord(hdc, GdiGetRelAbs, 0);
716 }
717 
718 
719 /*
720  * @implemented
721  */
722 INT
723 WINAPI
724 SetRelAbs(
725     HDC hdc,
726     INT Mode)
727 {
728     return GetAndSetDCDWord(hdc, GdiGetSetRelAbs, Mode, 0, 0, 0);
729 }
730 
731 
732 /*
733  * @implemented
734  */
735 DWORD
736 WINAPI
737 GetAndSetDCDWord(
738     _In_ HDC hdc,
739     _In_ UINT u,
740     _In_ DWORD dwIn,
741     _In_ ULONG ulMFId,
742     _In_ USHORT usMF16Id,
743     _In_ DWORD dwError)
744 {
745     DWORD dwResult;
746 
747     /* This is a special API, handle it appropriately */
748     HANDLE_METADC2(DWORD, GetAndSetDCDWord, hdc, u, dwIn, ulMFId, usMF16Id, dwError);
749 
750     /* Call win32k to do the real work */
751     if (!NtGdiGetAndSetDCDword(hdc, u, dwIn, &dwResult))
752     {
753         return dwError;
754     }
755 
756     return dwResult;
757 }
758 
759 
760 /*
761  * @implemented
762  */
763 DWORD
764 WINAPI
765 GetDCDWord(
766     _In_ HDC hdc,
767     _In_ UINT u,
768     _In_ DWORD dwError)
769 {
770     DWORD dwResult;
771 
772     if (!NtGdiGetDCDword(hdc, u, &dwResult))
773     {
774         return dwError;
775     }
776 
777     return dwResult;
778 }
779 
780 
781 /*
782  * @implemented
783  */
784 BOOL
785 WINAPI
786 GetAspectRatioFilterEx(
787     HDC hdc,
788     LPSIZE lpAspectRatio)
789 {
790     return NtGdiGetDCPoint(hdc, GdiGetAspectRatioFilter, (PPOINTL)lpAspectRatio );
791 }
792 
793 
794 /*
795  * @implemented
796  */
797 UINT
798 WINAPI
799 GetBoundsRect(
800     HDC	hdc,
801     LPRECT	lprcBounds,
802     UINT	flags
803 )
804 {
805     return NtGdiGetBoundsRect(hdc,lprcBounds,flags & ~DCB_WINDOWMGR);
806 }
807 
808 
809 /*
810  * @implemented
811  */
812 UINT
813 WINAPI
814 SetBoundsRect(HDC hdc,
815               CONST RECT *prc,
816               UINT flags)
817 {
818     /* FIXME add check for validate the flags */
819     return NtGdiSetBoundsRect(hdc, (LPRECT)prc, flags & ~DCB_WINDOWMGR);
820 }
821 
822 
823 /*
824  * @implemented
825  *
826  */
827 int
828 WINAPI
829 GetClipBox(HDC hdc,
830            LPRECT lprc)
831 {
832     return NtGdiGetAppClipBox(hdc, lprc);
833 }
834 
835 
836 /*
837  * @implemented
838  */
839 COLORREF
840 WINAPI
841 GetDCBrushColor(
842     _In_ HDC hdc)
843 {
844     PDC_ATTR pdcattr;
845 
846     /* Get the DC attribute */
847     pdcattr = GdiGetDcAttr(hdc);
848     if (pdcattr == NULL)
849     {
850         SetLastError(ERROR_INVALID_PARAMETER);
851         return CLR_INVALID;
852     }
853 
854     return pdcattr->ulBrushClr;
855 }
856 
857 /*
858  * @implemented
859  */
860 COLORREF
861 WINAPI
862 GetDCPenColor(
863     _In_ HDC hdc)
864 {
865     PDC_ATTR pdcattr;
866 
867     /* Get the DC attribute */
868     pdcattr = GdiGetDcAttr(hdc);
869     if (pdcattr == NULL)
870     {
871         SetLastError(ERROR_INVALID_PARAMETER);
872         return CLR_INVALID;
873     }
874 
875     return pdcattr->ulPenClr;
876 }
877 
878 /*
879  * @implemented
880  */
881 COLORREF
882 WINAPI
883 SetDCBrushColor(
884     _In_ HDC hdc,
885     _In_ COLORREF crColor)
886 {
887     PDC_ATTR pdcattr;
888     COLORREF crOldColor;
889 
890     /* Get the DC attribute */
891     pdcattr = GdiGetDcAttr(hdc);
892     if (pdcattr == NULL)
893     {
894         SetLastError(ERROR_INVALID_PARAMETER);
895         return CLR_INVALID;
896     }
897 
898     /* We handle only enhanced meta DCs here */
899     HANDLE_METADC(COLORREF, SetDCBrushColor, CLR_INVALID, hdc, crColor);
900 
901     /* Get old color and store the new */
902     crOldColor = pdcattr->ulBrushClr;
903     pdcattr->ulBrushClr = crColor;
904 
905     if (pdcattr->crBrushClr != crColor)
906     {
907         pdcattr->ulDirty_ |= DIRTY_FILL;
908         pdcattr->crBrushClr = crColor;
909     }
910 
911     return crOldColor;
912 }
913 
914 /*
915  * @implemented
916  */
917 COLORREF
918 WINAPI
919 SetDCPenColor(
920     _In_ HDC hdc,
921     _In_ COLORREF crColor)
922 {
923     PDC_ATTR pdcattr;
924     COLORREF crOldColor;
925 
926     /* Get the DC attribute */
927     pdcattr = GdiGetDcAttr(hdc);
928     if (pdcattr == NULL)
929     {
930         SetLastError(ERROR_INVALID_PARAMETER);
931         return CLR_INVALID;
932     }
933 
934     /* We handle only enhanced meta DCs here */
935     HANDLE_METADC(COLORREF, SetDCPenColor, CLR_INVALID, hdc, crColor);
936 
937     /* Get old color and store the new */
938     crOldColor = pdcattr->ulPenClr;
939     pdcattr->ulPenClr = (ULONG)crColor;
940 
941     if (pdcattr->crPenClr != crColor)
942     {
943         pdcattr->ulDirty_ |= DIRTY_LINE;
944         pdcattr->crPenClr = crColor;
945     }
946 
947     return crOldColor;
948 }
949 
950 /*
951  * @implemented
952  *
953  */
954 COLORREF
955 WINAPI
956 GetBkColor(
957     _In_ HDC hdc)
958 {
959     PDC_ATTR pdcattr;
960 
961     /* Get the DC attribute */
962     pdcattr = GdiGetDcAttr(hdc);
963     if (pdcattr == NULL)
964     {
965         /* Don't set LastError here! */
966         return CLR_INVALID;
967     }
968 
969     return pdcattr->ulBackgroundClr;
970 }
971 
972 /*
973  * @implemented
974  */
975 COLORREF
976 WINAPI
977 SetBkColor(
978     _In_ HDC hdc,
979     _In_ COLORREF crColor)
980 {
981     PDC_ATTR pdcattr;
982     COLORREF crOldColor;
983 
984     HANDLE_METADC(COLORREF, SetBkColor, CLR_INVALID, hdc, crColor);
985 
986     /* Get the DC attribute */
987     pdcattr = GdiGetDcAttr(hdc);
988     if (pdcattr == NULL)
989     {
990         SetLastError(ERROR_INVALID_PARAMETER);
991         return CLR_INVALID;
992     }
993 
994     /* Get old color and store the new */
995     crOldColor = pdcattr->ulBackgroundClr;
996     pdcattr->ulBackgroundClr = crColor;
997 
998     if (pdcattr->crBackgroundClr != crColor)
999     {
1000         pdcattr->ulDirty_ |= (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL);
1001         pdcattr->crBackgroundClr = crColor;
1002     }
1003 
1004     return crOldColor;
1005 }
1006 
1007 /*
1008  * @implemented
1009  *
1010  */
1011 int
1012 WINAPI
1013 GetBkMode(HDC hdc)
1014 {
1015     PDC_ATTR pdcattr;
1016 
1017     /* Get the DC attribute */
1018     pdcattr = GdiGetDcAttr(hdc);
1019     if (pdcattr == NULL)
1020     {
1021         /* Don't set LastError here! */
1022         return 0;
1023     }
1024 
1025     return pdcattr->lBkMode;
1026 }
1027 
1028 /*
1029  * @implemented
1030  *
1031  */
1032 int
1033 WINAPI
1034 SetBkMode(
1035     _In_ HDC hdc,
1036     _In_ int iBkMode)
1037 {
1038     PDC_ATTR pdcattr;
1039     INT iOldMode;
1040 
1041     HANDLE_METADC(INT, SetBkMode, 0, hdc, iBkMode);
1042 
1043     /* Get the DC attribute */
1044     pdcattr = GdiGetDcAttr(hdc);
1045     if (pdcattr == NULL)
1046     {
1047         SetLastError(ERROR_INVALID_PARAMETER);
1048         return 0;
1049     }
1050 
1051     iOldMode = pdcattr->lBkMode;
1052     pdcattr->jBkMode = iBkMode; // Processed
1053     pdcattr->lBkMode = iBkMode; // Raw
1054 
1055     return iOldMode;
1056 }
1057 
1058 /*
1059  * @implemented
1060  *
1061  */
1062 int
1063 WINAPI
1064 GetROP2(
1065     _In_ HDC hdc)
1066 {
1067     PDC_ATTR pdcattr;
1068 
1069     /* Get the DC attribute */
1070     pdcattr = GdiGetDcAttr(hdc);
1071     if (pdcattr == NULL)
1072     {
1073         /* Do not set LastError here! */
1074         return 0;
1075     }
1076 
1077     return pdcattr->jROP2;
1078 }
1079 
1080 /*
1081  * @implemented
1082  */
1083 int
1084 WINAPI
1085 SetROP2(
1086     _In_ HDC hdc,
1087     _In_ int rop2)
1088 {
1089     PDC_ATTR pdcattr;
1090     INT rop2Old;
1091 
1092     HANDLE_METADC(INT, SetROP2, 0, hdc, rop2);
1093 
1094     /* Get the DC attribute */
1095     pdcattr = GdiGetDcAttr(hdc);
1096     if (pdcattr == NULL)
1097     {
1098         SetLastError(ERROR_INVALID_PARAMETER);
1099         return 0;
1100     }
1101 
1102     if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
1103     {
1104         if (pdcattr->ulDirty_ & DC_MODE_DIRTY)
1105         {
1106             NtGdiFlush();
1107             pdcattr->ulDirty_ &= ~DC_MODE_DIRTY;
1108         }
1109     }
1110 
1111     rop2Old = pdcattr->jROP2;
1112     pdcattr->jROP2 = (BYTE)rop2;
1113 
1114     return rop2Old;
1115 }
1116 
1117 
1118 /*
1119  * @implemented
1120  *
1121  */
1122 int
1123 WINAPI
1124 GetPolyFillMode(HDC hdc)
1125 {
1126     PDC_ATTR pdcattr;
1127 
1128     /* Get DC attribute */
1129     pdcattr = GdiGetDcAttr(hdc);
1130     if (pdcattr == NULL)
1131     {
1132         /* Don't set LastError here! */
1133         return 0;
1134     }
1135 
1136     /* Return current fill mode */
1137     return pdcattr->lFillMode;
1138 }
1139 
1140 /*
1141  * @unimplemented
1142  */
1143 int
1144 WINAPI
1145 SetPolyFillMode(
1146     _In_ HDC hdc,
1147     _In_ int iPolyFillMode)
1148 {
1149     INT iOldPolyFillMode;
1150     PDC_ATTR pdcattr;
1151 
1152     HANDLE_METADC(INT, SetPolyFillMode, 0, hdc, iPolyFillMode);
1153 
1154     /* Get the DC attribute */
1155     pdcattr = GdiGetDcAttr(hdc);
1156     if (pdcattr == NULL)
1157     {
1158         SetLastError(ERROR_INVALID_PARAMETER);
1159         return 0;
1160     }
1161 
1162     if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
1163     {
1164         if (pdcattr->ulDirty_ & DC_MODE_DIRTY)
1165         {
1166             NtGdiFlush(); // Sync up pdcattr from Kernel space.
1167             pdcattr->ulDirty_ &= ~DC_MODE_DIRTY;
1168         }
1169     }
1170 
1171     iOldPolyFillMode = pdcattr->lFillMode;
1172     pdcattr->lFillMode = iPolyFillMode;
1173 
1174     return iOldPolyFillMode;
1175 }
1176 
1177 /*
1178  * @implemented
1179  *
1180  */
1181 int
1182 WINAPI
1183 GetGraphicsMode(HDC hdc)
1184 {
1185     PDC_ATTR pdcattr;
1186 
1187     /* Get the DC attribute */
1188     pdcattr = GdiGetDcAttr(hdc);
1189     if (pdcattr == NULL)
1190     {
1191         /* Don't set LastError here! */
1192         return 0;
1193     }
1194 
1195     /* Return current graphics mode */
1196     return pdcattr->iGraphicsMode;
1197 }
1198 
1199 /*
1200  * @unimplemented
1201  */
1202 int
1203 WINAPI
1204 SetGraphicsMode(
1205     _In_ HDC hdc,
1206     _In_ int iMode)
1207 {
1208     INT iOldMode;
1209     PDC_ATTR pdcattr;
1210 
1211     /* Check parameters */
1212     if ((iMode < GM_COMPATIBLE) || (iMode > GM_ADVANCED))
1213     {
1214         SetLastError(ERROR_INVALID_PARAMETER);
1215         return 0;
1216     }
1217 
1218     /* Get the DC attribute */
1219     pdcattr = GdiGetDcAttr(hdc);
1220     if (pdcattr == NULL)
1221     {
1222         SetLastError(ERROR_INVALID_PARAMETER);
1223         return 0;
1224     }
1225 
1226     /* Check for trivial case */
1227     if (iMode == pdcattr->iGraphicsMode)
1228         return iMode;
1229 
1230     if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
1231     {
1232         if (pdcattr->ulDirty_ & DC_MODE_DIRTY)
1233         {
1234             NtGdiFlush(); // Sync up pdcattr from Kernel space.
1235             pdcattr->ulDirty_ &= ~DC_MODE_DIRTY;
1236         }
1237     }
1238 
1239     /* One would think that setting the graphics mode to GM_COMPATIBLE
1240      * would also reset the world transformation matrix to the unity
1241      * matrix. However, in Windows, this is not the case. This doesn't
1242      * make a lot of sense to me, but that's the way it is.
1243      */
1244     iOldMode = pdcattr->iGraphicsMode;
1245     pdcattr->iGraphicsMode = iMode;
1246 
1247     return iOldMode;
1248 }
1249 
1250 /*
1251  * @implemented
1252  */
1253 HDC
1254 WINAPI
1255 ResetDCW(
1256     _In_ HDC hdc,
1257     _In_ CONST DEVMODEW *lpInitData)
1258 {
1259     NtGdiResetDC ( hdc, (PDEVMODEW)lpInitData, NULL, NULL, NULL);
1260     return hdc;
1261 }
1262 
1263 
1264 /*
1265  * @implemented
1266  */
1267 HDC
1268 WINAPI
1269 ResetDCA(
1270     _In_ HDC hdc,
1271     _In_ CONST DEVMODEA *lpInitData)
1272 {
1273     LPDEVMODEW InitDataW;
1274 
1275     InitDataW = GdiConvertToDevmodeW((LPDEVMODEA)lpInitData);
1276 
1277     NtGdiResetDC ( hdc, InitDataW, NULL, NULL, NULL);
1278     HEAP_free(InitDataW);
1279     return hdc;
1280 }
1281 
1282 
1283 /* FIXME: include correct header */
1284 HPALETTE WINAPI NtUserSelectPalette(HDC  hDC,
1285                                     HPALETTE  hpal,
1286                                     BOOL  ForceBackground);
1287 
1288 HPALETTE
1289 WINAPI
1290 SelectPalette(
1291     HDC hdc,
1292     HPALETTE hpal,
1293     BOOL bForceBackground)
1294 {
1295     HANDLE_METADC(HPALETTE, SelectPalette, NULL, hdc, hpal, bForceBackground);
1296 
1297     return NtUserSelectPalette(hdc, hpal, bForceBackground);
1298 }
1299 
1300 /*
1301  * @implemented
1302  *
1303  */
1304 int
1305 WINAPI
1306 GetStretchBltMode(HDC hdc)
1307 {
1308     PDC_ATTR pdcattr;
1309 
1310     /* Get the DC attribute */
1311     pdcattr = GdiGetDcAttr(hdc);
1312     if (pdcattr == NULL)
1313     {
1314         /* Don't set LastError here! */
1315         return 0;
1316     }
1317 
1318     return pdcattr->lStretchBltMode;
1319 }
1320 
1321 /*
1322  * @implemented
1323  */
1324 int
1325 WINAPI
1326 SetStretchBltMode(
1327     _In_ HDC hdc,
1328     _In_ int iStretchMode)
1329 {
1330     INT iOldMode;
1331     PDC_ATTR pdcattr;
1332 
1333     HANDLE_METADC(INT, SetStretchBltMode, 0, hdc, iStretchMode);
1334 
1335     /* Get the DC attribute */
1336     pdcattr = GdiGetDcAttr(hdc);
1337     if (pdcattr == NULL)
1338     {
1339         SetLastError(ERROR_INVALID_PARAMETER);
1340         return 0;
1341     }
1342 
1343     iOldMode = pdcattr->lStretchBltMode;
1344     pdcattr->lStretchBltMode = iStretchMode;
1345 
1346     // Wine returns an error here. We set the default.
1347     if ((iStretchMode <= 0) || (iStretchMode > MAXSTRETCHBLTMODE)) iStretchMode = WHITEONBLACK;
1348 
1349     pdcattr->jStretchBltMode = iStretchMode;
1350 
1351     return iOldMode;
1352 }
1353 
1354 /*
1355  * @implemented
1356  */
1357 HFONT
1358 WINAPI
1359 GetHFONT(HDC hdc)
1360 {
1361     PDC_ATTR pdcattr;
1362 
1363     /* Get the DC attribute */
1364     pdcattr = GdiGetDcAttr(hdc);
1365     if (pdcattr == NULL)
1366     {
1367         /* Don't set LastError here! */
1368         return NULL;
1369     }
1370 
1371     /* Return the current font */
1372     return pdcattr->hlfntNew;
1373 }
1374 
1375 
1376 
1377 HBITMAP
1378 WINAPI
1379 GdiSelectBitmap(
1380     _In_ HDC hdc,
1381     _In_ HBITMAP hbmp)
1382 {
1383     return NtGdiSelectBitmap(hdc, hbmp);
1384 }
1385 
1386 HBRUSH
1387 WINAPI
1388 GdiSelectBrush(
1389     _In_ HDC hdc,
1390     _In_ HBRUSH hbr)
1391 {
1392     PDC_ATTR pdcattr;
1393     HBRUSH hbrOld;
1394 
1395     HANDLE_METADC(HBRUSH, SelectBrush, NULL, hdc, hbr);
1396 
1397     /* Get the DC attribute */
1398     pdcattr = GdiGetDcAttr(hdc);
1399     if (pdcattr == NULL)
1400     {
1401         SetLastError(ERROR_INVALID_PARAMETER);
1402         return NULL;
1403     }
1404 
1405     /* Get the current brush. If it matches the new brush, we're done */
1406     hbrOld = pdcattr->hbrush;
1407     if (hbrOld == hbr)
1408         return hbrOld;
1409 
1410     /* Set the new brush and update dirty flags */
1411     pdcattr->hbrush = hbr;
1412     pdcattr->ulDirty_ |= DC_BRUSH_DIRTY;
1413     return hbrOld;
1414 }
1415 
1416 HPEN
1417 WINAPI
1418 GdiSelectPen(
1419     _In_ HDC hdc,
1420     _In_ HPEN hpen)
1421 {
1422     PDC_ATTR pdcattr;
1423     HPEN hpenOld;
1424 
1425     HANDLE_METADC(HPEN, SelectPen, NULL, hdc, hpen);
1426 
1427     /* Get the DC attribute */
1428     pdcattr = GdiGetDcAttr(hdc);
1429     if (pdcattr == NULL)
1430     {
1431         SetLastError(ERROR_INVALID_HANDLE);
1432         return NULL;
1433     }
1434 
1435     /* Get the current pen. If it matches the new pen, we're done */
1436     hpenOld = pdcattr->hpen;
1437     if (hpenOld == hpen)
1438         return hpenOld;
1439 
1440     /* Set the new pen and update dirty flags */
1441     pdcattr->ulDirty_ |= DC_PEN_DIRTY;
1442     pdcattr->hpen = hpen;
1443     return hpenOld;
1444 }
1445 
1446 HFONT
1447 WINAPI
1448 GdiSelectFont(
1449     _In_ HDC hdc,
1450     _In_ HFONT hfont)
1451 {
1452     PDC_ATTR pdcattr;
1453     HFONT hfontOld;
1454 
1455     HANDLE_METADC(HFONT, SelectFont, NULL, hdc, hfont);
1456 
1457     /* Get the DC attribute */
1458     pdcattr = GdiGetDcAttr(hdc);
1459     if (pdcattr == NULL)
1460     {
1461         SetLastError(ERROR_INVALID_PARAMETER);
1462         return NULL;
1463     }
1464 
1465     /* Get the current font. If it matches the new font, we're done */
1466     hfontOld = pdcattr->hlfntNew;
1467     if (hfontOld == hfont)
1468         return hfontOld;
1469 
1470     /* Set the new font and update dirty flags */
1471     pdcattr->hlfntNew = hfont;
1472     pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
1473     pdcattr->ulDirty_ |= DIRTY_CHARSET;
1474 
1475     /* If the DC does not have a DIB section selected, try a batch command */
1476     if (!(pdcattr->ulDirty_ & DC_DIBSECTION))
1477     {
1478         PGDIBSOBJECT pgO;
1479 
1480         pgO = GdiAllocBatchCommand(hdc, GdiBCSelObj);
1481         if (pgO)
1482         {
1483             pgO->hgdiobj = hfont;
1484             return hfontOld;
1485         }
1486     }
1487 
1488     /* We could not use the batch command, call win32k */
1489     return NtGdiSelectFont(hdc, hfont);
1490 }
1491 
1492 
1493 /*
1494  * @implemented
1495  *
1496  */
1497 HGDIOBJ
1498 WINAPI
1499 SelectObject(
1500     _In_ HDC hdc,
1501     _In_ HGDIOBJ hobj)
1502 {
1503     /* Fix up 16 bit handles */
1504     hobj = GdiFixUpHandle(hobj);
1505     if (!GdiValidateHandle(hobj))
1506     {
1507         return NULL;
1508     }
1509 
1510     /* Call the appropriate select function */
1511     switch (GDI_HANDLE_GET_TYPE(hobj))
1512     {
1513         case GDILoObjType_LO_REGION_TYPE:
1514             return (HGDIOBJ)UlongToHandle(ExtSelectClipRgn(hdc, hobj, RGN_COPY));
1515 
1516         case GDILoObjType_LO_BITMAP_TYPE:
1517         case GDILoObjType_LO_DIBSECTION_TYPE:
1518             return GdiSelectBitmap(hdc, hobj);
1519 
1520         case GDILoObjType_LO_BRUSH_TYPE:
1521             return GdiSelectBrush(hdc, hobj);
1522 
1523         case GDILoObjType_LO_PEN_TYPE:
1524         case GDILoObjType_LO_EXTPEN_TYPE:
1525             return GdiSelectPen(hdc, hobj);
1526 
1527         case GDILoObjType_LO_FONT_TYPE:
1528             return GdiSelectFont(hdc, hobj);
1529 
1530         case GDILoObjType_LO_ICMLCS_TYPE:
1531             return SetColorSpace(hdc, hobj);
1532 
1533         case GDILoObjType_LO_PALETTE_TYPE:
1534             SetLastError(ERROR_INVALID_FUNCTION);
1535 
1536         default:
1537             return NULL;
1538     }
1539 
1540     return NULL;
1541 }
1542 
1543 /***********************************************************************
1544  *           D3DKMTCreateDCFromMemory    (GDI32.@)
1545  */
1546 DWORD WINAPI D3DKMTCreateDCFromMemory( D3DKMT_CREATEDCFROMMEMORY *desc )
1547 {
1548     return NtGdiDdDDICreateDCFromMemory( desc );
1549 }
1550 
1551 DWORD WINAPI D3DKMTDestroyDCFromMemory( const D3DKMT_DESTROYDCFROMMEMORY *desc )
1552 {
1553     return NtGdiDdDDIDestroyDCFromMemory( desc );
1554 }
1555