Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45727 Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/comctl32/button.c | 421 +++++++++++++++++++++++++++++------------ 1 file changed, 295 insertions(+), 126 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index 6f9bc39de5..653586a748 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -98,7 +98,7 @@ typedef struct _BUTTON_INFO } u; } BUTTON_INFO;
-static UINT BUTTON_CalcLabelRect( const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc ); +static UINT BUTTON_CalcLayoutRects( const BUTTON_INFO *infoPtr, HDC hdc, RECT *labelRc, RECT *imageRc, RECT *textRc ); static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); @@ -615,7 +615,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L /* FIXME: check other BS_* handlers */ if (btn_type == BS_GROUPBOX) InflateRect(&rc, -7, 1); /* GB_Paint does this */ - BUTTON_CalcLabelRect(infoPtr, hdc, &rc); + BUTTON_CalcLayoutRects(infoPtr, hdc, &rc, NULL, NULL); /* Clip by client rect bounds */ if (rc.right > client.right) rc.right = client.right; if (rc.bottom > client.bottom) rc.bottom = client.bottom; @@ -855,95 +855,257 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L return 0; }
+/* If maxWidth is zero, rectangle width is unlimited */ +static RECT BUTTON_GetTextRect(const BUTTON_INFO *infoPtr, HDC hdc, const WCHAR *text, LONG maxWidth) +{ + LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + LONG exStyle = GetWindowLongW(infoPtr->hwnd, GWL_EXSTYLE); + UINT dtStyle = BUTTON_BStoDT(style, exStyle); + HFONT hPrevFont; + RECT rect = {0}; + + rect.right = maxWidth; + hPrevFont = SelectObject(hdc, infoPtr->font); + /* Calculate height without DT_VCENTER and DT_BOTTOM to get the correct height */ + DrawTextW(hdc, text, -1, &rect, (dtStyle & ~(DT_VCENTER | DT_BOTTOM)) | DT_CALCRECT); + if (hPrevFont) SelectObject(hdc, hPrevFont); + + return rect; +} + +static BOOL show_image_only(const BUTTON_INFO *infoPtr) +{ + LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + return (style & (BS_ICON | BS_BITMAP)) && infoPtr->u.image; +} + +static BOOL show_image_and_text(const BUTTON_INFO *infoPtr) +{ + LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + UINT type = get_button_type(style); + return !(style & (BS_ICON | BS_BITMAP)) && infoPtr->u.image + && (type == BS_PUSHBUTTON || type == BS_DEFPUSHBUTTON || type == BS_USERBUTTON || type == BS_SPLITBUTTON + || type == BS_DEFSPLITBUTTON || type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK); +} + +static BOOL show_image(const BUTTON_INFO *infoPtr) +{ + return show_image_only(infoPtr) || show_image_and_text(infoPtr); +} + +/* Get a bounding rectangle that is large enough to contain a image and a text side by side. + * Note: (left,top) of the result rectangle may not be (0,0), offset it by yourself if needed */ +static RECT BUTTON_GetBoundingLabelRect(LONG style, const RECT *textRect, const RECT *imageRect) +{ + RECT labelRect; + RECT rect = *imageRect; + INT textWidth = textRect->right - textRect->left; + INT textHeight = textRect->bottom - textRect->top; + INT imageWidth = imageRect->right - imageRect->left; + INT imageHeight = imageRect->bottom - imageRect->top; + + if ((style & BS_CENTER) == BS_RIGHT) + OffsetRect(&rect, textWidth, 0); + else if ((style & BS_CENTER) == BS_LEFT) + OffsetRect(&rect, -imageWidth, 0); + else if ((style & BS_VCENTER) == BS_BOTTOM) + OffsetRect(&rect, 0, textHeight); + else if ((style & BS_VCENTER) == BS_TOP) + OffsetRect(&rect, 0, -imageHeight); + else + OffsetRect(&rect, -imageWidth, 0); + + UnionRect(&labelRect, textRect, &rect); + return labelRect; +} + +/* Position a rectangle inside a bounding rectangle according to button alignment flags */ +static void BUTTON_PositionRect(LONG style, const RECT *outerRect, RECT *innerRect, const RECT *margin) +{ + INT width = innerRect->right - innerRect->left; + INT height = innerRect->bottom - innerRect->top; + + if ((style & WS_EX_RIGHT) && !(style & BS_CENTER)) style |= BS_CENTER; + + if (!(style & BS_CENTER)) + { + /* Push button's text is centered by default, all other types have left aligned text */ + if (get_button_type(style) <= BS_DEFPUSHBUTTON) + style |= BS_CENTER; + else + style |= BS_LEFT; + } + + if (!(style & BS_VCENTER)) + { + /* Group box's text is top aligned by default */ + if (get_button_type(style) == BS_GROUPBOX) + style |= BS_TOP; + } + + switch (style & BS_CENTER) + { + case BS_CENTER: + innerRect->left = outerRect->left + (outerRect->right - outerRect->left - width) / 2; + innerRect->right = innerRect->left + width; + break; + case BS_RIGHT: + innerRect->right = outerRect->right - margin->right; + innerRect->left = innerRect->right - width; + break; + case BS_LEFT: + default: + innerRect->left = outerRect->left + margin->left; + innerRect->right = innerRect->left + width; + break; + } + + switch (style & BS_VCENTER) + { + case BS_TOP: + innerRect->top = outerRect->top + margin->top; + innerRect->bottom = innerRect->top + height; + break; + case BS_BOTTOM: + innerRect->bottom = outerRect->bottom - margin->bottom; + innerRect->top = innerRect->bottom - height; + break; + case BS_VCENTER: + default: + innerRect->top = outerRect->top + (outerRect->bottom - outerRect->top - height) / 2; + innerRect->bottom = innerRect->top + height; + break; + } +} + +static SIZE BUTTON_GetImageSize(const BUTTON_INFO *infoPtr) +{ + ICONINFO iconInfo; + BITMAP bm = {0}; + SIZE size = {0}; + + if (infoPtr->u.image) + { + if (infoPtr->image_type == IMAGE_ICON) + { + GetIconInfo(infoPtr->u.icon, &iconInfo); + GetObjectW(iconInfo.hbmColor, sizeof(bm), &bm); + DeleteObject(iconInfo.hbmColor); + DeleteObject(iconInfo.hbmMask); + } + else if (infoPtr->image_type == IMAGE_BITMAP) + GetObjectW(infoPtr->u.bitmap, sizeof(bm), &bm); + + size.cx = bm.bmWidth; + size.cy = bm.bmHeight; + } + + return size; +} + /********************************************************************** - * BUTTON_CalcLabelRect + * BUTTON_CalcLayoutRects * - * Calculates label's rectangle depending on button style. + * Calculates the rectangles of the button label(image and text) and its parts depending on a button's style. * * Returns flags to be passed to DrawText. * Calculated rectangle doesn't take into account button state * (pushed, etc.). If there is nothing to draw (no text/image) output * rectangle is empty, and return value is (UINT)-1. + * + * PARAMS: + * infoPtr [I] Button pointer + * hdc [I] Handle to device context to draw to + * labelRc [I/O] Input the rect the label to be positioned in, and output the label rect + * imageRc [O] Optional, output the image rect + * textRc [O] Optional, output the text rect */ -static UINT BUTTON_CalcLabelRect(const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc) +static UINT BUTTON_CalcLayoutRects(const BUTTON_INFO *infoPtr, HDC hdc, RECT *labelRc, RECT *imageRc, RECT *textRc) { LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE ); LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE ); WCHAR *text = get_button_text(infoPtr); - ICONINFO iconInfo; - BITMAP bm = { 0 }; - UINT dtStyle = BUTTON_BStoDT( style, ex_style ); - RECT r = *rc; - INT n; + SIZE imageSize = BUTTON_GetImageSize(infoPtr); + UINT dtStyle = BUTTON_BStoDT(style, ex_style); + RECT labelRect, imageRect, textRect; + RECT emptyMargin = {0}, oneMargin = {1, 1, 1, 1}; + LONG maxTextWidth;
/* Calculate label rectangle according to label type */ - /* FIXME: Doesn't support showing both image and text yet */ - if (infoPtr->u.image) - { - if (infoPtr->image_type == IMAGE_ICON) - { - GetIconInfo(infoPtr->u.icon, &iconInfo); - GetObjectW(iconInfo.hbmColor, sizeof(bm), &bm); - DeleteObject(iconInfo.hbmColor); - DeleteObject(iconInfo.hbmMask); - } - else if (infoPtr->image_type == IMAGE_BITMAP) - { - GetObjectW(infoPtr->u.bitmap, sizeof(bm), &bm); - } - - r.right = r.left + bm.bmWidth; - r.bottom = r.top + bm.bmHeight; - } - else if (text && text[0]) + if ((imageSize.cx == 0 && imageSize.cy == 0) && (text == NULL || text[0] == '\0')) { - HFONT hFont, hPrevFont = 0; - - if ((hFont = infoPtr->font)) hPrevFont = SelectObject(hdc, hFont); - DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT); - if (hPrevFont) SelectObject(hdc, hPrevFont); - } - - if ((infoPtr->u.image && bm.bmWidth == 0 && bm.bmHeight == 0) - || (text == NULL || text[0] == '\0')) - { - rc->right = r.left; - rc->bottom = r.top; + SetRectEmpty(labelRc); + SetRectEmpty(imageRc); + SetRectEmpty(textRc); heap_free(text); return (UINT)-1; } - heap_free(text);
- /* Position label inside bounding rectangle according to - * alignment flags. (calculated rect is always left-top aligned). - * If label is aligned to any side - shift label in opposite - * direction to leave extra space for focus rectangle. - */ - switch (dtStyle & (DT_CENTER|DT_RIGHT)) + SetRect(&imageRect, 0, 0, imageSize.cx, imageSize.cy); + + /* Show image only */ + if (show_image_only(infoPtr)) { - case DT_LEFT: r.left++; r.right++; break; - case DT_CENTER: n = r.right - r.left; - r.left = rc->left + ((rc->right - rc->left) - n) / 2; - r.right = r.left + n; break; - case DT_RIGHT: n = r.right - r.left; - r.right = rc->right - 1; - r.left = r.right - n; - break; + BUTTON_PositionRect(style, labelRc, &imageRect, + infoPtr->imagelist.himl ? &infoPtr->imagelist.margin : &emptyMargin); + labelRect = imageRect; + SetRectEmpty(&textRect); } - - switch (dtStyle & (DT_VCENTER|DT_BOTTOM)) + else { - case DT_TOP: r.top++; r.bottom++; break; - case DT_VCENTER: n = r.bottom - r.top; - r.top = rc->top + ((rc->bottom - rc->top) - n) / 2; - r.bottom = r.top + n; break; - case DT_BOTTOM: n = r.bottom - r.top; - r.bottom = rc->bottom - 1; - r.top = r.bottom - n; - break; + /* Get text rect */ + maxTextWidth = labelRc->right - labelRc->left; + textRect = BUTTON_GetTextRect(infoPtr, hdc, text, maxTextWidth); + heap_free(text); + + /* Show image and text */ + if (show_image_and_text(infoPtr)) + { + RECT boundingLabelRect, boundingImageRect, boundingTextRect; + + /* Get label rect */ + /* Get a label bounding rect to position the label in the user specified label rect because text and + * image need to align together. */ + boundingLabelRect = BUTTON_GetBoundingLabelRect(style, &textRect, &imageRect); + BUTTON_PositionRect(style, labelRc, &boundingLabelRect, &emptyMargin); + labelRect = boundingLabelRect; + + /* Get image rect */ + /* Split the label rect to two halves as two bounding rects for image and text */ + boundingImageRect = labelRect; + if ((style & BS_CENTER) == BS_RIGHT) + boundingImageRect.left = boundingImageRect.right - imageSize.cx; + else if ((style & BS_CENTER) == BS_LEFT) + boundingImageRect.right = boundingImageRect.left + imageSize.cx; + else if ((style & BS_VCENTER) == BS_BOTTOM) + boundingImageRect.top = boundingImageRect.bottom - imageSize.cy; + else if ((style & BS_VCENTER) == BS_TOP) + boundingImageRect.bottom = boundingImageRect.top + imageSize.cy; + else + boundingImageRect.right = boundingImageRect.left + imageSize.cx; + BUTTON_PositionRect(style, &boundingImageRect, &imageRect, &emptyMargin); + + /* Get text rect */ + SubtractRect(&boundingTextRect, &labelRect, &boundingImageRect); + BUTTON_PositionRect(style, &boundingTextRect, &textRect, &oneMargin); + } + /* Show text only */ + else + { + if (get_button_type(style) != BS_GROUPBOX) + BUTTON_PositionRect(style, labelRc, &textRect, &oneMargin); + else + /* GroupBox is always top aligned */ + BUTTON_PositionRect((style & ~BS_VCENTER) | BS_TOP, labelRc, &textRect, &oneMargin); + labelRect = textRect; + SetRectEmpty(&imageRect); + } }
- *rc = r; + CopyRect(labelRc, &labelRect); + CopyRect(imageRc, &imageRect); + CopyRect(textRc, &textRect); + return dtStyle; }
@@ -962,19 +1124,25 @@ static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int return TRUE; }
- /********************************************************************** * BUTTON_DrawLabel * * Common function for drawing button label. + * + * FIXME: + * 1. When BS_SINGLELINE is specified and text contains '\t', '\n' or '\r' in the middle, they are rendered as + * squares now whereas they should be ignored. + * 2. When BS_MULTILINE is specified and text contains space in the middle, the space mistakenly be rendered as newline. */ -static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const RECT *rc) +static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const RECT *imageRect, + const RECT *textRect) { DRAWSTATEPROC lpOutputProc = NULL; LPARAM lp; WPARAM wp = 0; HBRUSH hbr = 0; UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED; + UINT imageFlags; LONG state = infoPtr->state; LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE ); WCHAR *text = NULL; @@ -990,35 +1158,34 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, flags |= DSS_MONO; }
- /* FIXME: Support drawing label with both image and text */ - if (infoPtr->u.image != 0) + switch (infoPtr->image_type) { - switch (infoPtr->image_type) - { - case IMAGE_ICON: - flags |= DST_ICON; - lp = (LPARAM)infoPtr->u.icon; - break; - case IMAGE_BITMAP: - flags |= DST_BITMAP; - lp = (LPARAM)infoPtr->u.bitmap; - break; - default: - return; - } - } - else - { - /* DST_COMPLEX -- is 0 */ - lpOutputProc = BUTTON_DrawTextCallback; - if (!(text = get_button_text(infoPtr))) return; - lp = (LPARAM)text; - wp = dtFlags; + case IMAGE_ICON: + imageFlags = flags | DST_ICON; + lp = (LPARAM)infoPtr->u.icon; + break; + case IMAGE_BITMAP: + imageFlags = flags | DST_BITMAP; + lp = (LPARAM)infoPtr->u.bitmap; + break; + default: + return; }
- DrawStateW(hdc, hbr, lpOutputProc, lp, wp, rc->left, rc->top, - rc->right - rc->left, rc->bottom - rc->top, flags); - heap_free( text ); + if (show_image(infoPtr)) + DrawStateW(hdc, hbr, lpOutputProc, lp, wp, imageRect->left, imageRect->top, + imageRect->right - imageRect->left, imageRect->bottom - imageRect->top, imageFlags); + + if (show_image_only(infoPtr)) return; + + /* DST_COMPLEX -- is 0 */ + lpOutputProc = BUTTON_DrawTextCallback; + if (!(text = get_button_text(infoPtr))) return; + lp = (LPARAM)text; + wp = dtFlags; + DrawStateW(hdc, hbr, lpOutputProc, lp, wp, textRect->left, textRect->top, textRect->right - textRect->left, + textRect->bottom - textRect->top, flags); + heap_free(text); }
/********************************************************************** @@ -1026,7 +1193,7 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, */ static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) { - RECT rc, r; + RECT rc, labelRect, imageRect, textRect; UINT dtFlags, uState; HPEN hOldPen, hpen; HBRUSH hOldBrush; @@ -1082,18 +1249,17 @@ static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
/* draw button label */ - r = rc; - dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &r); + labelRect = rc; + dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
if (dtFlags == (UINT)-1L) goto cleanup;
- if (pushedState) - OffsetRect(&r, 1, 1); + if (pushedState) OffsetRect(&labelRect, 1, 1);
oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
- BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &r); + BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
SetTextColor( hDC, oldTxtColor );
@@ -1119,7 +1285,7 @@ draw_focus:
static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) { - RECT rbox, rtext, client; + RECT rbox, labelRect, imageRect, textRect, client; HBRUSH hBrush; int delta, text_offset, checkBoxWidth, checkBoxHeight; UINT dtFlags; @@ -1137,7 +1303,7 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) }
GetClientRect(infoPtr->hwnd, &client); - rbox = rtext = client; + rbox = labelRect = client;
checkBoxWidth = 12 * GetDpiForWindow( infoPtr->hwnd ) / 96 + 1; checkBoxHeight = 12 * GetDpiForWindow( infoPtr->hwnd ) / 96 + 1; @@ -1155,12 +1321,12 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
if (style & BS_LEFTTEXT || ex_style & WS_EX_RIGHT) { - rtext.right -= checkBoxWidth + text_offset; + labelRect.right -= checkBoxWidth + text_offset; rbox.left = rbox.right - checkBoxWidth; } else { - rtext.left += checkBoxWidth + text_offset; + labelRect.left += checkBoxWidth + text_offset; rbox.right = checkBoxWidth; }
@@ -1169,14 +1335,14 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) if (action == ODA_DRAWENTIRE) FillRect( hDC, &client, hBrush );
/* Draw label */ - client = rtext; - dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rtext); + client = labelRect; + dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
/* Only adjust rbox when rtext is valid */ if (dtFlags != (UINT)-1L) { - rbox.top = rtext.top; - rbox.bottom = rtext.bottom; + rbox.top = labelRect.top; + rbox.bottom = labelRect.bottom; }
/* Draw the check-box bitmap */ @@ -1229,16 +1395,15 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) if (dtFlags == (UINT)-1L) /* Noting to draw */ return;
- if (action == ODA_DRAWENTIRE) - BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rtext); + if (action == ODA_DRAWENTIRE) BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
/* ... and focus */ if (action == ODA_FOCUS || (state & BST_FOCUS)) { - rtext.left--; - rtext.right++; - IntersectRect(&rtext, &rtext, &client); - DrawFocusRect( hDC, &rtext ); + labelRect.left--; + labelRect.right++; + IntersectRect(&labelRect, &labelRect, &client); + DrawFocusRect(hDC, &labelRect); } SelectClipRgn( hDC, hrgn ); if (hrgn) DeleteObject( hrgn ); @@ -1274,7 +1439,7 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) { - RECT rc, rcFrame; + RECT labelRect, imageRect, textRect, rcFrame; HBRUSH hbr; HFONT hFont; UINT dtFlags; @@ -1290,16 +1455,16 @@ static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd); if (!hbr) /* did the app forget to call defwindowproc ? */ hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd); - GetClientRect( infoPtr->hwnd, &rc); - rcFrame = rc; - hrgn = set_control_clipping( hDC, &rc ); + GetClientRect(infoPtr->hwnd, &labelRect); + rcFrame = labelRect; + hrgn = set_control_clipping(hDC, &labelRect);
GetTextMetricsW (hDC, &tm); rcFrame.top += (tm.tmHeight / 2) - 1; DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT | ((style & BS_FLAT) ? BF_FLAT : 0));
- InflateRect(&rc, -7, 1); - dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rc); + InflateRect(&labelRect, -7, 1); + dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
if (dtFlags != (UINT)-1) { @@ -1309,11 +1474,15 @@ static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) */
/* There is 1-pixel margin at the left, right, and bottom */ - rc.left--; rc.right++; rc.bottom++; - FillRect(hDC, &rc, hbr); - rc.left++; rc.right--; rc.bottom--; - - BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rc); + labelRect.left--; + labelRect.right++; + labelRect.bottom++; + FillRect(hDC, &labelRect, hbr); + labelRect.left++; + labelRect.right--; + labelRect.bottom--; + + BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect); } SelectClipRgn( hDC, hrgn ); if (hrgn) DeleteObject( hrgn );