I tried to patch the code with the instructions at:
Re: Fails under Windows 2003 SP1 - How to fix the DEP Problem
http://www.codeproject.com/miscctrl/balloonhelp.asp?msg=1383510#xx1383510xx[^]
http://www.codeproject.com/miscctrl/balloonhelp.asp?msg=1462896#xx1462896xx[^]
http://www.codeproject.com/miscctrl/balloonhelp.asp?msg=1531900#xx1531900xx[^]
After the three fixes I got rid of _ThunkImpl class and it works on x64!!!.
If anyone wants to get the full code with all the fixes, here it is:
BalloonHelp.h :
#ifndef _BALLOON_HELP_H_INCLUDED_
#define _BALLOON_HELP_H_INCLUDED_
#include <string>
#include <list>
#include <afxmt.h>
class CBalloonHelp : public CWnd
{
public:
CBalloonHelp();
virtual ~CBalloonHelp();
static const unsigned int unCLOSE_ON_LBUTTON_UP;
static const unsigned int unCLOSE_ON_MBUTTON_UP;
static const unsigned int unCLOSE_ON_RBUTTON_UP;
static const unsigned int unCLOSE_ON_LBUTTON_DOWN;
static const unsigned int unCLOSE_ON_MBUTTON_DOWN;
static const unsigned int unCLOSE_ON_RBUTTON_DOWN;
static const unsigned int unCLOSE_ON_MOUSE_MOVE;
static const unsigned int unCLOSE_ON_KEYPRESS;
static const unsigned int unCLOSE_ON_ANYTHING;
static const unsigned int unDELAY_CLOSE;
static const unsigned int unDELETE_THIS_ON_CLOSE;
static const unsigned int unSHOW_CLOSE_BUTTON;
static const unsigned int unSHOW_INNER_SHADOW;
static const unsigned int unSHOW_TOPMOST;
static const unsigned int unDISABLE_XP_SHADOW;
static const unsigned int unDISABLE_FADEIN;
static const unsigned int unDISABLE_FADEOUT;
static const unsigned int unDISABLE_FADE;
BOOL Create(const CString& strTitle,
const CString& strContent,
const CPoint& ptAnchor,
unsigned int unOptions,
CWnd* pParentWnd = NULL,
const CString strURL = "",
unsigned int unTimeout = 0,
HICON hIcon = NULL);
static void LaunchBalloon(const CString& strTitle, const CString& strContent,
const CPoint& ptAnchor,
LPCTSTR szIcon = IDI_EXCLAMATION,
unsigned int unOptions = unSHOW_CLOSE_BUTTON,
CWnd* pParentWnd = NULL,
const CString strURL = "",
unsigned int unTimeout = 10000);
void SetTitleFont(CFont* pFont);
void SetContentFont(CFont* pFont);
void SetIcon(HICON hIcon);
void SetIconScaled(HICON hIcon, int cx, int cy);
void SetIcon(HBITMAP hBitmap, COLORREF crMask);
void SetIcon(HBITMAP hBitmap, HBITMAP hMask);
void SetIcon(CImageList* pImageList, int nIconIndex);
void SetURL(const CString& strURL);
void SetTimeout(unsigned int unTimeout);
void SetMouseMoveTolerance(int nTolerance);
void SetAnchorPoint(CPoint ptAnchor, CWnd* pWndAnchor = NULL);
void SetTitle(const CString& strTitle);
void SetContent(const CString& strContent);
void SetForegroundColor(COLORREF crForeground);
void SetBackgroundColor(COLORREF crBackground);
protected:
static const int nTIP_TAIL;
static const int nTIP_MARGIN;
CPoint GetAnchorPoint();
void GetAnchorScreenBounds(CRect& rect);
enum BALLOON_QUADRANT { BQ_TOPRIGHT, BQ_TOPLEFT, BQ_BOTTOMRIGHT, BQ_BOTTOMLEFT };
BALLOON_QUADRANT GetBalloonQuadrant();
virtual void DrawNonClientArea(CDC* pDC);
virtual void DrawClientArea(CDC* pDC);
virtual CSize DrawHeader(CDC* pDC, bool bDraw = TRUE);
virtual CSize DrawContent(CDC* pDC, int nTop, bool bDraw = TRUE);
CSize CalcHeaderSize(CDC* pDC) { return DrawHeader(pDC, FALSE); }
CSize CalcContentSize(CDC* pDC) { return DrawContent(pDC, 0, FALSE); }
CSize CalcWindowSize();
CSize CalcClientSize();
void PositionWindow();
void ShowBalloon(void);
void HideBalloon(void);
static ATOM GetClassAtom(BOOL bShadowed);
afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
afx_msg LRESULT OnPrint(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnPrintClient(WPARAM wParam, LPARAM lParam);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnPaint();
afx_msg void OnNcPaint();
afx_msg void OnLButtonDown(UINT, CPoint point);
afx_msg void OnLButtonUp(UINT, CPoint point);
afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnMouseMove(UINT, CPoint point);
afx_msg LRESULT OnNcHitTest(CPoint point);
afx_msg void OnClose();
afx_msg void OnDestroy();
virtual void PostNcDestroy();
DECLARE_MESSAGE_MAP()
private:
void SetKeyboardHook();
void RemoveKeyboardHook();
void SetMouseHook();
void RemoveMouseHook();
void SetCallWndRetHook();
void RemoveCallWndRetHook();
protected:
LRESULT KeyboardHookProc( int code, WPARAM wParam, LPARAM lParam);
LRESULT MouseHookProc(int code, WPARAM wParam, LPARAM lParam);
LRESULT CallWndRetProc(int code, WPARAM wParam, LPARAM lParam);
private:
typedef BOOL (WINAPI* FN_ANIMATE_WINDOW)(HWND,DWORD,DWORD);
FN_ANIMATE_WINDOW m_fnAnimateWindow;
bool m_bKeyboardHook;
bool m_bMouseHook;
bool m_bCallWndRetHook;
unsigned int m_unOptions;
unsigned int m_unTimeout;
UINT_PTR m_unTimerClose;
CString m_strContent;
CString m_strURL;
HWND m_hwndAnchor;
CPoint m_ptAnchor;
CImageList m_ilIcon;
CFont* m_pTitleFont;
CFont* m_pContentFont;
COLORREF m_crBackground;
COLORREF m_crForeground;
CRect m_screenRect;
CRgn m_rgnComplete;
CPoint m_ptMouseOrig;
UINT m_uCloseState;
int m_nMouseMoveToleranceX;
int m_nMouseMoveToleranceY;
static ATOM s_ClassAtom;
static ATOM s_ClassAtomShadowed;
protected:
class HookMan
{
public:
HHOOK m_hKeyboardHook;
HHOOK m_hMouseHook;
HHOOK m_hCallWndRetHook;
std::list<CBalloonHelp*> m_lstClasses;
int m_nCountKeyboard;
int m_nCountMouse;
int m_nCountCallWnd;
CCriticalSection m_cs;
HookMan();
~HookMan();
void AddClass(CBalloonHelp* pClass);
void RemoveClass(CBalloonHelp* pClass);
void SetKeyboardHook();
void RemoveKeyboardHook();
void SetMouseHook();
void RemoveMouseHook();
void SetCallWndRetHook();
void RemoveCallWndRetHook();
static LRESULT CALLBACK KeyboardHookProcStatic( int code, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK MouseHookProcStatic(int code, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK CallWndRetProcStatic(int code, WPARAM wParam, LPARAM lParam);
};
friend class HookMan;
static HookMan s_hookMan;
};
#endif // _BALLOON_HELP_H_INCLUDED_
BalloonHelp.cpp :
#include "stdafx.h"
#include "BalloonHelp.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef DFCS_HOT
#define DFCS_HOT 0x1000
#endif
#ifndef AW_HIDE
#define AW_HIDE 0x00010000
#define AW_BLEND 0x00080000
#endif
#ifndef CS_DROPSHADOW
#define CS_DROPSHADOW 0x00020000
#endif
#ifndef SPI_GETDROPSHADOW
#define SPI_GETDROPSHADOW 0x1024
#endif
#ifndef SPI_GETTOOLTIPANIMATION
#define SPI_GETTOOLTIPANIMATION 0x1016
#endif
#ifndef SPI_GETTOOLTIPFADE
#define SPI_GETTOOLTIPFADE 0x1018
#endif
const unsigned int CBalloonHelp::unCLOSE_ON_LBUTTON_UP = 0x0001;
const unsigned int CBalloonHelp::unCLOSE_ON_MBUTTON_UP = 0x0002;
const unsigned int CBalloonHelp::unCLOSE_ON_RBUTTON_UP = 0x0004;
const unsigned int CBalloonHelp::unCLOSE_ON_LBUTTON_DOWN = 0x0008;
const unsigned int CBalloonHelp::unCLOSE_ON_MBUTTON_DOWN = 0x0010;
const unsigned int CBalloonHelp::unCLOSE_ON_RBUTTON_DOWN = 0x0020;
const unsigned int CBalloonHelp::unCLOSE_ON_MOUSE_MOVE = 0x0040;
const unsigned int CBalloonHelp::unCLOSE_ON_KEYPRESS = 0x0080;
const unsigned int CBalloonHelp::unCLOSE_ON_ANYTHING = CBalloonHelp::unCLOSE_ON_MOUSE_MOVE|CBalloonHelp::unCLOSE_ON_RBUTTON_DOWN|CBalloonHelp::unCLOSE_ON_RBUTTON_DOWN|CBalloonHelp::unCLOSE_ON_MBUTTON_DOWN|CBalloonHelp::unCLOSE_ON_LBUTTON_DOWN|CBalloonHelp::unCLOSE_ON_RBUTTON_UP|CBalloonHelp::unCLOSE_ON_MBUTTON_UP|CBalloonHelp::unCLOSE_ON_LBUTTON_UP;
const unsigned int CBalloonHelp::unDELAY_CLOSE = 0x0100;
const unsigned int CBalloonHelp::unDELETE_THIS_ON_CLOSE = 0x0200;
const unsigned int CBalloonHelp::unSHOW_CLOSE_BUTTON = 0x0400;
const unsigned int CBalloonHelp::unSHOW_INNER_SHADOW = 0x0800;
const unsigned int CBalloonHelp::unSHOW_TOPMOST = 0x1000;
const unsigned int CBalloonHelp::unDISABLE_XP_SHADOW = 0x2000;
const unsigned int CBalloonHelp::unDISABLE_FADEIN = 0x4000;
const unsigned int CBalloonHelp::unDISABLE_FADEOUT = 0x8000;
const unsigned int CBalloonHelp::unDISABLE_FADE = CBalloonHelp::unDISABLE_FADEIN|CBalloonHelp::unDISABLE_FADEOUT;
const int CBalloonHelp::nTIP_TAIL = 20;
const int CBalloonHelp::nTIP_MARGIN = 8;
ATOM CBalloonHelp::s_ClassAtom = NULL;
ATOM CBalloonHelp::s_ClassAtomShadowed = NULL;
#define ID_TIMER_CLOSE 1
void CBalloonHelp::LaunchBalloon(const CString& strTitle, const CString& strContent,
const CPoint& ptAnchor,
LPCTSTR szIcon ,
unsigned int unOptions ,
CWnd* pParentWnd ,
const CString strURL ,
unsigned int unTimeout )
{
CBalloonHelp* pbh = new CBalloonHelp;
if ( NULL != szIcon )
{
CSize sizeIcon(max(::GetSystemMetrics(SM_CXSIZE), ::GetSystemMetrics(SM_CXSMICON)), max(::GetSystemMetrics(SM_CYSIZE), ::GetSystemMetrics(SM_CYSMICON)));
HICON hIcon = (HICON)::LoadImage(NULL, szIcon, IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_SHARED);
if (NULL != hIcon)
pbh->SetIconScaled(hIcon, sizeIcon.cx, sizeIcon.cy);
}
pbh->Create(strTitle, strContent, ptAnchor, unOptions|unDELETE_THIS_ON_CLOSE,
pParentWnd, strURL, unTimeout, NULL);
}
CBalloonHelp::CBalloonHelp()
: m_fnAnimateWindow(NULL),
m_unOptions(0),
m_unTimeout(0),
m_unTimerClose(0),
m_strURL(""),
m_ptAnchor(0,0),
m_hwndAnchor(NULL),
m_screenRect(0,0,0,0),
m_strContent(""),
m_nMouseMoveToleranceX(34),
m_nMouseMoveToleranceY(14),
m_ptMouseOrig(0,0),
m_uCloseState(0),
m_pTitleFont(NULL),
m_pContentFont(NULL),
m_crForeground(::GetSysColor(COLOR_INFOTEXT)),
m_crBackground(::GetSysColor(COLOR_INFOBK)),
m_bKeyboardHook(false),
m_bMouseHook(false),
m_bCallWndRetHook(false)
{
CBalloonHelp::s_hookMan.AddClass(this);
HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));
if ( NULL != hUser32 )
m_fnAnimateWindow = (FN_ANIMATE_WINDOW)GetProcAddress(hUser32, _T("AnimateWindow"));
else
m_fnAnimateWindow = NULL;
int nTol = 0;
if ( ::SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &nTol, 0) && nTol > 0 )
{
m_nMouseMoveToleranceX = nTol+30;
m_nMouseMoveToleranceY = nTol+10;
}
}
CBalloonHelp::~CBalloonHelp()
{
CBalloonHelp::s_hookMan.RemoveClass(this);
if ( NULL != m_pTitleFont )
delete m_pTitleFont;
m_pTitleFont = NULL;
if ( NULL != m_pContentFont )
delete m_pContentFont;
m_pContentFont = NULL;
}
void CBalloonHelp::SetTitleFont(CFont* pFont)
{
if ( NULL != m_pTitleFont )
delete m_pTitleFont;
m_pTitleFont = pFont;
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetContentFont(CFont* pFont)
{
if ( NULL != m_pContentFont )
delete m_pContentFont;
m_pContentFont = pFont;
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetIcon(HICON hIcon)
{
if ( NULL != m_ilIcon.m_hImageList )
m_ilIcon.DeleteImageList();
ICONINFO iconinfo;
if ( NULL != hIcon && ::GetIconInfo(hIcon, &iconinfo) )
{
SetIcon(iconinfo.hbmColor, iconinfo.hbmMask);
::DeleteObject(iconinfo.hbmColor);
::DeleteObject(iconinfo.hbmMask);
}
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetIconScaled(HICON hIcon, int cx, int cy)
{
ICONINFO iconinfo;
if ( NULL != hIcon && ::GetIconInfo(hIcon, &iconinfo) )
{
BITMAP bm;
if (::GetObject(iconinfo.hbmColor, sizeof(bm),(LPVOID)&bm))
{
CDC dc;
CDC dcTmp1;
CDC dcTmp2;
CBitmap bmpIcon;
CBitmap bmpIconScaled;
dc.Attach(::GetDC(NULL));
dcTmp1.CreateCompatibleDC(&dc);
dcTmp2.CreateCompatibleDC(&dc);
bmpIcon.CreateCompatibleBitmap(&dc, bm.bmWidth, bm.bmHeight);
bmpIconScaled.CreateCompatibleBitmap(&dc, cx, cy);
::ReleaseDC(NULL, dc.Detach());
CBitmap* pbmpOld1 = dcTmp1.SelectObject(&bmpIcon);
CBitmap* pbmpOld2 = dcTmp2.SelectObject(&bmpIconScaled);
dcTmp1.FillSolidRect(0,0,bm.bmWidth,bm.bmHeight, m_crBackground);
::DrawIconEx(dcTmp1, 0,0,hIcon,bm.bmWidth,bm.bmHeight,0,NULL,DI_NORMAL);
dcTmp2.SetStretchBltMode(HALFTONE);
dcTmp2.StretchBlt(0,0,cx,cy,&dcTmp1, 0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcTmp1.SelectObject(pbmpOld1);
dcTmp2.SelectObject(pbmpOld2);
SetIcon(bmpIconScaled, m_crBackground);
}
::DeleteObject(iconinfo.hbmColor);
::DeleteObject(iconinfo.hbmMask);
}
}
void CBalloonHelp::SetIcon(HBITMAP hBitmap, COLORREF crMask)
{
if ( NULL != m_ilIcon.m_hImageList )
m_ilIcon.DeleteImageList();
if ( NULL != hBitmap )
{
BITMAP bm;
if (::GetObject(hBitmap, sizeof(bm),(LPVOID)&bm))
{
m_ilIcon.Create(bm.bmWidth, bm.bmHeight, ILC_COLOR24|ILC_MASK,1,0);
m_ilIcon.Add(CBitmap::FromHandle(hBitmap), crMask);
}
}
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetIcon(HBITMAP hBitmap, HBITMAP hMask)
{
if ( NULL != m_ilIcon.m_hImageList )
m_ilIcon.DeleteImageList();
ASSERT(NULL != hBitmap);
ASSERT(NULL != hMask);
BITMAP bm;
if (::GetObject(hBitmap, sizeof(bm),(LPVOID)&bm))
{
m_ilIcon.Create(bm.bmWidth, bm.bmHeight, ILC_COLOR24|ILC_MASK,1,0);
m_ilIcon.Add(CBitmap::FromHandle(hBitmap), CBitmap::FromHandle(hMask));
}
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetIcon(CImageList* pImageList, int nIconIndex)
{
ASSERT_VALID(pImageList);
ASSERT(nIconIndex >= 0 && nIconIndex < pImageList->GetImageCount() );
HICON hIcon = NULL;
if ( NULL != pImageList && nIconIndex >= 0 && nIconIndex < pImageList->GetImageCount() )
hIcon = pImageList->ExtractIcon(nIconIndex);
SetIcon(hIcon);
if ( NULL != hIcon )
::DestroyIcon(hIcon);
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetURL(const CString& strURL)
{
m_strURL = strURL;
}
void CBalloonHelp::SetTimeout(unsigned int unTimeout)
{
m_unTimeout = unTimeout;
if ( NULL != m_hWnd )
{
if ( m_unTimeout > 0 )
{
m_unTimerClose = SetTimer(ID_TIMER_CLOSE, m_unTimeout, NULL);
}
else
{
KillTimer(m_unTimerClose);
}
}
}
void CBalloonHelp::SetAnchorPoint(CPoint ptAnchor, CWnd* pWndAnchor )
{
m_ptAnchor = ptAnchor;
m_hwndAnchor = pWndAnchor->GetSafeHwnd();
if ( NULL != m_hwndAnchor )
SetCallWndRetHook();
else
RemoveCallWndRetHook();
if ( NULL != m_hWnd )
{
PositionWindow();
}
}
void CBalloonHelp::SetTitle(const CString& strTitle)
{
SetWindowText(strTitle);
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetContent(const CString& strContent)
{
m_strContent = strContent;
if ( NULL != m_hWnd )
PositionWindow();
}
void CBalloonHelp::SetForegroundColor(COLORREF crForeground)
{
m_crForeground = crForeground;
if ( NULL != m_hWnd )
Invalidate(FALSE);
}
void CBalloonHelp::SetBackgroundColor(COLORREF crBackground)
{
m_crBackground = crBackground;
if ( NULL != m_hWnd )
Invalidate(FALSE);
}
void CBalloonHelp::SetMouseMoveTolerance(int nTolerance)
{
m_nMouseMoveToleranceX = nTolerance;
m_nMouseMoveToleranceY = nTolerance;
}
BOOL CBalloonHelp::Create(const CString& strTitle, const CString& strContent,
const CPoint& ptAnchor, unsigned int unOptions,
CWnd* pParentWnd ,
const CString strURL ,
unsigned int unTimeout ,
HICON hIcon )
{
m_strContent = strContent;
SetAnchorPoint(ptAnchor, pParentWnd);
m_unOptions = unOptions;
m_strURL = strURL;
m_unTimeout = unTimeout;
if ( NULL != hIcon )
SetIcon(hIcon);
pParentWnd = GetSafeOwner(pParentWnd);
if ( NULL == pParentWnd )
{
ASSERT(FALSE);
return FALSE;
}
if ( NULL == m_pContentFont )
{
m_pContentFont = new CFont;
if ( !m_pContentFont->CreateStockObject(DEFAULT_GUI_FONT) )
return FALSE;
}
if ( NULL == m_pTitleFont )
{
m_pTitleFont = new CFont;
LOGFONT LogFont;
m_pContentFont->GetLogFont(&LogFont);
LogFont.lfWeight = FW_BOLD;
if ( !m_pTitleFont->CreateFontIndirect(&LogFont) )
return FALSE;
}
ATOM wndClass = GetClassAtom(!(m_unOptions&unDISABLE_XP_SHADOW));
if ( NULL == wndClass )
return FALSE;
BOOL bFade = FALSE;
::SystemParametersInfo(SPI_GETTOOLTIPANIMATION, 0, &bFade, 0);
if (bFade)
::SystemParametersInfo(SPI_GETTOOLTIPFADE, 0, &bFade, 0);
if (!bFade || NULL == m_fnAnimateWindow)
m_unOptions |= unDISABLE_FADE;
DWORD dwExStyle = WS_EX_TOOLWINDOW;
if ( m_unOptions&unSHOW_TOPMOST )
dwExStyle |= WS_EX_TOPMOST;
if ( !CreateEx(dwExStyle, (LPCTSTR)wndClass, strTitle, WS_POPUP, CRect(0,0,10,10), pParentWnd, 0, NULL) )
return FALSE;
PositionWindow();
if ( (m_unOptions&unCLOSE_ON_MOUSE_MOVE)
||(m_unOptions&unCLOSE_ON_LBUTTON_UP)
||(m_unOptions&unCLOSE_ON_LBUTTON_DOWN)
||(m_unOptions&unCLOSE_ON_MBUTTON_UP)
||(m_unOptions&unCLOSE_ON_MBUTTON_DOWN)
||(m_unOptions&unCLOSE_ON_RBUTTON_UP)
||(m_unOptions&unCLOSE_ON_RBUTTON_DOWN) )
{
::GetCursorPos(&m_ptMouseOrig);
SetMouseHook();
}
if ( (m_unOptions&unCLOSE_ON_LBUTTON_UP)
||(m_unOptions&unCLOSE_ON_MBUTTON_UP)
||(m_unOptions&unCLOSE_ON_RBUTTON_UP) )
{
if ( NULL == GetCapture() )
SetCapture();
}
if ( m_unOptions&unCLOSE_ON_KEYPRESS )
SetKeyboardHook();
ShowBalloon();
return TRUE;
}
CPoint CBalloonHelp::GetAnchorPoint()
{
CPoint ptAnchor = m_ptAnchor;
if ( NULL != m_hwndAnchor )
::ClientToScreen(m_hwndAnchor, &ptAnchor);
return ptAnchor;
}
void CBalloonHelp::GetAnchorScreenBounds(CRect& rect)
{
if ( m_screenRect.IsRectEmpty() )
{
HMONITOR hMonitor = MonitorFromPoint(GetAnchorPoint(), MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
m_screenRect = mi.rcWork;
}
rect = m_screenRect;
}
CBalloonHelp::BALLOON_QUADRANT CBalloonHelp::GetBalloonQuadrant()
{
CRect rectDesktop;
GetAnchorScreenBounds(rectDesktop);
CPoint ptAnchor = GetAnchorPoint();
if ( ptAnchor.y < rectDesktop.top + rectDesktop.Height()/2 )
{
if ( ptAnchor.x < rectDesktop.left + rectDesktop.Width()/2 )
{
return BQ_TOPLEFT;
}
else
{
return BQ_TOPRIGHT;
}
}
else
{
if ( ptAnchor.x < rectDesktop.left + rectDesktop.Width()/2 )
{
return BQ_BOTTOMLEFT;
}
else
{
return BQ_BOTTOMRIGHT;
}
}
}
void CBalloonHelp::DrawNonClientArea(CDC* pDC)
{
CRect rect;
GetWindowRect(&rect);
ScreenToClient(&rect);
CRect rectClient;
GetClientRect(&rectClient);
rectClient.OffsetRect(-rect.left, -rect.top);
rect.OffsetRect(-rect.left, -rect.top);
pDC->ExcludeClipRect(&rectClient);
pDC->FillSolidRect(&rect, m_crBackground);
pDC->SelectClipRgn(NULL);
ASSERT(NULL != m_rgnComplete.m_hObject);
CBrush brushFg;
brushFg.CreateSolidBrush(m_crForeground);
if ( m_unOptions & unSHOW_INNER_SHADOW )
{
CBrush brushHL;
int red = 170 + GetRValue(m_crBackground)/3;
int green = 170 + GetGValue(m_crBackground)/3;
int blue = 170 + GetBValue(m_crBackground)/3;
brushHL.CreateSolidBrush(RGB(red,green,blue));
m_rgnComplete.OffsetRgn(1,1);
pDC->FrameRgn(&m_rgnComplete, &brushHL, 2, 2);
red = GetRValue(m_crForeground)/3 + GetRValue(m_crBackground)/3*2;
green = GetGValue(m_crForeground)/3 + GetGValue(m_crBackground)/3*2;
blue = GetBValue(m_crForeground)/3 + GetBValue(m_crBackground)/3*2;
brushHL.DeleteObject();
m_rgnComplete.OffsetRgn(-2,-2);
brushHL.CreateSolidBrush(RGB(red,green,blue));
pDC->FrameRgn(&m_rgnComplete, &brushHL, 2, 2);
m_rgnComplete.OffsetRgn(1,1);
}
pDC->FrameRgn(&m_rgnComplete, &brushFg, 1, 1);
}
void CBalloonHelp::DrawClientArea(CDC* pDC)
{
CSize sizeHeader = DrawHeader(pDC);
DrawContent(pDC, sizeHeader.cy+nTIP_MARGIN);
}
CSize CBalloonHelp::DrawHeader(CDC* pDC, bool bDraw)
{
CSize sizeHdr(0,0);
CRect rectClient;
GetClientRect(&rectClient);
if ( NULL != m_ilIcon.m_hImageList )
{
int x = 0;
int y = 0;
ImageList_GetIconSize(m_ilIcon, &x, &y);
sizeHdr.cx += x;
sizeHdr.cy = max(sizeHdr.cy, y);
m_ilIcon.SetBkColor(m_crBackground);
if (bDraw)
m_ilIcon.Draw(pDC, 0, CPoint(0,0), ILD_NORMAL);
rectClient.left += x;
}
if ( m_unOptions & unSHOW_CLOSE_BUTTON )
{
int nBtnWidth = ::GetSystemMetrics(SM_CXSIZE);
if ( sizeHdr.cx > 0 )
sizeHdr.cx += nTIP_MARGIN;
sizeHdr.cx += nBtnWidth;
sizeHdr.cy = max(sizeHdr.cy, ::GetSystemMetrics(SM_CYSIZE));
if (bDraw)
pDC->DrawFrameControl(CRect(rectClient.right-nBtnWidth,0,rectClient.right,::GetSystemMetrics(SM_CYSIZE)), DFC_CAPTION, DFCS_CAPTIONCLOSE|DFCS_FLAT);
rectClient.right -= nBtnWidth;
}
CString strTitle;
GetWindowText(strTitle);
if ( !strTitle.IsEmpty() )
{
CFont* pOldFont = pDC->SelectObject(m_pTitleFont);
if ( sizeHdr.cx > 0 )
sizeHdr.cx += nTIP_MARGIN;
CRect rectTitle(0,0,0,0);
pDC->DrawText(strTitle, &rectTitle, DT_CALCRECT | DT_NOPREFIX | DT_EXPANDTABS | DT_SINGLELINE);
sizeHdr.cx += rectTitle.Width();
sizeHdr.cy = max(sizeHdr.cy, rectTitle.Height());
if ( bDraw )
{
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(m_crForeground);
pDC->DrawText(strTitle, &rectClient, DT_CENTER | DT_NOPREFIX | DT_EXPANDTABS | DT_SINGLELINE);
}
pDC->SelectObject(pOldFont);
}
return sizeHdr;
}
CSize CBalloonHelp::DrawContent(CDC* pDC, int nTop, bool bDraw)
{
CRect rectContent;
GetAnchorScreenBounds(rectContent);
rectContent.OffsetRect(-rectContent.left, -rectContent.top);
rectContent.top = nTop;
rectContent.right -= rectContent.Width()/2;
CFont* pOldFont = pDC->SelectObject(m_pContentFont);
if ( !m_strContent.IsEmpty() )
pDC->DrawText(m_strContent, &rectContent, DT_CALCRECT | DT_LEFT | DT_NOPREFIX | DT_EXPANDTABS | DT_WORDBREAK);
else
rectContent.SetRectEmpty();
if (bDraw)
{
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(m_crForeground);
pDC->DrawText(m_strContent, &rectContent, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_EXPANDTABS);
}
pDC->SelectObject(pOldFont);
return rectContent.Size();
}
CSize CBalloonHelp::CalcClientSize()
{
ASSERT(NULL != m_hWnd);
CWindowDC dc(this);
CSize sizeHeader = CalcHeaderSize(&dc);
CSize sizeContent = CalcContentSize(&dc);
return CSize(max(sizeHeader.cx,sizeContent.cx), sizeHeader.cy + nTIP_MARGIN + sizeContent.cy);
}
CSize CBalloonHelp::CalcWindowSize()
{
CSize size = CalcClientSize();
size.cx += nTIP_MARGIN*2;
size.cy += nTIP_TAIL+nTIP_MARGIN*2;
return size;
}
void CBalloonHelp::PositionWindow()
{
CSize sizeWnd = CalcWindowSize();
CPoint ptTail[3];
CPoint ptTopLeft(0,0);
CPoint ptBottomRight(sizeWnd.cx, sizeWnd.cy);
m_screenRect.SetRectEmpty();
switch (GetBalloonQuadrant())
{
case BQ_TOPLEFT:
ptTopLeft.y = nTIP_TAIL;
ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4 + nTIP_TAIL;
ptTail[0].y = nTIP_TAIL+1;
ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4;
ptTail[2].y = ptTail[0].y;
ptTail[1].x = ptTail[2].x;
ptTail[1].y = 1;
break;
case BQ_TOPRIGHT:
ptTopLeft.y = nTIP_TAIL;
ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4*3;
ptTail[0].y = nTIP_TAIL+1;
ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4*3 + nTIP_TAIL;
ptTail[2].y = ptTail[0].y;
ptTail[1].x = ptTail[2].x;
ptTail[1].y = 1;
break;
case BQ_BOTTOMLEFT:
ptBottomRight.y = sizeWnd.cy-nTIP_TAIL;
ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4 + nTIP_TAIL;
ptTail[0].y = sizeWnd.cy-nTIP_TAIL-2;
ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4;
ptTail[2].y = ptTail[0].y;
ptTail[1].x = ptTail[2].x;
ptTail[1].y = sizeWnd.cy-2;
break;
case BQ_BOTTOMRIGHT:
ptBottomRight.y = sizeWnd.cy-nTIP_TAIL;
ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4*3;
ptTail[0].y = sizeWnd.cy-nTIP_TAIL-2;
ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4*3 + nTIP_TAIL;
ptTail[2].y = ptTail[0].y;
ptTail[1].x = ptTail[2].x;
ptTail[1].y = sizeWnd.cy-2;
break;
}
if ( ptTail[0].x < nTIP_MARGIN )
ptTail[0].x = nTIP_MARGIN;
if ( ptTail[0].x > sizeWnd.cx - nTIP_MARGIN )
ptTail[0].x = sizeWnd.cx - nTIP_MARGIN;
if ( ptTail[1].x < nTIP_MARGIN )
ptTail[1].x = nTIP_MARGIN;
if ( ptTail[1].x > sizeWnd.cx - nTIP_MARGIN )
ptTail[1].x = sizeWnd.cx - nTIP_MARGIN;
if ( ptTail[2].x < nTIP_MARGIN )
ptTail[2].x = nTIP_MARGIN;
if ( ptTail[2].x > sizeWnd.cx - nTIP_MARGIN )
ptTail[2].x = sizeWnd.cx - nTIP_MARGIN;
CPoint ptAnchor = GetAnchorPoint();
CPoint ptOffs(ptAnchor.x - ptTail[1].x, ptAnchor.y - ptTail[1].y);
CRect rectScreen;
GetAnchorScreenBounds(rectScreen);
int nAdjustX = 0;
int nAdjustY = 0;
if ( ptOffs.x < rectScreen.left )
nAdjustX = rectScreen.left-ptOffs.x;
else if ( ptOffs.x + sizeWnd.cx >= rectScreen.right )
nAdjustX = rectScreen.right - (ptOffs.x + sizeWnd.cx);
if ( ptOffs.y + nTIP_TAIL < rectScreen.top )
nAdjustY = rectScreen.top - (ptOffs.y + nTIP_TAIL);
else if ( ptOffs.y + sizeWnd.cy - nTIP_TAIL >= rectScreen.bottom )
nAdjustY = rectScreen.bottom - (ptOffs.y + sizeWnd.cy - nTIP_TAIL);
ptTail[1].x -= nAdjustX;
ptOffs.x += nAdjustX;
ptOffs.y += nAdjustY;
MoveWindow(ptOffs.x, ptOffs.y, sizeWnd.cx, sizeWnd.cy, TRUE);
CRgn region;
CRgn regionRound;
CRgn regionComplete;
region.CreatePolygonRgn(&ptTail[0], 3, ALTERNATE);
regionRound.CreateRoundRectRgn(ptTopLeft.x,ptTopLeft.y,ptBottomRight.x,ptBottomRight.y,nTIP_MARGIN*3,nTIP_MARGIN*3);
regionComplete.CreateRectRgn(0,0,1,1);
regionComplete.CombineRgn(®ion, ®ionRound, RGN_OR);
if ( NULL == m_rgnComplete.m_hObject )
m_rgnComplete.CreateRectRgn(0,0,1,1);
if ( !m_rgnComplete.EqualRgn(®ionComplete) )
{
m_rgnComplete.CopyRgn(®ionComplete);
SetWindowRgn((HRGN)regionComplete.Detach(), TRUE);
RedrawWindow(NULL, NULL, RDW_UPDATENOW| RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
}
}
ATOM CBalloonHelp::GetClassAtom(BOOL bShadowed)
{
if ( NULL == s_ClassAtom )
{
WNDCLASSEX wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_DBLCLKS|CS_SAVEBITS
|CS_DROPSHADOW;
wcx.lpfnWndProc = AfxWndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = AfxGetInstanceHandle();
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL,IDC_ARROW);
wcx.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW);
wcx.lpszMenuName = NULL;
wcx.lpszClassName = "BalloonHelpClassDS";
wcx.hIconSm = NULL;
s_ClassAtomShadowed = RegisterClassEx(&wcx);
wcx.style &= ~CS_DROPSHADOW;
wcx.lpszClassName = "BalloonHelpClass";
s_ClassAtom = RegisterClassEx(&wcx);
}
if ( bShadowed && NULL != s_ClassAtomShadowed )
return s_ClassAtomShadowed;
return s_ClassAtom;
}
void CBalloonHelp::ShowBalloon(void)
{
ShowWindow(SW_SHOWNOACTIVATE);
if ( !(m_unOptions&unDELAY_CLOSE) )
SetTimeout(m_unTimeout);
}
void CBalloonHelp::HideBalloon(void)
{
if ( m_unOptions&unDELAY_CLOSE )
{
m_unOptions &= ~(unDELAY_CLOSE|unCLOSE_ON_ANYTHING);
SetTimeout(m_unTimeout);
return;
}
ShowWindow( SW_HIDE );
if ( GetCapture() == this )
ReleaseCapture();
DestroyWindow();
}
void CBalloonHelp::SetKeyboardHook()
{
if (m_bKeyboardHook){ return; }
CBalloonHelp::s_hookMan.SetKeyboardHook();
m_bKeyboardHook=true;
}
void CBalloonHelp::RemoveKeyboardHook()
{
if (!m_bKeyboardHook){ return; }
CBalloonHelp::s_hookMan.RemoveKeyboardHook();
m_bKeyboardHook=false;
}
void CBalloonHelp::SetMouseHook()
{
if (m_bMouseHook){ return; }
CBalloonHelp::s_hookMan.SetMouseHook();
m_bMouseHook=true;
}
void CBalloonHelp::RemoveMouseHook()
{
if (!m_bMouseHook){ return; }
CBalloonHelp::s_hookMan.RemoveMouseHook();
m_bMouseHook=false;
}
void CBalloonHelp::SetCallWndRetHook()
{
if (m_bCallWndRetHook){ return; }
CBalloonHelp::s_hookMan.SetCallWndRetHook();
m_bCallWndRetHook=true;
}
void CBalloonHelp::RemoveCallWndRetHook()
{
if (!m_bCallWndRetHook){ return; }
CBalloonHelp::s_hookMan.RemoveCallWndRetHook();
m_bCallWndRetHook=false;
}
BEGIN_MESSAGE_MAP(CBalloonHelp, CWnd)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_NCPAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_NCCALCSIZE()
ON_WM_TIMER()
ON_WM_NCHITTEST()
ON_WM_MOUSEMOVE()
ON_WM_DESTROY()
ON_WM_CLOSE()
ON_WM_SHOWWINDOW()
ON_MESSAGE(WM_PRINT, OnPrint)
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
END_MESSAGE_MAP()
void CBalloonHelp::OnShowWindow(BOOL bShow, UINT)
{
if ( NULL != m_fnAnimateWindow )
{
if ( bShow && !(m_unOptions&unDISABLE_FADEIN) )
m_fnAnimateWindow( m_hWnd, 200, AW_BLEND);
else if ( !bShow && !(m_unOptions&unDISABLE_FADEOUT) )
m_fnAnimateWindow( m_hWnd, 200, AW_HIDE | AW_BLEND );
}
}
BOOL CBalloonHelp::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
pDC->FillSolidRect(&rect, m_crBackground);
return TRUE;
}
void CBalloonHelp::OnPaint()
{
CPaintDC dc(this);
DrawClientArea(&dc);
}
void CBalloonHelp::OnNcPaint()
{
CWindowDC dc(this);
DrawNonClientArea(&dc);
}
LRESULT CBalloonHelp::OnPrint(WPARAM wParam, LPARAM lParam)
{
CDC* pDC = CDC::FromHandle((HDC)wParam);
if ( lParam & PRF_NONCLIENT )
DrawNonClientArea(pDC);
return Default();
}
LRESULT CBalloonHelp::OnPrintClient(WPARAM wParam, LPARAM lParam)
{
CDC* pDC = CDC::FromHandle((HDC)wParam);
if ( lParam & PRF_ERASEBKGND )
SendMessage( WM_ERASEBKGND, wParam );
if ( lParam & PRF_CLIENT )
DrawClientArea(pDC);
return 0;
}
void CBalloonHelp::OnLButtonDown(UINT, CPoint point)
{
if (m_unOptions & unSHOW_CLOSE_BUTTON)
{
CRect rect;
GetClientRect(&rect);
rect.left = rect.right-::GetSystemMetrics(SM_CXSIZE);
rect.bottom = rect.top+::GetSystemMetrics(SM_CYSIZE);
if ( rect.PtInRect(point) )
{
m_uCloseState |= DFCS_PUSHED;
SetCapture();
OnMouseMove(0, point);
}
}
}
void CBalloonHelp::OnLButtonUp(UINT, CPoint point)
{
if ( (m_unOptions & unSHOW_CLOSE_BUTTON) && (m_uCloseState & DFCS_PUSHED) )
{
ReleaseCapture();
m_uCloseState &= ~DFCS_PUSHED;
CRect rect;
GetClientRect(&rect);
rect.left = rect.right-::GetSystemMetrics(SM_CXSIZE);
rect.bottom = rect.top+::GetSystemMetrics(SM_CYSIZE);
if ( rect.PtInRect(point) )
HideBalloon();
}
else if ( !m_strURL.IsEmpty() )
{
CRect rect;
GetClientRect(&rect);
if ( rect.PtInRect(point) )
{
::ShellExecute(NULL, NULL, m_strURL, NULL, NULL, SW_SHOWNORMAL);
HideBalloon();
}
}
}
LRESULT CBalloonHelp::OnNcHitTest(CPoint)
{
return HTCLIENT;
}
void CBalloonHelp::OnMouseMove(UINT, CPoint point)
{
if (m_unOptions & unSHOW_CLOSE_BUTTON)
{
CRect rect;
GetClientRect(&rect);
rect.left = rect.right-::GetSystemMetrics(SM_CXSIZE);
rect.bottom = rect.top+::GetSystemMetrics(SM_CYSIZE);
CClientDC dc(this);
UINT uState = DFCS_CAPTIONCLOSE;
BOOL bPushed = m_uCloseState&DFCS_PUSHED;
m_uCloseState &= ~DFCS_PUSHED;
if ( rect.PtInRect(point) )
{
uState |= DFCS_HOT;
if ( bPushed )
uState |= DFCS_PUSHED;
}
else
{
uState |= DFCS_FLAT;
}
if ( uState != m_uCloseState )
{
dc.DrawFrameControl(&rect, DFC_CAPTION, uState);
m_uCloseState = uState;
}
if ( bPushed )
m_uCloseState |= DFCS_PUSHED;
}
}
void CBalloonHelp::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
::InflateRect(&lpncsp->rgrc[0], -nTIP_MARGIN,-nTIP_MARGIN);
switch ( GetBalloonQuadrant() )
{
case BQ_TOPRIGHT:
case BQ_TOPLEFT:
lpncsp->rgrc[0].top += nTIP_TAIL;
break;
case BQ_BOTTOMRIGHT:
case BQ_BOTTOMLEFT:
lpncsp->rgrc[0].bottom -= nTIP_TAIL;
break;
}
if ( lpncsp->rgrc[0].right < lpncsp->rgrc[0].left )
lpncsp->rgrc[0].right = lpncsp->rgrc[0].left;
if ( lpncsp->rgrc[0].bottom < lpncsp->rgrc[0].top )
lpncsp->rgrc[0].bottom = lpncsp->rgrc[0].top;
if ( bCalcValidRects )
{
if ( !::EqualRect(&lpncsp->rgrc[0], &lpncsp->rgrc[2]) )
{
::SetRectEmpty(&lpncsp->rgrc[2]);
}
}
}
void CBalloonHelp::OnTimer(UINT_PTR nIDEvent)
{
if ( nIDEvent == ID_TIMER_CLOSE )
{
KillTimer(m_unTimerClose);
HideBalloon();
}
}
void CBalloonHelp::OnDestroy()
{
RemoveMouseHook();
RemoveKeyboardHook();
RemoveCallWndRetHook();
CWnd::OnDestroy();
}
void CBalloonHelp::OnClose()
{
HideBalloon();
}
void CBalloonHelp::PostNcDestroy()
{
CWnd::PostNcDestroy();
if ( m_unOptions & unDELETE_THIS_ON_CLOSE )
delete this;
}
LRESULT CBalloonHelp::KeyboardHookProc( int code, WPARAM wParam, LPARAM lParam)
{
if ( code>=0 && !(lParam&0x80000000) && NULL != m_hWnd )
{
PostMessage(WM_CLOSE);
}
return 0;
}
LRESULT CBalloonHelp::MouseHookProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code>=0 && NULL != m_hWnd )
{
switch ( (UINT)wParam )
{
case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE:
if ((m_unOptions & unCLOSE_ON_MOUSE_MOVE))
{
CPoint pt;
::GetCursorPos(&pt);
if ((abs(pt.x-m_ptMouseOrig.x) > m_nMouseMoveToleranceX || abs(pt.y-m_ptMouseOrig.y) > m_nMouseMoveToleranceY) ){
PostMessage(WM_CLOSE);
return 1;
}
}
break;
case WM_NCLBUTTONDOWN:
case WM_LBUTTONDOWN:
if ((m_unOptions & unCLOSE_ON_LBUTTON_DOWN)){
PostMessage(WM_CLOSE);
return 1;
}
break;
case WM_NCMBUTTONDOWN:
case WM_MBUTTONDOWN:
if ((m_unOptions & unCLOSE_ON_MBUTTON_DOWN)){
PostMessage(WM_CLOSE);
return 1;
}
break;
case WM_NCRBUTTONDOWN:
case WM_RBUTTONDOWN:
if ((m_unOptions& unCLOSE_ON_RBUTTON_DOWN)){
PostMessage(WM_CLOSE);
return 1;
}
break;
case WM_NCLBUTTONUP:
case WM_LBUTTONUP:
if ((m_unOptions & unCLOSE_ON_LBUTTON_UP)){
PostMessage(WM_CLOSE);
return 1;
}
break;
case WM_NCMBUTTONUP:
case WM_MBUTTONUP:
if ((m_unOptions & unCLOSE_ON_MBUTTON_UP)){
PostMessage(WM_CLOSE);
return 1;
}
break;
case WM_NCRBUTTONUP:
case WM_RBUTTONUP:
if ((m_unOptions & unCLOSE_ON_RBUTTON_UP)){
PostMessage(WM_CLOSE);
return 1;
}
break;
}
}
return 0;
}
LRESULT CBalloonHelp::CallWndRetProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code>=0 && NULL != m_hWnd )
{
CWPRETSTRUCT* pcwpr = (CWPRETSTRUCT*)lParam;
if ( WM_MOVE == pcwpr->message && pcwpr->hwnd == m_hwndAnchor )
PositionWindow();
}
return 0;
}
CBalloonHelp::HookMan::HookMan()
{
m_hKeyboardHook = NULL;
m_hMouseHook = NULL;
m_hCallWndRetHook = NULL;
m_nCountKeyboard = 0;
m_nCountMouse = 0;
m_nCountCallWnd = 0;
}
CBalloonHelp::HookMan::~HookMan()
{
while(m_nCountKeyboard > 0){ RemoveKeyboardHook(); }
while(m_nCountMouse > 0){ RemoveMouseHook(); }
while(m_nCountCallWnd > 0){ RemoveCallWndRetHook(); }
m_hKeyboardHook = NULL;
m_hMouseHook = NULL;
m_hCallWndRetHook = NULL;
}
void CBalloonHelp::HookMan::AddClass(CBalloonHelp* pClass)
{
RemoveClass(pClass);
CSingleLock monCS(&m_cs);
m_lstClasses.push_front(pClass);
}
void CBalloonHelp::HookMan::RemoveClass(CBalloonHelp* pClass)
{
CSingleLock monCS(&m_cs);
std::list<CBalloonHelp*>::iterator itrEnd = m_lstClasses.end();
for (std::list<CBalloonHelp*>::iterator itr = m_lstClasses.begin(); itr != itrEnd; ){
if (*itr == pClass){ itr = m_lstClasses.erase(itr); }
else{ itr++; }
}
}
void CBalloonHelp::HookMan::SetKeyboardHook()
{
CSingleLock monCS(&m_cs);
m_nCountKeyboard++;
if ( NULL==m_hKeyboardHook )
{
m_hKeyboardHook = ::SetWindowsHookEx(WH_KEYBOARD,KeyboardHookProcStatic, NULL, ::GetCurrentThreadId());
}
}
void CBalloonHelp::HookMan::RemoveKeyboardHook()
{
CSingleLock monCS(&m_cs);
m_nCountKeyboard--;
if (m_nCountKeyboard <= 0 && NULL != m_hKeyboardHook){
::UnhookWindowsHookEx(m_hKeyboardHook);
m_hKeyboardHook=NULL;
m_nCountKeyboard=0;
}
}
void CBalloonHelp::HookMan::SetMouseHook()
{
CSingleLock monCS(&m_cs);
m_nCountMouse++;
if ( NULL==m_hMouseHook )
{
m_hMouseHook = ::SetWindowsHookEx(WH_MOUSE,MouseHookProcStatic, NULL, ::GetCurrentThreadId());
}
}
void CBalloonHelp::HookMan::RemoveMouseHook()
{
CSingleLock monCS(&m_cs);
m_nCountMouse--;
if (m_nCountMouse <= 0 && NULL != m_hMouseHook){
::UnhookWindowsHookEx(m_hMouseHook);
m_hMouseHook=NULL;
m_nCountMouse=0;
}
}
void CBalloonHelp::HookMan::SetCallWndRetHook()
{
CSingleLock monCS(&m_cs);
m_nCountCallWnd++;
if ( NULL==m_hCallWndRetHook )
{
m_hCallWndRetHook = ::SetWindowsHookEx(WH_CALLWNDPROCRET, CallWndRetProcStatic, NULL, ::GetCurrentThreadId());
}
}
void CBalloonHelp::HookMan::RemoveCallWndRetHook()
{
CSingleLock monCS(&m_cs);
m_nCountCallWnd--;
if (m_nCountCallWnd <= 0 && NULL != m_hCallWndRetHook){
::UnhookWindowsHookEx(m_hCallWndRetHook);
m_hCallWndRetHook=NULL;
m_nCountCallWnd=0;
}
}
LRESULT CALLBACK CBalloonHelp::HookMan::KeyboardHookProcStatic( int code, WPARAM wParam, LPARAM lParam)
{
try{
CSingleLock monCS(&CBalloonHelp::s_hookMan.m_cs);
try{
std::list<CBalloonHelp*>::iterator itrEnd = CBalloonHelp::s_hookMan.m_lstClasses.end();
for (std::list<CBalloonHelp*>::iterator itr = CBalloonHelp::s_hookMan.m_lstClasses.begin(); itr != itrEnd; itr++){
try{ if (((CBalloonHelp*)(*itr))->KeyboardHookProc(code, wParam, lParam)){ break; } }catch(...){}
}
}catch(...){}
if (NULL != CBalloonHelp::s_hookMan.m_hKeyboardHook){ return ::CallNextHookEx(CBalloonHelp::s_hookMan.m_hKeyboardHook, code, wParam, lParam); }
}catch(...){}
return 0;
}
LRESULT CALLBACK CBalloonHelp::HookMan::MouseHookProcStatic(int code, WPARAM wParam, LPARAM lParam)
{
try{
CSingleLock monCS(&CBalloonHelp::s_hookMan.m_cs);
try{
std::list<CBalloonHelp*>::iterator itrEnd = CBalloonHelp::s_hookMan.m_lstClasses.end();
for (std::list<CBalloonHelp*>::iterator itr = CBalloonHelp::s_hookMan.m_lstClasses.begin(); itr != itrEnd; itr++){
try{ if (((CBalloonHelp*)(*itr))->MouseHookProc(code, wParam, lParam)){ break; } }catch(...){}
}
}catch(...){}
if (NULL != CBalloonHelp::s_hookMan.m_hMouseHook){ return ::CallNextHookEx(CBalloonHelp::s_hookMan.m_hMouseHook, code, wParam, lParam); }
}catch(...){}
return 0;
}
LRESULT CALLBACK CBalloonHelp::HookMan::CallWndRetProcStatic(int code, WPARAM wParam, LPARAM lParam)
{
try{
CSingleLock monCS(&CBalloonHelp::s_hookMan.m_cs);
try{
std::list<CBalloonHelp*>::iterator itrEnd = CBalloonHelp::s_hookMan.m_lstClasses.end();
for (std::list<CBalloonHelp*>::iterator itr = CBalloonHelp::s_hookMan.m_lstClasses.begin(); itr != itrEnd; itr++){
try{ if (((CBalloonHelp*)(*itr))->CallWndRetProc(code, wParam, lParam)){ break; } }catch(...){}
}
}catch(...){}
if (NULL != CBalloonHelp::s_hookMan.m_hCallWndRetHook){ return ::CallNextHookEx(CBalloonHelp::s_hookMan.m_hCallWndRetHook, code, wParam, lParam); }
}catch(...){}
return 0;
}
CBalloonHelp::HookMan CBalloonHelp::s_hookMan;
End.
|