reactos/win32ss/user/user32/windows/nonclient.c
Hermès Bélusca-Maïto b819608ed8 Create a branch for console restructuration work.
svn path=/branches/condrv_restructure/; revision=63104
2014-05-02 14:13:40 +00:00

1388 lines
41 KiB
C

/*
* ReactOS User32 Library
* - Window non-client area management
*
* Copyright (C) 2003 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* INCLUDES *******************************************************************/
#include <user32.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32);
#define HAS_DLGFRAME(Style, ExStyle) \
(((ExStyle) & WS_EX_DLGMODALFRAME) || \
(((Style) & WS_DLGFRAME) && (!((Style) & (WS_THICKFRAME | WS_MINIMIZE)))))
#define HAS_THICKFRAME(Style, ExStyle) \
(((Style) & WS_THICKFRAME) && !((Style) & WS_MINIMIZE) && \
(!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
#define HAS_THINFRAME(Style, ExStyle) \
(((Style) & (WS_BORDER | WS_MINIMIZE)) || (!((Style) & (WS_CHILD | WS_POPUP))))
#define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \
((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
(WindowRect.right - WindowRect.left == ParentClientRect.right) && \
(WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
#ifndef STATE_SYSTEM_OFFSCREEN
#define STATE_SYSTEM_OFFSCREEN 0x00010000
#endif
/*
* FIXME: This should be moved to a header
*/
VOID
IntDrawScrollBar(HWND hWnd, HDC hDC, INT nBar);
DWORD
IntScrollHitTest(HWND hWnd, INT nBar, POINT pt, BOOL bDragging);
BOOL WINAPI GdiGradientFill(HDC,PTRIVERTEX,ULONG,PVOID,ULONG,ULONG);
extern ATOM AtomInternalPos;
/* PRIVATE FUNCTIONS **********************************************************/
BOOL
IntIsScrollBarVisible(HWND hWnd, INT hBar)
{
SCROLLBARINFO sbi;
sbi.cbSize = sizeof(SCROLLBARINFO);
if(!NtUserGetScrollBarInfo(hWnd, hBar, &sbi))
return FALSE;
return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
}
BOOL
UserHasWindowEdge(DWORD Style, DWORD ExStyle)
{
if (Style & WS_MINIMIZE)
return TRUE;
if (ExStyle & WS_EX_DLGMODALFRAME)
return TRUE;
if (ExStyle & WS_EX_STATICEDGE)
return FALSE;
if (Style & WS_THICKFRAME)
return TRUE;
Style &= WS_CAPTION;
if (Style == WS_DLGFRAME || Style == WS_CAPTION)
return TRUE;
return FALSE;
}
VOID
UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
{
DWORD Border = 0;
if (UserHasWindowEdge(Style, ExStyle))
Border += 2;
else if (ExStyle & WS_EX_STATICEDGE)
Border += 1;
if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
Border += 2;
if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
Border ++;
Size->cx = Size->cy = Border;
if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
{
Size->cx += GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
Size->cy += GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
}
Size->cx *= GetSystemMetrics(SM_CXBORDER);
Size->cy *= GetSystemMetrics(SM_CYBORDER);
}
BOOL
UserHasMenu(HWND hWnd, ULONG Style)
{
return (!(Style & WS_CHILD) && GetMenu(hWnd) != 0);
}
HICON
UserGetWindowIcon(HWND hwnd)
{
HICON hIcon = 0;
SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
if (!hIcon) hIcon = UserGetProp(hwnd, gpsi->atomIconSmProp);
if (!hIcon) hIcon = UserGetProp(hwnd, gpsi->atomIconProp);
if (!hIcon) hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
if (!hIcon) hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
{
if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size.
}
return hIcon;
}
BOOL
UserDrawSysMenuButton(HWND hWnd, HDC hDC, LPRECT Rect, BOOL Down)
{
HICON WindowIcon;
if ((WindowIcon = UserGetWindowIcon(hWnd)))
{
return DrawIconEx(hDC, Rect->left + 2, Rect->top + 2, WindowIcon,
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
0, NULL, DI_NORMAL);
}
return FALSE;
}
/*
* FIXME:
* - Cache bitmaps, then just bitblt instead of calling DFC() (and
* wasting precious CPU cycles) every time
* - Center the buttons verticaly in the rect
*/
VOID
UserDrawCaptionButton(HWND hWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
{
RECT TempRect;
if (!(Style & WS_SYSMENU))
{
return;
}
TempRect = *Rect;
switch (Type)
{
case DFCS_CAPTIONMIN:
{
if (ExStyle & WS_EX_TOOLWINDOW)
return; /* ToolWindows don't have min/max buttons */
if (Style & WS_SYSMENU)
TempRect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
TempRect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE) + 1;
TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
TempRect.top += 2;
TempRect.right -= 1;
DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
(bDown ? DFCS_PUSHED : 0) |
((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
break;
}
case DFCS_CAPTIONMAX:
{
if (ExStyle & WS_EX_TOOLWINDOW)
return; /* ToolWindows don't have min/max buttons */
if (Style & WS_SYSMENU)
TempRect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE) + 1;
TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
TempRect.top += 2;
TempRect.right -= 1;
DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
(bDown ? DFCS_PUSHED : 0) |
((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
break;
}
case DFCS_CAPTIONCLOSE:
{
HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
UINT MenuState = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
/* FIXME: A tool window has a smaller Close button */
if (ExStyle & WS_EX_TOOLWINDOW)
{
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSMSIZE);
TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSMSIZE) - 2;
}
else
{
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE);
TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
}
TempRect.top += 2;
TempRect.right -= 2;
DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
(DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) |
((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(GetClassLong(hWnd, GCL_STYLE) & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE)));
break;
}
}
}
VOID
UserDrawCaptionButtonWnd(HWND hWnd, HDC hDC, BOOL bDown, ULONG Type)
{
RECT WindowRect;
SIZE WindowBorder;
DWORD Style, ExStyle;
GetWindowRect(hWnd, &WindowRect);
WindowRect.right -= WindowRect.left;
WindowRect.bottom -= WindowRect.top;
WindowRect.left = WindowRect.top = 0;
Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
UserGetWindowBorders(Style, ExStyle, &WindowBorder, FALSE);
InflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
UserDrawCaptionButton(hWnd, &WindowRect, Style, ExStyle, hDC, bDown, Type);
}
// Note from Wine:
/* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
the call to GetDCEx implying that it is allowed not to use it either.
However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
will cause clipRgn to be deleted after ReleaseDC().
Now, how is the "system" supposed to tell what happened?
*/
/*
* FIXME:
* - Drawing of WS_BORDER after scrollbars
* - Correct drawing of size-box
*/
LRESULT
DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active)
{
HDC hDC;
DWORD Style, ExStyle;
HWND Parent;
RECT ClientRect, WindowRect, CurrentRect, TempRect;
if (!IsWindowVisible(hWnd))
return 0;
Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
if (hDC == 0)
{
return 0;
}
Parent = GetParent(hWnd);
ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
if (Active == -1)
{
if (ExStyle & WS_EX_MDICHILD)
{
Active = IsChild(GetForegroundWindow(), hWnd);
if (Active)
Active = (hWnd == (HWND)SendMessageW(Parent, WM_MDIGETACTIVE, 0, 0));
}
else
{
Active = (GetForegroundWindow() == hWnd);
}
}
GetWindowRect(hWnd, &WindowRect);
GetClientRect(hWnd, &ClientRect);
CurrentRect.top = CurrentRect.left = 0;
CurrentRect.right = WindowRect.right - WindowRect.left;
CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
/* Draw outer edge */
if (UserHasWindowEdge(Style, ExStyle))
{
DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
} else
if (ExStyle & WS_EX_STATICEDGE)
{
#if 0
DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
#else
SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW));
PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
PatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
SelectObject(hDC, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
InflateRect(&CurrentRect, -1, -1);
#endif
}
/* Firstly the "thick" frame */
if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
{
LONG Width =
(GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
GetSystemMetrics(SM_CXBORDER);
LONG Height =
(GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
GetSystemMetrics(SM_CYBORDER);
SelectObject(hDC, GetSysColorBrush(Active ? COLOR_ACTIVEBORDER :
COLOR_INACTIVEBORDER));
/* Draw frame */
PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
#ifdef __REACTOS__
PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
#else
PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
#endif
InflateRect(&CurrentRect, -Width, -Height);
}
/* Now the other bit of the frame */
if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
{
DWORD Width = GetSystemMetrics(SM_CXBORDER);
DWORD Height = GetSystemMetrics(SM_CYBORDER);
SelectObject(hDC, GetSysColorBrush(
(ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
(ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
(Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
COLOR_WINDOWFRAME));
/* Draw frame */
PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
#ifdef __REACTOS__
PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
#else
PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
#endif
InflateRect(&CurrentRect, -Width, -Height);
}
/* Draw caption */
if ((Style & WS_CAPTION) == WS_CAPTION)
{
DWORD CaptionFlags = DC_ICON | DC_TEXT | DC_BUTTONS;
HPEN PreviousPen;
BOOL Gradient = FALSE;
if(SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
{
CaptionFlags |= DC_GRADIENT;
}
TempRect = CurrentRect;
if (Active)
{
CaptionFlags |= DC_ACTIVE;
}
if (ExStyle & WS_EX_TOOLWINDOW)
{
CaptionFlags |= DC_SMALLCAP;
TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSMCAPTION) - 1;
CurrentRect.top += GetSystemMetrics(SM_CYSMCAPTION);
}
else
{
TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYCAPTION) - 1;
CurrentRect.top += GetSystemMetrics(SM_CYCAPTION);
}
NtUserDrawCaption(hWnd, hDC, &TempRect, CaptionFlags);
/* Draw buttons */
if (Style & WS_SYSMENU)
{
UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
{
UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
}
}
if(!(Style & WS_MINIMIZE))
{
/* Line under caption */
PreviousPen = SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, GetSysColor(
((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE |
WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
COLOR_WINDOWFRAME : COLOR_3DFACE));
MoveToEx(hDC, TempRect.left, TempRect.bottom, NULL);
LineTo(hDC, TempRect.right, TempRect.bottom);
SelectObject(hDC, PreviousPen);
}
}
if(!(Style & WS_MINIMIZE))
{
HMENU menu = GetMenu(hWnd);
/* Draw menu bar */
if (menu && !(Style & WS_CHILD))
{
TempRect = CurrentRect;
TempRect.bottom = TempRect.top + (UINT)NtUserxSetMenuBarHeight(menu, 0);
CurrentRect.top += MenuDrawMenuBar(hDC, &TempRect, hWnd, FALSE);
}
if (ExStyle & WS_EX_CLIENTEDGE)
{
DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
}
/* Draw the scrollbars */
if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
IntIsScrollBarVisible(hWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
{
RECT ParentClientRect;
TempRect = CurrentRect;
if (ExStyle & WS_EX_LEFTSCROLLBAR)
TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
else
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
FillRect(hDC, &TempRect, GetSysColorBrush(COLOR_BTNFACE));
/* FIXME: Correct drawing of size-box with WS_EX_LEFTSCROLLBAR */
if(Parent)
GetClientRect(Parent, &ParentClientRect);
if (HASSIZEGRIP(Style, ExStyle, GetWindowLongPtrW(Parent, GWL_STYLE), WindowRect, ParentClientRect))
{
DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
}
IntDrawScrollBar(hWnd, hDC, SB_VERT);
IntDrawScrollBar(hWnd, hDC, SB_HORZ);
}
else
{
if (Style & WS_VSCROLL && IntIsScrollBarVisible(hWnd, OBJID_VSCROLL))
IntDrawScrollBar(hWnd, hDC, SB_VERT);
else if (Style & WS_HSCROLL && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
IntDrawScrollBar(hWnd, hDC, SB_HORZ);
}
}
ReleaseDC(hWnd, hDC);
if (hRgn != HRGN_WINDOW)
DeleteObject(hRgn); // We use DCX_KEEPCLIPRGN
return 0; // For WM_NCPAINT message, return 0.
}
LRESULT
DefWndNCCalcSize(HWND hWnd, BOOL CalcSizeStruct, RECT *Rect)
{
LRESULT Result = 0;
DWORD Style = GetClassLongPtrW(hWnd, GCL_STYLE);
DWORD ExStyle;
SIZE WindowBorders;
RECT OrigRect;
if (Rect == NULL)
{
return Result;
}
OrigRect = *Rect;
if (CalcSizeStruct)
{
if (Style & CS_VREDRAW)
{
Result |= WVR_VREDRAW;
}
if (Style & CS_HREDRAW)
{
Result |= WVR_HREDRAW;
}
Result |= WVR_VALIDRECTS;
}
Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
if (!(Style & WS_MINIMIZE))
{
HMENU menu = GetMenu(hWnd);
if (UserHasWindowEdge(Style, ExStyle))
{
UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
InflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
} else
if ((ExStyle & WS_EX_STATICEDGE) || (Style & WS_BORDER))
{
InflateRect(Rect, -1, -1);
}
if ((Style & WS_CAPTION) == WS_CAPTION)
{
if (ExStyle & WS_EX_TOOLWINDOW)
Rect->top += GetSystemMetrics(SM_CYSMCAPTION);
else
Rect->top += GetSystemMetrics(SM_CYCAPTION);
}
if (menu && !(Style & WS_CHILD))
{
HDC hDC = GetWindowDC(hWnd);
if(hDC)
{
RECT CliRect = *Rect;
CliRect.bottom -= OrigRect.top;
CliRect.right -= OrigRect.left;
CliRect.left -= OrigRect.left;
CliRect.top -= OrigRect.top;
Rect->top += MenuDrawMenuBar(hDC, &CliRect, hWnd, TRUE);
ReleaseDC(hWnd, hDC);
}
}
if (ExStyle & WS_EX_CLIENTEDGE)
{
InflateRect(Rect, -2 * GetSystemMetrics(SM_CXBORDER),
-2 * GetSystemMetrics(SM_CYBORDER));
}
if(Style & (WS_VSCROLL | WS_HSCROLL))
{
SCROLLBARINFO sbi;
SETSCROLLBARINFO ssbi;
sbi.cbSize = sizeof(SCROLLBARINFO);
if((Style & WS_VSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_VSCROLL, &sbi))
{
int i;
LONG sx = Rect->right;
sx -= GetSystemMetrics(SM_CXVSCROLL);
for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
ssbi.rgstate[i] = sbi.rgstate[i];
if(sx <= Rect->left)
ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
else
ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
NtUserSetScrollBarInfo(hWnd, OBJID_VSCROLL, &ssbi);
if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
Style &= ~WS_VSCROLL;
}
else
Style &= ~WS_VSCROLL;
if((Style & WS_HSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_HSCROLL, &sbi))
{
int i;
LONG sy = Rect->bottom;
sy -= GetSystemMetrics(SM_CYHSCROLL);
for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
ssbi.rgstate[i] = sbi.rgstate[i];
if(sy <= Rect->top)
ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
else
ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
NtUserSetScrollBarInfo(hWnd, OBJID_HSCROLL, &ssbi);
if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
Style &= ~WS_HSCROLL;
}
else
Style &= ~WS_HSCROLL;
}
if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
{
if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
Rect->left += GetSystemMetrics(SM_CXVSCROLL);
else
Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
}
else
{
if (Style & WS_VSCROLL)
{
if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
Rect->left += GetSystemMetrics(SM_CXVSCROLL);
else
Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
}
else if (Style & WS_HSCROLL)
Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
}
if (Rect->top > Rect->bottom)
Rect->bottom = Rect->top;
if (Rect->left > Rect->right)
Rect->right = Rect->left;
}
else
{
Rect->right = Rect->left;
Rect->bottom = Rect->top;
}
return Result;
}
LRESULT
DefWndNCActivate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
PWND Wnd = ValidateHwnd(hWnd);
if (!Wnd) return 0;
/* Lotus Notes draws menu descriptions in the caption of its main
* window. When it wants to restore original "system" view, it just
* sends WM_NCACTIVATE message to itself. Any optimizations here in
* attempt to minimize redrawings lead to a not restored caption.
*/
if (wParam)
NtUserxSetWindowState(Wnd, WNDSACTIVEFRAME);
else
NtUserxClearWindowState(Wnd, WNDSACTIVEFRAME);
if (Wnd->state & WNDS_NONCPAINT)
return 0;
/* This isn't documented but is reproducible in at least XP SP2 and
* Outlook 2007 depends on it
*/
// MSDN:
// If this parameter is set to -1, DefWindowProc does not repaint the
// nonclient area to reflect the state change.
if (lParam != -1)
{
DefWndNCPaint(hWnd, HRGN_WINDOW, wParam);
}
return TRUE;
}
/*
* FIXME:
* - Check the scrollbar handling
*/
LRESULT
DefWndNCHitTest(HWND hWnd, POINT Point)
{
RECT WindowRect, ClientRect, OrigWndRect;
POINT ClientPoint;
SIZE WindowBorders;
DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
GetWindowRect(hWnd, &WindowRect);
if (!PtInRect(&WindowRect, Point))
{
return HTNOWHERE;
}
OrigWndRect = WindowRect;
if (UserHasWindowEdge(Style, ExStyle))
{
LONG XSize, YSize;
UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
if (!PtInRect(&WindowRect, Point))
{
BOOL ThickFrame;
ThickFrame = (Style & WS_THICKFRAME);
if (Point.y < WindowRect.top)
{
if(Style & WS_MINIMIZE)
return HTCAPTION;
if(!ThickFrame)
return HTBORDER;
if (Point.x < (WindowRect.left + XSize))
return HTTOPLEFT;
if (Point.x >= (WindowRect.right - XSize))
return HTTOPRIGHT;
return HTTOP;
}
if (Point.y >= WindowRect.bottom)
{
if(Style & WS_MINIMIZE)
return HTCAPTION;
if(!ThickFrame)
return HTBORDER;
if (Point.x < (WindowRect.left + XSize))
return HTBOTTOMLEFT;
if (Point.x >= (WindowRect.right - XSize))
return HTBOTTOMRIGHT;
return HTBOTTOM;
}
if (Point.x < WindowRect.left)
{
if(Style & WS_MINIMIZE)
return HTCAPTION;
if(!ThickFrame)
return HTBORDER;
if (Point.y < (WindowRect.top + YSize))
return HTTOPLEFT;
if (Point.y >= (WindowRect.bottom - YSize))
return HTBOTTOMLEFT;
return HTLEFT;
}
if (Point.x >= WindowRect.right)
{
if(Style & WS_MINIMIZE)
return HTCAPTION;
if(!ThickFrame)
return HTBORDER;
if (Point.y < (WindowRect.top + YSize))
return HTTOPRIGHT;
if (Point.y >= (WindowRect.bottom - YSize))
return HTBOTTOMRIGHT;
return HTRIGHT;
}
}
}
else
{
if (ExStyle & WS_EX_STATICEDGE)
InflateRect(&WindowRect,
-GetSystemMetrics(SM_CXBORDER),
-GetSystemMetrics(SM_CYBORDER));
if (!PtInRect(&WindowRect, Point))
return HTBORDER;
}
if ((Style & WS_CAPTION) == WS_CAPTION)
{
if (ExStyle & WS_EX_TOOLWINDOW)
WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
else
WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
if (!PtInRect(&WindowRect, Point))
{
if (Style & WS_SYSMENU)
{
if (ExStyle & WS_EX_TOOLWINDOW)
{
WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
}
else
{
if(!(ExStyle & WS_EX_DLGMODALFRAME))
WindowRect.left += GetSystemMetrics(SM_CXSIZE);
WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
}
}
if (Point.x < WindowRect.left)
return HTSYSMENU;
if (WindowRect.right <= Point.x)
return HTCLOSE;
if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
if (Point.x >= WindowRect.right)
return HTMAXBUTTON;
if (Style & WS_MINIMIZEBOX)
WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
if (Point.x >= WindowRect.right)
return HTMINBUTTON;
return HTCAPTION;
}
}
if(!(Style & WS_MINIMIZE))
{
ClientPoint = Point;
ScreenToClient(hWnd, &ClientPoint);
GetClientRect(hWnd, &ClientRect);
if (PtInRect(&ClientRect, ClientPoint))
{
return HTCLIENT;
}
if (GetMenu(hWnd) && !(Style & WS_CHILD))
{
if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
return HTMENU;
}
if (ExStyle & WS_EX_CLIENTEDGE)
{
InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
-2 * GetSystemMetrics(SM_CYBORDER));
}
if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
(WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
{
RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
HWND Parent = GetParent(hWnd);
TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
else
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
if (PtInRect(&TempRect, Point))
return HTVSCROLL;
TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
else
TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
if (PtInRect(&TempRect2, Point))
return HTHSCROLL;
TempRect.top = TempRect2.top;
TempRect.bottom = TempRect2.bottom;
if(Parent)
GetClientRect(Parent, &ParentRect);
if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
{
if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
return HTBOTTOMLEFT;
else
return HTBOTTOMRIGHT;
}
}
else
{
if (Style & WS_VSCROLL)
{
RECT TempRect = WindowRect;
if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
else
TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
if (PtInRect(&TempRect, Point))
return HTVSCROLL;
} else
if (Style & WS_HSCROLL)
{
RECT TempRect = WindowRect;
TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
if (PtInRect(&TempRect, Point))
return HTHSCROLL;
}
}
}
return HTNOWHERE;
}
VOID
DefWndDoButton(HWND hWnd, WPARAM wParam)
{
MSG Msg;
HDC WindowDC;
BOOL Pressed = TRUE, OldState;
WPARAM SCMsg;
HMENU hSysMenu;
ULONG ButtonType;
DWORD Style;
UINT MenuState;
Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
switch (wParam)
{
case HTCLOSE:
hSysMenu = GetSystemMenu(hWnd, FALSE);
MenuState = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (GetClassLongPtrW(hWnd, GCL_STYLE) & CS_NOCLOSE))
return;
ButtonType = DFCS_CAPTIONCLOSE;
SCMsg = SC_CLOSE;
break;
case HTMINBUTTON:
if (!(Style & WS_MINIMIZEBOX))
return;
ButtonType = DFCS_CAPTIONMIN;
SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
break;
case HTMAXBUTTON:
if (!(Style & WS_MAXIMIZEBOX))
return;
ButtonType = DFCS_CAPTIONMAX;
SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
break;
default:
ASSERT(FALSE);
return;
}
/*
* FIXME: Not sure where to do this, but we must flush the pending
* window updates when someone clicks on the close button and at
* the same time the window is overlapped with another one. This
* looks like a good place for now...
*/
UpdateWindow(hWnd);
WindowDC = GetWindowDC(hWnd);
UserDrawCaptionButtonWnd(hWnd, WindowDC, TRUE, ButtonType);
SetCapture(hWnd);
for (;;)
{
if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
break;
if (CallMsgFilterW( &Msg, MSGF_MAX )) continue;
if (Msg.message == WM_LBUTTONUP)
break;
if (Msg.message != WM_MOUSEMOVE)
continue;
OldState = Pressed;
Pressed = (DefWndNCHitTest(hWnd, Msg.pt) == wParam);
if (Pressed != OldState)
UserDrawCaptionButtonWnd(hWnd, WindowDC, Pressed, ButtonType);
}
if (Pressed)
UserDrawCaptionButtonWnd(hWnd, WindowDC, FALSE, ButtonType);
ReleaseCapture();
ReleaseDC(hWnd, WindowDC);
if (Pressed)
SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, MAKELONG(Msg.pt.x,Msg.pt.y));
}
LRESULT
DefWndNCLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
PWND Wnd = ValidateHwnd(hWnd);
switch (wParam)
{
case HTCAPTION:
{
HWND hTopWnd = hWnd, parent;
while(1)
{
if ((GetWindowLongW( hTopWnd, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
break;
parent = GetAncestor( hTopWnd, GA_PARENT );
if (!parent || parent == GetDesktopWindow()) break;
hTopWnd = parent;
}
if ( NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
GetActiveWindow() == hTopWnd)
{
SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
}
break;
}
case HTSYSMENU:
{
LONG style = GetWindowLongPtrW( hWnd, GWL_STYLE );
if (style & WS_SYSMENU)
{
if( Wnd && !(style & WS_MINIMIZE) )
{
RECT rect;
HDC hDC = GetWindowDC(hWnd);
UserGetInsideRectNC(Wnd, &rect);
UserDrawSysMenuButton(hWnd, hDC, &rect, TRUE);
ReleaseDC( hWnd, hDC );
}
SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
}
break;
}
case HTMENU:
{
SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
break;
}
case HTHSCROLL:
{
SendMessageW(hWnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
break;
}
case HTVSCROLL:
{
SendMessageW(hWnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
break;
}
case HTMINBUTTON:
case HTMAXBUTTON:
case HTCLOSE:
{
DefWndDoButton(hWnd, wParam);
break;
}
case HTLEFT:
case HTRIGHT:
case HTTOP:
case HTBOTTOM:
case HTTOPLEFT:
case HTTOPRIGHT:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
{
/* Old comment:
* "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
* This was previously done by setting wParam=SC_SIZE + wParam - 2
*/
/* But that is not what WinNT does. Instead it sends this. This
* is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
* SC_MOUSEMENU into wParam.
*/
SendMessageW(hWnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
break;
}
case HTBORDER:
break;
}
return(0);
}
LRESULT
DefWndNCLButtonDblClk(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
ULONG Style;
Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
switch(wParam)
{
case HTCAPTION:
{
/* Maximize/Restore the window */
if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
{
SendMessageW(hWnd, WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
}
break;
}
case HTSYSMENU:
{
HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
/* If the close item of the sysmenu is disabled or not present do nothing */
if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
break;
SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, lParam);
break;
}
default:
return DefWndNCLButtonDown(hWnd, wParam, lParam);
}
return(0);
}
/***********************************************************************
* NC_HandleNCRButtonDown
*
* Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
*/
LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
{
MSG msg;
INT hittest = wParam;
switch (hittest)
{
case HTCAPTION:
case HTSYSMENU:
if (!GetSystemMenu( hwnd, FALSE )) break;
SetCapture( hwnd );
for (;;)
{
if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
if (msg.message == WM_RBUTTONUP)
{
hittest = DefWndNCHitTest( hwnd, msg.pt );
break;
}
if (hwnd != GetCapture()) return 0;
}
ReleaseCapture();
if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
{
TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELONG(msg.pt.x,msg.pt.y));
}
break;
}
return 0;
}
/***********************************************************************
* NcGetInsideRect
*
* Get the 'inside' rectangle of a window, i.e. the whole window rectangle
* but without the borders (if any).
* The rectangle is in window coordinates (for drawing with GetWindowDC()).
*/
static void FASTCALL
NcGetInsideRect(HWND Wnd, RECT *Rect)
{
DWORD Style;
DWORD ExStyle;
GetWindowRect(Wnd, Rect);
Rect->right = Rect->right - Rect->left;
Rect->left = 0;
Rect->bottom = Rect->bottom - Rect->top;
Rect->top = 0;
Style = GetWindowLongPtrW(Wnd, GWL_STYLE);
if (0 != (Style & WS_ICONIC))
{
return;
}
/* Remove frame from rectangle */
ExStyle = GetWindowLongPtrW(Wnd, GWL_EXSTYLE);
if (HAS_THICKFRAME(Style, ExStyle))
{
InflateRect(Rect, - GetSystemMetrics(SM_CXFRAME), - GetSystemMetrics(SM_CYFRAME));
}
else if (HAS_DLGFRAME(Style, ExStyle))
{
InflateRect(Rect, - GetSystemMetrics(SM_CXDLGFRAME), - GetSystemMetrics(SM_CYDLGFRAME));
}
else if (HAS_THINFRAME(Style, ExStyle))
{
InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
}
/* We have additional border information if the window
* is a child (but not an MDI child) */
if (0 != (Style & WS_CHILD)
&& 0 == (ExStyle & WS_EX_MDICHILD))
{
if (0 != (ExStyle & WS_EX_CLIENTEDGE))
{
InflateRect(Rect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE));
}
if (0 != (ExStyle & WS_EX_STATICEDGE))
{
InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
}
}
}
/***********************************************************************
* NcGetSysPopupPos
*/
void FASTCALL
NcGetSysPopupPos(HWND Wnd, RECT *Rect)
{
RECT WindowRect;
if (IsIconic(Wnd))
{
GetWindowRect(Wnd, Rect);
}
else
{
NcGetInsideRect(Wnd, Rect);
GetWindowRect(Wnd, &WindowRect);
OffsetRect(Rect, WindowRect.left, WindowRect.top);
if (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE) & WS_CHILD))
{
ClientToScreen(GetParent(Wnd), (POINT *) Rect);
}
Rect->right = Rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
Rect->bottom = Rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
BOOL WINAPI
RealAdjustWindowRectEx(LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu,
DWORD dwExStyle)
{
SIZE BorderSize;
if (bMenu)
{
lpRect->top -= GetSystemMetrics(SM_CYMENU);
}
if ((dwStyle & WS_CAPTION) == WS_CAPTION)
{
if (dwExStyle & WS_EX_TOOLWINDOW)
lpRect->top -= GetSystemMetrics(SM_CYSMCAPTION);
else
lpRect->top -= GetSystemMetrics(SM_CYCAPTION);
}
UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
InflateRect(
lpRect,
BorderSize.cx,
BorderSize.cy);
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
AdjustWindowRectEx(LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu,
DWORD dwExStyle)
{
BOOL Hook, Ret = FALSE;
LoadUserApiHook();
Hook = BeginIfHookedUserApiHook();
/* Bypass SEH and go direct. */
if (!Hook) return RealAdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
_SEH2_TRY
{
Ret = guah.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
_SEH2_END;
EndUserApiHook();
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
AdjustWindowRect(LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu)
{
return AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0);
}
// Enabling this will cause captions to draw smoother, but slower:
#define DOUBLE_BUFFER_CAPTION
/*
* @implemented
*/
BOOL WINAPI
DrawCaption(HWND hWnd, HDC hDC, LPCRECT lprc, UINT uFlags)
{
BOOL Hook, Ret = FALSE;
LoadUserApiHook();
Hook = BeginIfHookedUserApiHook();
/* Bypass SEH and go direct. */
if (!Hook) return NtUserDrawCaption(hWnd, hDC, lprc, uFlags);
_SEH2_TRY
{
Ret = guah.DrawCaption(hWnd, hDC, lprc, uFlags);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
_SEH2_END;
EndUserApiHook();
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
DrawCaptionTempW(
HWND hWnd,
HDC hDC,
const RECT *rect,
HFONT hFont,
HICON hIcon,
LPCWSTR str,
UINT uFlags
)
{
UNICODE_STRING Text = {0};
RtlInitUnicodeString(&Text, str);
return NtUserDrawCaptionTemp(hWnd, hDC, rect, hFont, hIcon, &Text, uFlags);
}
/*
* @implemented
*/
BOOL
WINAPI
DrawCaptionTempA(
HWND hwnd,
HDC hdc,
const RECT *rect,
HFONT hFont,
HICON hIcon,
LPCSTR str,
UINT uFlags
)
{
LPWSTR strW;
INT len;
BOOL ret = FALSE;
if (!(uFlags & DC_TEXT) || !str)
return DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, NULL, uFlags);
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
if ((strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
{
MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len );
ret = DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
HeapFree(GetProcessHeap(), 0, strW);
}
return ret;
}