对于一般窗口来说,使用 @唐仕强 的方法就可以搞定,但因为Windows shell不支持MOUSELEAVE消息,所以需要自己来实现,一种方法就像 @唐仕强 所描述的,安装SHellNotify(托盘)窗口的消息钩子来实现。
另外一种是通过线程轮询来实现,思路很简单,如下:
在WM_MOUSEMOVE中保存鼠标的位置,然后启动线程比较当前的鼠标位置与你记录的鼠标位置进行比较,如果不同,就发送鼠标离开消息。

traypos.h

   
  #ifndef TRAYPOS_H
  
#define TRAYPOS_H

class CTrayPos
{
private:
POINT m_ptMouse;


HANDLE m_hThread;
HANDLE m_hExitEvent;

BOOL m_bTrackMouse;

CRITICAL_SECTION m_cs;


public:
CTrayPos();
virtual ~CTrayPos();

static UINT CALLBACK TrackMousePt(PVOID pvClass);
VOID OnMouseMove();
BOOL IsMouseHover();

protected:
virtual VOID OnMouseHover() = 0;
virtual VOID OnMouseLeave() = 0;
};

class CMsgTrayPos : public CTrayPos
{
private:
HWND m_hNotifyWnd;
UINT m_uID;
UINT m_uCallbackMsg;

public:
CMsgTrayPos(HWND hwnd=NULL, UINT uID=0, UINT uCallbackMsg=0);
~CMsgTrayPos();

VOID SetNotifyIconInfo(HWND hwnd, UINT uID, UINT uCallbackMsg);

protected:
VOID OnMouseHover();
VOID OnMouseLeave();
};

#endif

traypos.cpp

   
  #include "stdafx.h"
  
#include <commctrl.h>
#include <process.h>

#include "traypos.h"
#include "resource.h"

CTrayPos::CTrayPos()
{
UINT uThreadId;

m_bTrackMouse = FALSE;
m_hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hThread = (HANDLE) _beginthreadex(NULL, 0, CTrayPos::TrackMousePt, this, 0, &uThreadId;);
InitializeCriticalSection(&m;_cs);
}

CTrayPos::~CTrayPos()
{
if(m_hThread != NULL)
{
SetEvent(m_hExitEvent);
if(WaitForSingleObject(m_hThread, 5000) == WAIT_TIMEOUT)
{
TerminateThread(m_hThread, 0);
}

CloseHandle(m_hThread);
m_hThread = NULL;
}

if(m_hExitEvent != NULL)
{
CloseHandle(m_hExitEvent);
m_hExitEvent = NULL;
}

DeleteCriticalSection(&m;_cs);
}

UINT CALLBACK CTrayPos::TrackMousePt(PVOID pvClass)
{
POINT ptMouse;
CTrayPos *pTrayPos = (CTrayPos *) pvClass;

while(WaitForSingleObject(pTrayPos->m_hExitEvent, 2000) == WAIT_TIMEOUT)
{

if(pTrayPos->m_bTrackMouse == TRUE)
{
GetCursorPos(&ptMouse;);

if(ptMouse.x != pTrayPos->m_ptMouse.x || ptMouse.y != pTrayPos->m_ptMouse.y)
{
pTrayPos->m_bTrackMouse = FALSE;
pTrayPos->OnMouseLeave();
}
}
}

return 0;
}

VOID CTrayPos::OnMouseMove()
{
EnterCriticalSection(&m;_cs);

GetCursorPos(&m;_ptMouse);
if(m_bTrackMouse == FALSE)
{
OnMouseHover();
m_bTrackMouse = TRUE;
}

LeaveCriticalSection(&m;_cs);
}

BOOL CTrayPos::IsMouseHover()
{
return m_bTrackMouse;
}

//////////////////////////////////////////////////////////////////////////

CMsgTrayPos::CMsgTrayPos(HWND hwnd, UINT uID, UINT uCallbackMsg)
: CTrayPos()
{
SetNotifyIconInfo(hwnd, uID, uCallbackMsg);
}

CMsgTrayPos::~CMsgTrayPos()
{
}

VOID CMsgTrayPos::SetNotifyIconInfo(HWND hwnd, UINT uID, UINT uCallbackMsg)
{
m_hNotifyWnd = hwnd;
m_uID = uID;
m_uCallbackMsg = uCallbackMsg;
}

VOID CMsgTrayPos::OnMouseHover()
{
if(m_hNotifyWnd != NULL && IsWindow(m_hNotifyWnd))
PostMessage(m_hNotifyWnd, m_uCallbackMsg, m_uID, WM_MOUSEHOVER);
}

VOID CMsgTrayPos::OnMouseLeave()
{
if(m_hNotifyWnd != NULL && IsWindow(m_hNotifyWnd))
PostMessage(m_hNotifyWnd, m_uCallbackMsg, m_uID, WM_MOUSELEAVE);
}

我上头有神 answered 12 years, 3 months ago

Your Answer