一种在注入进程中使用WTL创建无焦点不在任务栏出现“吸附”窗口的方法和思路(二)

2014-11-24 11:21:31 · 作者: · 浏览: 2
IndowsHookEx WH_CALLWNDPROCRET),此时我们无法让我们窗口显示在被注入进程顶层窗口前面。方法2就是比方法1多出线程数,如果我想创建两个窗口,就多出两个窗口线程,以此类推。如我设想的需求,我将创建一个管理外框异形空心窗口的线程和一个“标题”窗口,那就多出两个线程。

我觉得我这两个窗口要处理的消息非常简单,同样也想做点与众不同。于是我设计了这样的方案,方案是融合了方案1和方案2的优点:

SetWindowsHookEx勾住被注入进程的消息,同时设置Hook类型为WH_CALLWNDPROCRET。

[cpp]
VOID HookWindowsFn()
{
do {
g_hhook = SetWindowsHookEx( WH_CALLWNDPROCRET, CallWndRetProc, NULL, GetCurrentThreadId() );
if ( NULL == g_hhook ) {
_ASSERT(FALSE);
}

InitializeCriticalSection( &g_cs );
} while (0);
}
这样我们将在原程序处理完消息后进行消息处理。

[cpp]
LRESULT CALLBACK CallWndRetProc( __in int nCode, __in WPARAM wParam, __in LPARAM lParam )
{
if ( NULL != lParam ) {
LPCWPRETSTRUCT lptagCWPRETSTRUCT = (LPCWPRETSTRUCT)lParam;
DealMsg( lptagCWPRETSTRUCT->hwnd, lptagCWPRETSTRUCT->message, lptagCWPRETSTRUCT->wParam, lptagCWPRETSTRUCT->lParam );
}

return CallNextHookEx(NULL, nCode, wParam, lParam);
}
当我们收到消息时,我们要判断是否是我们关心的消息,这样将减少我们处理消息的线程的工作量。
[cpp]
BOOL IsNeedDealMsg( UINT uMsg )
{
return ( IsNeedShowMsg( uMsg )
|| ( WM_DESTROY == uMsg )
|| ( WM_CLOSE == uMsg ) );
}

BOOL IsNeedShowMsg( UINT uMsg )
{
return ( ( WM_SHOWWINDOW == uMsg )
|| ( WM_MOVE == uMsg )
|| ( WM_MOVING == uMsg )
|| ( WM_SIZE == uMsg )
|| ( WM_WINDOWPOSCHANGED == uMsg )
);
}
[cpp]
VOID DealMsg( HWND hAttachedWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if ( FALSE == IsNeedDealMsg( uMsg ) ) {
return;
}
其次判断该窗口是否为我们自己创建的“吸附”窗口。如果是我们的“吸附”窗口,我们将不会做任何处理。

[cpp]
VOID DealMsg( HWND hAttachedWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if ( IsHelperWindow( hAttachedWnd ) ) {
return;
}
[cpp] view plaincopy
BOOL IsHelperWindow( HWND hwnd )
{
WCHAR wszClassNameBuffer[MAX_PATH] = {0};
int nClassNameLength = GetClassName( hwnd , wszClassNameBuffer, MAX_PATH - 1 );
if ( 0 != nClassNameLength ) {
std::wstring wszClassName = wszClassNameBuffer;
if ( 0 == wcscmp( wszClassNameBuffer, TITILEWINDOWCLASS ) ||
0 == wcscmp( wszClassNameBuffer, OUTSIDEWINDOWCLASS ) ) {
return TRUE; // 通过类名判断
}
}

return FALSE;
}
然后我们需要根据消息类型,对窗口句柄做个判断。因为如果我们“宿主”窗口处理完WM_DESTROY后,我们再将不能对其调用GetWindowLong以获取其样式。于是对WM_DESTORY消息,我们只是判断其是否为顶层窗口。如果不是该消息,我们将判断该窗口是否为顶层窗口,且其窗口样式包含WS_SYSMENU(我试验了下,我所遇到的我认为该处理的窗口都有该属性,这个属于经验之谈,不一定准确)。

[cpp]
if ( WM_DESTROY != uMsg ) {
if ( FALSE == IsValibleWindow( hAttachedWnd ) ) {
return;
}
}
else {
if ( FALSE == IsBaseWindow(hAttachedWnd) ) {
return;
}
}

if ( FALSE == IsNeedDealMsg( uMsg ) ) {
return;
}
[cpp]
BOOL IsValibleWindow( HWND hWnd )
{
if ( FALSE == IsBaseWindow( hWnd ) )
{
return FALSE;
}

DWORD dwStyle = ::GetWindowLong( hWnd, GWL_STYLE );
if ( !( WS_SYSMENU & dwStyle ) ) {
return FALSE;
}

return TRUE;
}

BOOL IsTopWindow( HWND hwnd )
{
BOOL bTop = FALSE;
do {
HWND hParentHwnd = NULL;
HWND hParenthwnd = GetParent( hwnd );
if ( NULL == hParenthwnd ){
bTop = TRUE;
}
} while (0);
return bTop;
}

BOOL IsBaseWindow( HWND hWnd )
{
if ( FALSE == ::IsWindow(hWnd)
|| FALSE == IsTopWindow(hWnd) )
{
return FAL