e4a6f40bb19a7389421c58c39d04d28cc28d7708
[reactos.git] / reactos / win32ss / gdi / ntgdi / dcutil.c
1 #include <win32k.h>
2
3 #define NDEBUG
4 #include <debug.h>
5
6 BOOL FASTCALL
7 GreDPtoLP(HDC hdc, LPPOINT lpPoints, INT nCount)
8 {
9 PDC dc;
10 if (!(dc = DC_LockDc(hdc)))
11 {
12 EngSetLastError(ERROR_INVALID_HANDLE);
13 return FALSE;
14 }
15 IntDPtoLP(dc, lpPoints, nCount);
16 DC_UnlockDc(dc);
17 return TRUE;
18 }
19
20 BOOL FASTCALL
21 GreLPtoDP(HDC hdc, LPPOINT lpPoints, INT nCount)
22 {
23 PDC dc;
24 if (!(dc = DC_LockDc(hdc)))
25 {
26 EngSetLastError(ERROR_INVALID_HANDLE);
27 return FALSE;
28 }
29 IntLPtoDP(dc, lpPoints, nCount);
30 DC_UnlockDc(dc);
31 return TRUE;
32 }
33
34 int FASTCALL
35 GreGetBkMode(HDC hdc)
36 {
37 PDC dc;
38 LONG lBkMode;
39 if (!(dc = DC_LockDc(hdc)))
40 {
41 EngSetLastError(ERROR_INVALID_HANDLE);
42 return CLR_INVALID;
43 }
44 lBkMode = dc->pdcattr->lBkMode;
45 DC_UnlockDc(dc);
46 return lBkMode;
47 }
48
49 int FASTCALL
50 GreGetMapMode(HDC hdc)
51 {
52 PDC dc;
53 INT iMapMode;
54 if (!(dc = DC_LockDc(hdc)))
55 {
56 EngSetLastError(ERROR_INVALID_HANDLE);
57 return CLR_INVALID;
58 }
59 iMapMode = dc->pdcattr->iMapMode;
60 DC_UnlockDc(dc);
61 return iMapMode;
62 }
63
64 COLORREF FASTCALL
65 GreGetTextColor(HDC hdc)
66 {
67 PDC dc;
68 ULONG ulForegroundClr;
69 if (!(dc = DC_LockDc(hdc)))
70 {
71 EngSetLastError(ERROR_INVALID_HANDLE);
72 return CLR_INVALID;
73 }
74 ulForegroundClr = dc->pdcattr->ulForegroundClr;
75 DC_UnlockDc(dc);
76 return ulForegroundClr;
77 }
78
79 COLORREF FASTCALL
80 IntGdiSetBkColor(HDC hDC, COLORREF color)
81 {
82 COLORREF oldColor;
83 PDC dc;
84 PDC_ATTR pdcattr;
85 HBRUSH hBrush;
86
87 if (!(dc = DC_LockDc(hDC)))
88 {
89 EngSetLastError(ERROR_INVALID_HANDLE);
90 return CLR_INVALID;
91 }
92 pdcattr = dc->pdcattr;
93 oldColor = pdcattr->crBackgroundClr;
94 pdcattr->crBackgroundClr = color;
95 pdcattr->ulBackgroundClr = (ULONG)color;
96 pdcattr->ulDirty_ |= DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL; // Clear Flag if set.
97 hBrush = pdcattr->hbrush;
98 DC_UnlockDc(dc);
99 NtGdiSelectBrush(hDC, hBrush);
100 return oldColor;
101 }
102
103 INT FASTCALL
104 IntGdiSetBkMode(HDC hDC, INT Mode)
105 {
106 COLORREF oldMode;
107 PDC dc;
108 PDC_ATTR pdcattr;
109
110 if (!(dc = DC_LockDc(hDC)))
111 {
112 EngSetLastError(ERROR_INVALID_HANDLE);
113 return CLR_INVALID;
114 }
115 pdcattr = dc->pdcattr;
116 oldMode = pdcattr->lBkMode;
117 pdcattr->jBkMode = Mode;
118 pdcattr->lBkMode = Mode;
119 DC_UnlockDc(dc);
120 return oldMode;
121 }
122
123 UINT
124 FASTCALL
125 IntGdiSetTextAlign(HDC hDC,
126 UINT Mode)
127 {
128 UINT prevAlign;
129 DC *dc;
130 PDC_ATTR pdcattr;
131
132 dc = DC_LockDc(hDC);
133 if (!dc)
134 {
135 EngSetLastError(ERROR_INVALID_HANDLE);
136 return GDI_ERROR;
137 }
138 pdcattr = dc->pdcattr;
139 prevAlign = pdcattr->lTextAlign;
140 pdcattr->lTextAlign = Mode;
141 DC_UnlockDc(dc);
142 return prevAlign;
143 }
144
145 COLORREF
146 FASTCALL
147 IntGdiSetTextColor(HDC hDC,
148 COLORREF color)
149 {
150 COLORREF crOldColor;
151 PDC pdc;
152 PDC_ATTR pdcattr;
153
154 pdc = DC_LockDc(hDC);
155 if (!pdc)
156 {
157 EngSetLastError(ERROR_INVALID_HANDLE);
158 return CLR_INVALID;
159 }
160 pdcattr = pdc->pdcattr;
161
162 // What about ulForegroundClr, like in gdi32?
163 crOldColor = pdcattr->crForegroundClr;
164 pdcattr->crForegroundClr = color;
165 DC_vUpdateTextBrush(pdc);
166
167 DC_UnlockDc(pdc);
168
169 return crOldColor;
170 }
171
172 COLORREF FASTCALL
173 IntSetDCBrushColor(HDC hdc, COLORREF crColor)
174 {
175 COLORREF OldColor = CLR_INVALID;
176 PDC dc;
177 if (!(dc = DC_LockDc(hdc)))
178 {
179 EngSetLastError(ERROR_INVALID_HANDLE);
180 return CLR_INVALID;
181 }
182 else
183 {
184 OldColor = (COLORREF) dc->pdcattr->ulBrushClr;
185 dc->pdcattr->ulBrushClr = (ULONG) crColor;
186
187 if ( dc->pdcattr->crBrushClr != crColor )
188 {
189 dc->pdcattr->ulDirty_ |= DIRTY_FILL;
190 dc->pdcattr->crBrushClr = crColor;
191 }
192 }
193 DC_UnlockDc(dc);
194 return OldColor;
195 }
196
197 COLORREF FASTCALL
198 IntSetDCPenColor(HDC hdc, COLORREF crColor)
199 {
200 COLORREF OldColor;
201 PDC dc;
202 if (!(dc = DC_LockDc(hdc)))
203 {
204 EngSetLastError(ERROR_INVALID_PARAMETER);
205 return CLR_INVALID;
206 }
207
208 OldColor = (COLORREF)dc->pdcattr->ulPenClr;
209 dc->pdcattr->ulPenClr = (ULONG)crColor;
210
211 if (dc->pdcattr->crPenClr != crColor)
212 {
213 dc->pdcattr->ulDirty_ |= DIRTY_LINE;
214 dc->pdcattr->crPenClr = crColor;
215 }
216 DC_UnlockDc(dc);
217 return OldColor;
218 }
219
220 int
221 FASTCALL
222 GreSetStretchBltMode(HDC hDC, int iStretchMode)
223 {
224 PDC pdc;
225 PDC_ATTR pdcattr;
226 INT oSMode = 0;
227
228 pdc = DC_LockDc(hDC);
229 if (pdc)
230 {
231 pdcattr = pdc->pdcattr;
232 oSMode = pdcattr->lStretchBltMode;
233 pdcattr->lStretchBltMode = iStretchMode;
234
235 // Wine returns an error here. We set the default.
236 if ((iStretchMode <= 0) || (iStretchMode > MAXSTRETCHBLTMODE)) iStretchMode = WHITEONBLACK;
237
238 pdcattr->jStretchBltMode = iStretchMode;
239 }
240 DC_UnlockDc(pdc);
241 return oSMode;
242 }
243
244 VOID
245 FASTCALL
246 DCU_SetDcUndeletable(HDC hDC)
247 {
248 PDC dc = DC_LockDc(hDC);
249 if (!dc)
250 {
251 EngSetLastError(ERROR_INVALID_HANDLE);
252 return;
253 }
254
255 dc->fs |= DC_FLAG_PERMANENT;
256 DC_UnlockDc(dc);
257 return;
258 }
259
260 #if 0
261 BOOL FASTCALL
262 IntIsPrimarySurface(SURFOBJ *SurfObj)
263 {
264 if (PrimarySurface.pSurface == NULL)
265 {
266 return FALSE;
267 }
268 return SurfObj->hsurf == PrimarySurface.pSurface; // <- FIXME: WTF?
269 }
270 #endif
271
272 BOOL
273 FASTCALL
274 IntSetDefaultRegion(PDC pdc)
275 {
276 PSURFACE pSurface;
277 PROSRGNDATA prgn;
278 RECTL rclWnd, rclClip;
279
280 IntGdiReleaseRaoRgn(pdc);
281
282 rclWnd.left = 0;
283 rclWnd.top = 0;
284 rclWnd.right = pdc->dclevel.sizl.cx;
285 rclWnd.bottom = pdc->dclevel.sizl.cy;
286 rclClip = rclWnd;
287
288 //EngAcquireSemaphoreShared(pdc->ppdev->hsemDevLock);
289 if (pdc->ppdev->flFlags & PDEV_META_DEVICE)
290 {
291 pSurface = pdc->dclevel.pSurface;
292 if (pSurface && pSurface->flags & PDEV_SURFACE)
293 {
294 rclClip.left += pdc->ppdev->ptlOrigion.x;
295 rclClip.top += pdc->ppdev->ptlOrigion.y;
296 rclClip.right += pdc->ppdev->ptlOrigion.x;
297 rclClip.bottom += pdc->ppdev->ptlOrigion.y;
298 }
299 }
300 //EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
301
302 prgn = pdc->prgnVis;
303
304 if (prgn && prgn != prgnDefault)
305 {
306 REGION_SetRectRgn( prgn,
307 rclClip.left,
308 rclClip.top,
309 rclClip.right ,
310 rclClip.bottom );
311 }
312 else
313 {
314 prgn = IntSysCreateRectpRgn( rclClip.left,
315 rclClip.top,
316 rclClip.right ,
317 rclClip.bottom );
318 pdc->prgnVis = prgn;
319 }
320
321 if (prgn)
322 {
323 pdc->ptlDCOrig.x = 0;
324 pdc->ptlDCOrig.y = 0;
325 pdc->erclWindow = rclWnd;
326 pdc->erclClip = rclClip;
327 /* Might be an InitDC or DCE... */
328 pdc->ptlFillOrigin.x = pdc->dcattr.VisRectRegion.Rect.right;
329 pdc->ptlFillOrigin.y = pdc->dcattr.VisRectRegion.Rect.bottom;
330 return TRUE;
331 }
332
333 pdc->prgnVis = prgnDefault;
334 return FALSE;
335 }
336
337
338 BOOL APIENTRY
339 NtGdiCancelDC(HDC hDC)
340 {
341 UNIMPLEMENTED;
342 return FALSE;
343 }
344
345
346 WORD APIENTRY
347 IntGdiSetHookFlags(HDC hDC, WORD Flags)
348 {
349 WORD wRet;
350 DC *dc = DC_LockDc(hDC);
351
352 if (NULL == dc)
353 {
354 EngSetLastError(ERROR_INVALID_HANDLE);
355 return 0;
356 }
357
358 wRet = dc->fs & DC_FLAG_DIRTY_RAO; // FIXME: Wrong flag!
359
360 /* Info in "Undocumented Windows" is slightly confusing. */
361 DPRINT("DC %p, Flags %04x\n", hDC, Flags);
362
363 if (Flags & DCHF_INVALIDATEVISRGN)
364 {
365 /* hVisRgn has to be updated */
366 dc->fs |= DC_FLAG_DIRTY_RAO;
367 }
368 else if (Flags & DCHF_VALIDATEVISRGN || 0 == Flags)
369 {
370 dc->fs &= ~DC_FLAG_DIRTY_RAO;
371 }
372
373 DC_UnlockDc(dc);
374
375 return wRet;
376 }
377
378
379 BOOL
380 APIENTRY
381 NtGdiGetDCDword(
382 HDC hDC,
383 UINT u,
384 DWORD *Result)
385 {
386 BOOL Ret = TRUE;
387 PDC pdc;
388 PDC_ATTR pdcattr;
389
390 DWORD SafeResult = 0;
391 NTSTATUS Status = STATUS_SUCCESS;
392
393 if (!Result)
394 {
395 EngSetLastError(ERROR_INVALID_PARAMETER);
396 return FALSE;
397 }
398
399 pdc = DC_LockDc(hDC);
400 if (!pdc)
401 {
402 EngSetLastError(ERROR_INVALID_HANDLE);
403 return FALSE;
404 }
405 pdcattr = pdc->pdcattr;
406
407 switch (u)
408 {
409 case GdiGetJournal:
410 break;
411
412 case GdiGetRelAbs:
413 SafeResult = pdcattr->lRelAbs;
414 break;
415
416 case GdiGetBreakExtra:
417 SafeResult = pdcattr->lBreakExtra;
418 break;
419
420 case GdiGerCharBreak:
421 SafeResult = pdcattr->cBreak;
422 break;
423
424 case GdiGetArcDirection:
425 if (pdcattr->dwLayout & LAYOUT_RTL)
426 SafeResult = AD_CLOCKWISE - ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0);
427 else
428 SafeResult = ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0) + AD_COUNTERCLOCKWISE;
429 break;
430
431 case GdiGetEMFRestorDc:
432 break;
433
434 case GdiGetFontLanguageInfo:
435 SafeResult = IntGetFontLanguageInfo(pdc);
436 break;
437
438 case GdiGetIsMemDc:
439 SafeResult = pdc->dctype;
440 break;
441
442 case GdiGetMapMode:
443 SafeResult = pdcattr->iMapMode;
444 break;
445
446 case GdiGetTextCharExtra:
447 SafeResult = pdcattr->lTextExtra;
448 break;
449
450 default:
451 EngSetLastError(ERROR_INVALID_PARAMETER);
452 Ret = FALSE;
453 break;
454 }
455
456 if (Ret)
457 {
458 _SEH2_TRY
459 {
460 ProbeForWrite(Result, sizeof(DWORD), 1);
461 *Result = SafeResult;
462 }
463 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
464 {
465 Status = _SEH2_GetExceptionCode();
466 }
467 _SEH2_END;
468
469 if (!NT_SUCCESS(Status))
470 {
471 SetLastNtError(Status);
472 Ret = FALSE;
473 }
474 }
475
476 DC_UnlockDc(pdc);
477 return Ret;
478 }
479
480 _Success_(return != FALSE)
481 BOOL
482 APIENTRY
483 NtGdiGetAndSetDCDword(
484 _In_ HDC hdc,
485 _In_ UINT u,
486 _In_ DWORD dwIn,
487 _Out_ DWORD *pdwResult)
488 {
489 BOOL Ret = TRUE;
490 PDC pdc;
491 PDC_ATTR pdcattr;
492
493 DWORD SafeResult = 0;
494 NTSTATUS Status = STATUS_SUCCESS;
495
496 if (!pdwResult)
497 {
498 EngSetLastError(ERROR_INVALID_PARAMETER);
499 return FALSE;
500 }
501
502 pdc = DC_LockDc(hdc);
503 if (!pdc)
504 {
505 EngSetLastError(ERROR_INVALID_HANDLE);
506 return FALSE;
507 }
508 pdcattr = pdc->pdcattr;
509
510 switch (u)
511 {
512 case GdiGetSetCopyCount:
513 SafeResult = pdc->ulCopyCount;
514 pdc->ulCopyCount = dwIn;
515 break;
516
517 case GdiGetSetTextAlign:
518 SafeResult = pdcattr->lTextAlign;
519 pdcattr->lTextAlign = dwIn;
520 // pdcattr->flTextAlign = dwIn; // Flags!
521 break;
522
523 case GdiGetSetRelAbs:
524 SafeResult = pdcattr->lRelAbs;
525 pdcattr->lRelAbs = dwIn;
526 break;
527
528 case GdiGetSetTextCharExtra:
529 SafeResult = pdcattr->lTextExtra;
530 pdcattr->lTextExtra = dwIn;
531 break;
532
533 case GdiGetSetSelectFont:
534 break;
535
536 case GdiGetSetMapperFlagsInternal:
537 if (dwIn & ~1)
538 {
539 EngSetLastError(ERROR_INVALID_PARAMETER);
540 Ret = FALSE;
541 break;
542 }
543 SafeResult = pdcattr->flFontMapper;
544 pdcattr->flFontMapper = dwIn;
545 break;
546
547 case GdiGetSetMapMode:
548 SafeResult = IntGdiSetMapMode(pdc, dwIn);
549 break;
550
551 case GdiGetSetArcDirection:
552 if (dwIn != AD_COUNTERCLOCKWISE && dwIn != AD_CLOCKWISE)
553 {
554 EngSetLastError(ERROR_INVALID_PARAMETER);
555 Ret = FALSE;
556 break;
557 }
558 if (pdcattr->dwLayout & LAYOUT_RTL) // Right to Left
559 {
560 SafeResult = AD_CLOCKWISE - ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0);
561 if (dwIn == AD_CLOCKWISE)
562 {
563 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
564 break;
565 }
566 pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
567 }
568 else // Left to Right
569 {
570 SafeResult = ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0) +
571 AD_COUNTERCLOCKWISE;
572 if (dwIn == AD_COUNTERCLOCKWISE)
573 {
574 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
575 break;
576 }
577 pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
578 }
579 break;
580
581 default:
582 EngSetLastError(ERROR_INVALID_PARAMETER);
583 Ret = FALSE;
584 break;
585 }
586
587 if (Ret)
588 {
589 _SEH2_TRY
590 {
591 ProbeForWrite(pdwResult, sizeof(DWORD), 1);
592 *pdwResult = SafeResult;
593 }
594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
595 {
596 Status = _SEH2_GetExceptionCode();
597 }
598 _SEH2_END;
599
600 if (!NT_SUCCESS(Status))
601 {
602 SetLastNtError(Status);
603 Ret = FALSE;
604 }
605 }
606
607 DC_UnlockDc(pdc);
608 return Ret;
609 }
610
611 DWORD
612 APIENTRY
613 NtGdiGetBoundsRect(
614 IN HDC hdc,
615 OUT LPRECT prc,
616 IN DWORD flags)
617 {
618 DWORD ret;
619 PDC pdc;
620
621 /* Lock the DC */
622 if (!(pdc = DC_LockDc(hdc))) return 0;
623
624 /* Get the return value */
625 ret = pdc->fs & DC_ACCUM_APP ? DCB_ENABLE : DCB_DISABLE;
626 ret |= RECTL_bIsEmptyRect(&pdc->erclBoundsApp) ? DCB_RESET : DCB_SET;
627
628 /* Copy the rect to the caller */
629 _SEH2_TRY
630 {
631 ProbeForWrite(prc, sizeof(RECT), 1);
632 *prc = pdc->erclBoundsApp;
633 }
634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
635 {
636 ret = 0;
637 }
638 _SEH2_END;
639
640 if (flags & DCB_RESET)
641 {
642 RECTL_vSetEmptyRect(&pdc->erclBoundsApp);
643 }
644
645 DC_UnlockDc(pdc);
646 return ret;
647 }
648
649
650 DWORD
651 APIENTRY
652 NtGdiSetBoundsRect(
653 IN HDC hdc,
654 IN LPRECT prc,
655 IN DWORD flags)
656 {
657 DWORD ret;
658 PDC pdc;
659 RECTL rcl;
660
661 /* Verify arguments */
662 if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
663
664 /* Lock the DC */
665 if (!(pdc = DC_LockDc(hdc))) return 0;
666
667 /* Get the return value */
668 ret = pdc->fs & DC_ACCUM_APP ? DCB_ENABLE : DCB_DISABLE;
669 ret |= RECTL_bIsEmptyRect(&pdc->erclBoundsApp) ? DCB_RESET : DCB_SET;
670
671 if (flags & DCB_RESET)
672 {
673 RECTL_vSetEmptyRect(&pdc->erclBoundsApp);
674 }
675
676 if (flags & DCB_ACCUMULATE)
677 {
678 /* Capture the rect */
679 _SEH2_TRY
680 {
681 ProbeForRead(prc, sizeof(RECT), 1);
682 rcl = *prc;
683 }
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
685 {
686 DC_UnlockDc(pdc);
687 _SEH2_YIELD(return 0;)
688 }
689 _SEH2_END;
690
691 RECTL_vMakeWellOrdered(&rcl);
692 RECTL_bUnionRect(&pdc->erclBoundsApp, &pdc->erclBoundsApp, &rcl);
693 }
694
695 if (flags & DCB_ENABLE) pdc->fs |= DC_ACCUM_APP;
696 if (flags & DCB_DISABLE) pdc->fs &= ~DC_ACCUM_APP;
697 DC_UnlockDc(pdc);
698 return ret;
699 }
700
701 /* Translates a COLORREF to the right color in the specified DC color space */
702 ULONG
703 TranslateCOLORREF(PDC pdc, COLORREF crColor)
704 {
705 PSURFACE psurfDC;
706 PPALETTE ppalDC;
707 ULONG index, ulColor, iBitmapFormat;
708 EXLATEOBJ exlo;
709
710 /* Get the DC surface */
711 psurfDC = pdc->dclevel.pSurface;
712
713 /* If no surface is selected, use the default bitmap */
714 if (!psurfDC)
715 psurfDC = psurfDefaultBitmap;
716
717 /* Check what color type this is */
718 switch (crColor >> 24)
719 {
720 case 0x00: /* RGB color */
721 break;
722
723 case 0x01: /* PALETTEINDEX */
724 index = crColor & 0xFFFFFF;
725 ppalDC = pdc->dclevel.ppal;
726 if (index >= ppalDC->NumColors) index = 0;
727
728 /* Get the RGB value */
729 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, index);
730 break;
731
732 case 0x02: /* PALETTERGB */
733
734 if (pdc->dclevel.hpal != StockObjects[DEFAULT_PALETTE])
735 {
736 /* First find the nearest index in the dc palette */
737 ppalDC = pdc->dclevel.ppal;
738 index = PALETTE_ulGetNearestIndex(ppalDC, crColor & 0xFFFFFF);
739
740 /* Get the RGB value */
741 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, index);
742 }
743 else
744 {
745 /* Use the pure color */
746 crColor = crColor & 0x00FFFFFF;
747 }
748 break;
749
750 case 0x10: /* DIBINDEX */
751 /* Mask the value to match the target bpp */
752 iBitmapFormat = psurfDC->SurfObj.iBitmapFormat;
753 if (iBitmapFormat == BMF_1BPP) index = crColor & 0x1;
754 else if (iBitmapFormat == BMF_4BPP) index = crColor & 0xf;
755 else if (iBitmapFormat == BMF_8BPP) index = crColor & 0xFF;
756 else if (iBitmapFormat == BMF_16BPP) index = crColor & 0xFFFF;
757 else index = crColor & 0xFFFFFF;
758 return index;
759
760 default:
761 DPRINT("Unsupported color type %u passed\n", crColor >> 24);
762 crColor &= 0xFFFFFF;
763 }
764
765 /* Initialize an XLATEOBJ from RGB to the target surface */
766 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurfDC->ppal, 0xFFFFFF, 0, 0);
767
768 /* Translate the color to the target format */
769 ulColor = XLATEOBJ_iXlate(&exlo.xlo, crColor);
770
771 /* Cleanup the XLATEOBJ */
772 EXLATEOBJ_vCleanup(&exlo);
773
774 return ulColor;
775 }
776
777