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