为什么写这个:
1,像我这么爱干净的人,当然不能容忍和MM聊天的时候,看到一个内衣广告在上面一闪一闪,这不引诱老纳么;
2,为什么不用其它外挂?珊瑚虫已S,再没用过其它。现有的外挂实现了一些我不想要的功能,看IP也没必要,聊天的都是熟人。另外,不知道它做了些什么事情;
3,打发这个无聊的周末。
怎样实现:
1,万能的HOOK
现在用到的是全局的SHELL HOOK,Hook的是窗口创建完成的消息;
g_hShellHook = SetWindowsHookEx( WH_SHELL,
(HOOKPROC)ShellHook,
g_hInstance,
0);
ShellHook 的实现如下:
static LRESULT CALLBACK ShellHook(UINT nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)
goto CallOrg;
if( HSHELL_WINDOWCREATED == nCode )
{
if( !isQQWnd( (HWND)wParam ) )
goto CallOrg;
EnumChildWindows( (HWND)wParam, EnumChildProc, (LPARAM)0 );
}
CallOrg:
return CallNextHookEx( g_hShellHook, nCode, wParam, lParam);
}
在收到窗口创建后的消息时,就判断这个窗口是不是QQ的,这里用到了 GetWindowThreadProcessId ,它返回窗口相关的进程ID
BOOL isQQWnd(HWND hWnd)
{
if( g_pContext == NULL )
return FALSE;
if( g_dwQQProcessID == 0 )
g_dwQQProcessID = GetQQProcessID();
DWORD dwWndProcessID;
if( GetWindowThreadProcessId( hWnd, &dwWndProcessID ) == 0 )
return FALSE;
return dwWndProcessID == g_dwQQProcessID;
}
然后枚举它的子窗口,看它的子窗口有没有广告控件,有的话就给子控件发送个WM_CLOSE的消息.
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam )
{
DWORD dwID = GetDlgCtrlID( hwnd );
if( dwID == 0x3e9 )
{
HWND hPrarent = GetParent( hwnd );
PostMessage(hwnd, WM_CLOSE, 0, 0 );
Sleep( 10 );
PostMessage(hPrarent, WM_PAINT, 0, 0 );
}
else if( dwID == 0x643f )
{
PostMessage(hwnd, WM_CLOSE, 0, 0 );
}
return TRUE;
}
其中的两个硬编码是用 spy++ 分析出来的,可能因为版本的不同,会有差异。所以我不确定能不能关闭其它版本的QQ广告。我使用的版本是QQ2008贺岁版。
--------------------------------------------------------------------------
后记:
尽管实现的技术很简单,但还是花了我大半天的时间. 写完之后觉得枚举子窗口的方式太低效, 或者还有其它高效点的方式。另外还有全局钩子,可能没有必要。如果下午周末持续无聊,我会尝试改进一下。
QQ的聊天对话框很简单,不像MSN的对话框,铁板一块,用spy++啥都看不到.但是可以用 AccExplorer 分析.想在MSN的对话框上加点东西进去,实现起来很困难。对这方面有研究的同学不妨与我讨论一下实现,一起学习、进步。
代码的行数没数,有效代码估计也就百把行吧,呵呵,我承认我是标题党。
附: 源代码 + bin