be21fedb2213e35a75f453fa9532013863de2b8c
[reactos.git] / reactos / win32ss / gdi / ntgdi / dcobjs.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Functions for creation and destruction of DCs
5 * FILE: subsystems/win32/win32k/objects/dcobjs.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 VOID
15 FASTCALL
16 DC_vUpdateFillBrush(PDC pdc)
17 {
18 PDC_ATTR pdcattr = pdc->pdcattr;
19 PBRUSH pbrFill;
20
21 /* Check if the brush handle has changed */
22 if (pdcattr->hbrush != pdc->dclevel.pbrFill->BaseObject.hHmgr)
23 {
24 /* Try to lock the new brush */
25 pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush);
26 if (pbrFill)
27 {
28 /* Unlock old brush, set new brush */
29 BRUSH_ShareUnlockBrush(pdc->dclevel.pbrFill);
30 pdc->dclevel.pbrFill = pbrFill;
31
32 /* Mark eboFill as dirty */
33 pdcattr->ulDirty_ |= DIRTY_FILL;
34 }
35 else
36 {
37 /* Invalid brush handle, restore old one */
38 pdcattr->hbrush = pdc->dclevel.pbrFill->BaseObject.hHmgr;
39 }
40 }
41
42 /* Check if the EBRUSHOBJ needs update */
43 if (pdcattr->ulDirty_ & DIRTY_FILL)
44 {
45 /* Update eboFill */
46 EBRUSHOBJ_vUpdateFromDC(&pdc->eboFill, pdc->dclevel.pbrFill, pdc);
47 }
48
49 /* Check for DC brush */
50 if (pdcattr->hbrush == StockObjects[DC_BRUSH])
51 {
52 /* ROS HACK, should use surf xlate */
53 /* Update the eboFill's solid color */
54 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboFill, pdcattr->crPenClr);
55 }
56
57 /* Clear flags */
58 pdcattr->ulDirty_ &= ~(DIRTY_FILL | DC_BRUSH_DIRTY);
59 }
60
61 VOID
62 FASTCALL
63 DC_vUpdateLineBrush(PDC pdc)
64 {
65 PDC_ATTR pdcattr = pdc->pdcattr;
66 PBRUSH pbrLine;
67
68 /* Check if the pen handle has changed */
69 if (pdcattr->hpen != pdc->dclevel.pbrLine->BaseObject.hHmgr)
70 {
71 /* Try to lock the new pen */
72 pbrLine = PEN_ShareLockPen(pdcattr->hpen);
73 if (pbrLine)
74 {
75 /* Unlock old brush, set new brush */
76 BRUSH_ShareUnlockBrush(pdc->dclevel.pbrLine);
77 pdc->dclevel.pbrLine = pbrLine;
78
79 /* Mark eboLine as dirty */
80 pdcattr->ulDirty_ |= DIRTY_LINE;
81 }
82 else
83 {
84 /* Invalid pen handle, restore old one */
85 pdcattr->hpen = pdc->dclevel.pbrLine->BaseObject.hHmgr;
86 }
87 }
88
89 /* Check if the EBRUSHOBJ needs update */
90 if (pdcattr->ulDirty_ & DIRTY_LINE)
91 {
92 /* Update eboLine */
93 EBRUSHOBJ_vUpdateFromDC(&pdc->eboLine, pdc->dclevel.pbrLine, pdc);
94 }
95
96 /* Check for DC pen */
97 if (pdcattr->hpen == StockObjects[DC_PEN])
98 {
99 /* Update the eboLine's solid color */
100 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboLine, pdcattr->crPenClr);
101 }
102
103 /* Clear flags */
104 pdcattr->ulDirty_ &= ~(DIRTY_LINE | DC_PEN_DIRTY);
105 }
106
107 VOID
108 FASTCALL
109 DC_vUpdateTextBrush(PDC pdc)
110 {
111 PDC_ATTR pdcattr = pdc->pdcattr;
112
113 /* Timo : The text brush should never be changed.
114 * Jérôme : Yeah, but its palette must be updated anyway! */
115 if(pdcattr->ulDirty_ & DIRTY_TEXT)
116 EBRUSHOBJ_vUpdateFromDC(&pdc->eboText, pbrDefaultBrush, pdc);
117
118 /* Update the eboText's solid color */
119 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboText, pdcattr->crForegroundClr);
120
121 /* Clear flag */
122 pdcattr->ulDirty_ &= ~DIRTY_TEXT;
123 }
124
125 VOID
126 FASTCALL
127 DC_vUpdateBackgroundBrush(PDC pdc)
128 {
129 PDC_ATTR pdcattr = pdc->pdcattr;
130
131 if(pdcattr->ulDirty_ & DIRTY_BACKGROUND)
132 EBRUSHOBJ_vUpdateFromDC(&pdc->eboBackground, pbrDefaultBrush, pdc);
133
134 /* Update the eboBackground's solid color */
135 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboBackground, pdcattr->crBackgroundClr);
136
137 /* Clear flag */
138 pdcattr->ulDirty_ &= ~DIRTY_BACKGROUND;
139 }
140
141 VOID
142 NTAPI
143 DC_vSetBrushOrigin(PDC pdc, LONG x, LONG y)
144 {
145 /* Set the brush origin */
146 pdc->dclevel.ptlBrushOrigin.x = x;
147 pdc->dclevel.ptlBrushOrigin.y = y;
148
149 /* Set the fill origin */
150 pdc->ptlFillOrigin.x = x + pdc->ptlDCOrig.x;
151 pdc->ptlFillOrigin.y = y + pdc->ptlDCOrig.y;
152 }
153
154 /**
155 * \name NtGdiSetBrushOrg
156 *
157 * \brief Sets the brush origin that GDI uses when drawing with pattern
158 * brushes. The brush origin is relative to the DC origin.
159 *
160 * @implemented
161 */
162 _Success_(return != FALSE)
163 BOOL
164 APIENTRY
165 NtGdiSetBrushOrg(
166 _In_ HDC hdc,
167 _In_ INT x,
168 _In_ INT y,
169 _Out_opt_ LPPOINT pptOut)
170 {
171 PDC pdc;
172
173 /* Lock the DC */
174 pdc = DC_LockDc(hdc);
175 if (pdc == NULL)
176 {
177 EngSetLastError(ERROR_INVALID_HANDLE);
178 return FALSE;
179 }
180
181 /* Check if the old origin was requested */
182 if (pptOut != NULL)
183 {
184 /* Enter SEH for buffer transfer */
185 _SEH2_TRY
186 {
187 /* Probe and copy the old origin */
188 ProbeForWrite(pptOut, sizeof(POINT), 1);
189 *pptOut = pdc->pdcattr->ptlBrushOrigin;
190 }
191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
192 {
193 DC_UnlockDc(pdc);
194 _SEH2_YIELD(return FALSE);
195 }
196 _SEH2_END;
197 }
198
199 /* Call the internal function */
200 DC_vSetBrushOrigin(pdc, x, y);
201
202 /* Unlock the DC and return success */
203 DC_UnlockDc(pdc);
204 return TRUE;
205 }
206
207 HPALETTE
208 NTAPI
209 GdiSelectPalette(
210 HDC hDC,
211 HPALETTE hpal,
212 BOOL ForceBackground)
213 {
214 PDC pdc;
215 HPALETTE oldPal = NULL;
216 PPALETTE ppal;
217
218 // FIXME: Mark the palette as a [fore\back]ground pal
219 pdc = DC_LockDc(hDC);
220 if (!pdc)
221 {
222 return NULL;
223 }
224
225 /* Check if this is a valid palette handle */
226 ppal = PALETTE_ShareLockPalette(hpal);
227 if (!ppal)
228 {
229 DC_UnlockDc(pdc);
230 return NULL;
231 }
232
233 /* Is this a valid palette for this depth? */
234 if ((!pdc->dclevel.pSurface) ||
235 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) <= 8
236 && (ppal->flFlags & PAL_INDEXED)) ||
237 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) > 8))
238 {
239 /* Get old palette, set new one */
240 oldPal = pdc->dclevel.hpal;
241 pdc->dclevel.hpal = hpal;
242 DC_vSelectPalette(pdc, ppal);
243
244 /* Mark the brushes invalid */
245 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE |
246 DIRTY_BACKGROUND | DIRTY_TEXT;
247 }
248
249 if(pdc->dctype == DCTYPE_MEMORY)
250 {
251 // This didn't work anyway
252 //IntGdiRealizePalette(hDC);
253 }
254
255 PALETTE_ShareUnlockPalette(ppal);
256 DC_UnlockDc(pdc);
257
258 return oldPal;
259 }
260
261 /*
262 * @implemented
263 */
264 HBRUSH
265 APIENTRY
266 NtGdiSelectBrush(
267 IN HDC hDC,
268 IN HBRUSH hBrush)
269 {
270 PDC pDC;
271 HBRUSH hOrgBrush;
272
273 if (hDC == NULL || hBrush == NULL) return NULL;
274
275 pDC = DC_LockDc(hDC);
276 if (!pDC)
277 {
278 return NULL;
279 }
280
281 /* Simply return the user mode value, without checking */
282 hOrgBrush = pDC->pdcattr->hbrush;
283 pDC->pdcattr->hbrush = hBrush;
284 DC_vUpdateFillBrush(pDC);
285
286 DC_UnlockDc(pDC);
287
288 return hOrgBrush;
289 }
290
291 /*
292 * @implemented
293 */
294 HPEN
295 APIENTRY
296 NtGdiSelectPen(
297 IN HDC hDC,
298 IN HPEN hPen)
299 {
300 PDC pDC;
301 HPEN hOrgPen;
302
303 if (hDC == NULL || hPen == NULL) return NULL;
304
305 pDC = DC_LockDc(hDC);
306 if (!pDC)
307 {
308 return NULL;
309 }
310
311 /* Simply return the user mode value, without checking */
312 hOrgPen = pDC->pdcattr->hpen;
313 pDC->pdcattr->hpen = hPen;
314 DC_vUpdateLineBrush(pDC);
315
316 DC_UnlockDc(pDC);
317
318 return hOrgPen;
319 }
320
321 /*
322 * @implemented
323 */
324 HBITMAP
325 APIENTRY
326 NtGdiSelectBitmap(
327 IN HDC hdc,
328 IN HBITMAP hbmp)
329 {
330 PDC pdc;
331 HBITMAP hbmpOld;
332 PSURFACE psurfNew, psurfOld;
333 HRGN hVisRgn;
334 HDC hdcOld;
335 ULONG cBitsPixel;
336 ASSERT_NOGDILOCKS();
337
338 /* Verify parameters */
339 if (hdc == NULL || hbmp == NULL) return NULL;
340
341 /* First lock the DC */
342 pdc = DC_LockDc(hdc);
343 if (!pdc)
344 {
345 return NULL;
346 }
347
348 /* Must be a memory dc to select a bitmap */
349 if (pdc->dctype != DC_TYPE_MEMORY)
350 {
351 DC_UnlockDc(pdc);
352 return NULL;
353 }
354
355 /* Save the old bitmap */
356 psurfOld = pdc->dclevel.pSurface;
357
358 /* Check if there is a bitmap selected */
359 if (psurfOld)
360 {
361 /* Get the old bitmap's handle */
362 hbmpOld = psurfOld->BaseObject.hHmgr;
363 }
364 else
365 {
366 /* Use the default bitmap */
367 hbmpOld = StockObjects[DEFAULT_BITMAP];
368 }
369
370 /* Check if the new bitmap is already selected */
371 if (hbmp == hbmpOld)
372 {
373 /* Unlock the DC and return the old bitmap */
374 DC_UnlockDc(pdc);
375 return hbmpOld;
376 }
377
378 /* Check if the default bitmap was passed */
379 if (hbmp == StockObjects[DEFAULT_BITMAP])
380 {
381 psurfNew = NULL;
382
383 /* Default bitmap is 1x1 pixel */
384 pdc->dclevel.sizl.cx = 1;
385 pdc->dclevel.sizl.cy = 1;
386 }
387 else
388 {
389 /* Reference the new bitmap and check if it's valid */
390 psurfNew = SURFACE_ShareLockSurface(hbmp);
391 if (!psurfNew)
392 {
393 DC_UnlockDc(pdc);
394 return NULL;
395 }
396
397 /* Check if the bitmap is compatile with the dc */
398 cBitsPixel = gajBitsPerFormat[psurfNew->SurfObj.iBitmapFormat];
399 if ((cBitsPixel != 1) &&
400 (cBitsPixel != pdc->ppdev->gdiinfo.cBitsPixel) &&
401 (psurfNew->hSecure == NULL))
402 {
403 /* Dereference the bitmap, unlock the DC and fail. */
404 SURFACE_ShareUnlockSurface(psurfNew);
405 DC_UnlockDc(pdc);
406 return NULL;
407 }
408
409 /* Set the bitmap's hdc and check if it was set before */
410 hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
411 if (hdcOld != NULL)
412 {
413 /* The bitmap is already selected into a different DC */
414 ASSERT(hdcOld != hdc);
415
416 /* Dereference the bitmap, unlock the DC and fail. */
417 SURFACE_ShareUnlockSurface(psurfNew);
418 DC_UnlockDc(pdc);
419 return NULL;
420 }
421
422 /* Copy the bitmap size */
423 pdc->dclevel.sizl = psurfNew->SurfObj.sizlBitmap;
424
425 /* Check if the bitmap is a dibsection */
426 if (psurfNew->hSecure)
427 {
428 /* Set DIBSECTION attribute */
429 pdc->pdcattr->ulDirty_ |= DC_DIBSECTION;
430 }
431 else
432 {
433 /* Remove DIBSECTION attribute */
434 pdc->pdcattr->ulDirty_ &= ~DC_DIBSECTION;
435 }
436 }
437
438 /* Select the new bitmap */
439 pdc->dclevel.pSurface = psurfNew;
440
441 /* Check if there was a bitmap selected before */
442 if (psurfOld)
443 {
444 /* Reset hdc of the old bitmap, it isn't selected anymore */
445 psurfOld->hdc = NULL;
446
447 /* Dereference the old bitmap */
448 SURFACE_ShareUnlockSurface(psurfOld);
449 }
450
451 /* Mark the dc brushes invalid */
452 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
453
454 /* FIXME: Improve by using a region without a handle and selecting it */
455 hVisRgn = IntSysCreateRectRgn( 0,
456 0,
457 pdc->dclevel.sizl.cx,
458 pdc->dclevel.sizl.cy);
459
460 if (hVisRgn)
461 {
462 GdiSelectVisRgn(hdc, hVisRgn);
463 GreDeleteObject(hVisRgn);
464 }
465
466 /* Unlock the DC */
467 DC_UnlockDc(pdc);
468
469 /* Return the old bitmap handle */
470 return hbmpOld;
471 }
472
473
474 BOOL
475 APIENTRY
476 NtGdiSelectClipPath(
477 HDC hDC,
478 int Mode)
479 {
480 HRGN hrgnPath;
481 PPATH pPath;
482 BOOL success = FALSE;
483 PDC_ATTR pdcattr;
484 PDC pdc;
485
486 pdc = DC_LockDc(hDC);
487 if (!pdc)
488 {
489 EngSetLastError(ERROR_INVALID_PARAMETER);
490 return FALSE;
491 }
492 pdcattr = pdc->pdcattr;
493
494 pPath = PATH_LockPath(pdc->dclevel.hPath);
495 if (!pPath)
496 {
497 DC_UnlockDc(pdc);
498 return FALSE;
499 }
500
501 /* Check that path is closed */
502 if (pPath->state != PATH_Closed)
503 {
504 EngSetLastError(ERROR_CAN_NOT_COMPLETE);
505 DC_UnlockDc(pdc);
506 return FALSE;
507 }
508
509 /* Construct a region from the path */
510 else if (PATH_PathToRegion(pPath, pdcattr->jFillMode, &hrgnPath))
511 {
512 success = GdiExtSelectClipRgn(pdc, hrgnPath, Mode) != ERROR;
513 GreDeleteObject( hrgnPath );
514
515 /* Empty the path */
516 if (success)
517 PATH_EmptyPath(pPath);
518
519 /* FIXME: Should this function delete the path even if it failed? */
520 }
521
522 PATH_UnlockPath(pPath);
523 DC_UnlockDc(pdc);
524
525 return success;
526 }
527
528 HFONT
529 NTAPI
530 DC_hSelectFont(
531 _In_ PDC pdc,
532 _In_ HFONT hlfntNew)
533 {
534 PLFONT plfntNew;
535 HFONT hlfntOld;
536
537 // Legacy crap that will die with font engine rewrite
538 if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew, NULL)))
539 {
540 return NULL;
541 }
542
543 /* Get the current selected font */
544 hlfntOld = pdc->dclevel.plfnt->BaseObject.hHmgr;
545
546 /* Check if a new font should be selected */
547 if (hlfntNew != hlfntOld)
548 {
549 /* Lock the new font */
550 plfntNew = LFONT_ShareLockFont(hlfntNew);
551 if (plfntNew)
552 {
553 /* Success, dereference the old font */
554 LFONT_ShareUnlockFont(pdc->dclevel.plfnt);
555
556 /* Select the new font */
557 pdc->dclevel.plfnt = plfntNew;
558 pdc->pdcattr->hlfntNew = hlfntNew;
559
560 /* Update dirty flags */
561 pdc->pdcattr->ulDirty_ |= DIRTY_CHARSET;
562 pdc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
563 }
564 else
565 {
566 /* Failed, restore old, return NULL */
567 pdc->pdcattr->hlfntNew = hlfntOld;
568 hlfntOld = NULL;
569 }
570 }
571
572 return hlfntOld;
573 }
574
575 HFONT
576 APIENTRY
577 NtGdiSelectFont(
578 _In_ HDC hdc,
579 _In_ HFONT hfont)
580 {
581 HFONT hfontOld;
582 PDC pdc;
583
584 /* Check parameters */
585 if ((hdc == NULL) || (hfont == NULL))
586 {
587 return NULL;
588 }
589
590 /* Lock the DC */
591 pdc = DC_LockDc(hdc);
592 if (!pdc)
593 {
594 return NULL;
595 }
596
597 /* Call the internal function */
598 hfontOld = DC_hSelectFont(pdc, hfont);
599
600 /* Unlock the DC */
601 DC_UnlockDc(pdc);
602
603 /* Return the previously selected font */
604 return hfontOld;
605 }
606
607 HANDLE
608 APIENTRY
609 NtGdiGetDCObject(HDC hDC, INT ObjectType)
610 {
611 HGDIOBJ SelObject;
612 DC *pdc;
613 PDC_ATTR pdcattr;
614
615 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
616 if(!hDC) return NULL;
617
618 if(!(pdc = DC_LockDc(hDC)))
619 {
620 return NULL;
621 }
622 pdcattr = pdc->pdcattr;
623
624 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
625 DC_vUpdateFillBrush(pdc);
626
627 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
628 DC_vUpdateLineBrush(pdc);
629
630 switch(ObjectType)
631 {
632 case GDI_OBJECT_TYPE_EXTPEN:
633 case GDI_OBJECT_TYPE_PEN:
634 SelObject = pdcattr->hpen;
635 break;
636
637 case GDI_OBJECT_TYPE_BRUSH:
638 SelObject = pdcattr->hbrush;
639 break;
640
641 case GDI_OBJECT_TYPE_PALETTE:
642 SelObject = pdc->dclevel.hpal;
643 break;
644
645 case GDI_OBJECT_TYPE_FONT:
646 SelObject = pdcattr->hlfntNew;
647 break;
648
649 case GDI_OBJECT_TYPE_BITMAP:
650 {
651 SURFACE *psurf = pdc->dclevel.pSurface;
652 SelObject = psurf ? psurf->BaseObject.hHmgr : StockObjects[DEFAULT_BITMAP];
653 break;
654 }
655
656 case GDI_OBJECT_TYPE_COLORSPACE:
657 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
658 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
659 SelObject = NULL;
660 break;
661
662 default:
663 SelObject = NULL;
664 EngSetLastError(ERROR_INVALID_PARAMETER);
665 break;
666 }
667
668 DC_UnlockDc(pdc);
669 return SelObject;
670 }
671
672 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
673 *
674 * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
675 *
676 * The intersection of the clip with the meta region is not Rao it's API!
677 * Go back and read 7.2 Clipping pages 418-19:
678 * Rao = API & Vis:
679 * 1) The Rao region is the intersection of the API region and the system region,
680 * named after the Microsoft engineer who initially proposed it.
681 * 2) The Rao region can be calculated from the API region and the system region.
682 *
683 * API:
684 * API region is the intersection of the meta region and the clipping region,
685 * clearly named after the fact that it is controlled by GDI API calls.
686 */
687 INT
688 APIENTRY
689 NtGdiGetRandomRgn(
690 HDC hdc,
691 HRGN hrgnDest,
692 INT iCode)
693 {
694 INT ret = 0;
695 PDC pdc;
696 HRGN hrgnSrc = NULL;
697 PREGION prgnSrc = NULL;
698 POINTL ptlOrg;
699
700 pdc = DC_LockDc(hdc);
701 if (!pdc)
702 {
703 EngSetLastError(ERROR_INVALID_HANDLE);
704 return -1;
705 }
706
707 switch (iCode)
708 {
709 case CLIPRGN:
710 hrgnSrc = pdc->rosdc.hClipRgn;
711 // if (pdc->dclevel.prgnClip) prgnSrc = pdc->dclevel.prgnClip;
712 break;
713
714 case METARGN:
715 prgnSrc = pdc->dclevel.prgnMeta;
716 break;
717
718 case APIRGN:
719 if (pdc->prgnAPI)
720 {
721 prgnSrc = pdc->prgnAPI;
722 }
723 // else if (pdc->dclevel.prgnClip) prgnSrc = pdc->dclevel.prgnClip;
724 else if (pdc->rosdc.hClipRgn)
725 {
726 hrgnSrc = pdc->rosdc.hClipRgn;
727 }
728 else if (pdc->dclevel.prgnMeta)
729 {
730 prgnSrc = pdc->dclevel.prgnMeta;
731 }
732 break;
733
734 case SYSRGN:
735 prgnSrc = pdc->prgnVis;
736 break;
737
738 default:
739 break;
740 }
741
742 if (hrgnSrc)
743 {
744 ret = NtGdiCombineRgn(hrgnDest, hrgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
745 }
746 else if (prgnSrc)
747 {
748 PREGION prgnDest = REGION_LockRgn(hrgnDest);
749 if (prgnDest)
750 {
751 ret = IntGdiCombineRgn(prgnDest, prgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
752 REGION_UnlockRgn(prgnDest);
753 }
754 else
755 ret = -1;
756 }
757
758 if (iCode == SYSRGN)
759 {
760 ptlOrg = pdc->ptlDCOrig;
761 NtGdiOffsetRgn(hrgnDest, ptlOrg.x, ptlOrg.y );
762 }
763
764 DC_UnlockDc(pdc);
765
766 return ret;
767 }
768
769 ULONG
770 APIENTRY
771 NtGdiEnumObjects(
772 IN HDC hdc,
773 IN INT iObjectType,
774 IN ULONG cjBuf,
775 OUT OPTIONAL PVOID pvBuf)
776 {
777 UNIMPLEMENTED;
778 return 0;
779 }
780
781 /* EOF */