我已经受不了了,当一个软件有时会弹出对话框,可以忍,但是如果一个软件时不时的弹窗,你是不是会有一种冲动--"杀死"它.
我说的是ORCAD LAYOUT的窗口,下面有图为证:这个窗口进程名叫lsession.exe,每次打开图档都有
,这个每隔几分钟就提示一次,带提示声音,不过可以设定掉
这个是打开时碰到
这个也是打开时偶尔碰到
那如何杀死它呢,
第一种方法,:关掉它.
第二种方法,不使用它.
第三种方法:念"咒语",用指令,用代码片段杀.
下面就开始摆道场了.
首先见人说人话,见鬼说鬼话,不同的窗口,用不同的方式招待.
1.对于Orcad Layout窗口,就可以发送WM_CLOSE消息:SendMessage( hwndOrcadLayout,WM_CLOSE,0,0 ),或者直接让它隐身:ShowWindow(hwndOrcadLayout,SW_HIDE),但是不管你是用什么方法,最终它的进程lsession.exe始终在后台运行的,所以不会影响软件的使用.
2.对于关闭按钮失效的窗口,法术失灵了,怎么办呢?看不是还有按钮!于是我们可以发按键消息: SendMessage(hwndLayoutPlus, WM_COMMAND, idChildButton,0);
有了核心方法,接下来就是如何实现它.
我们要时时扫描窗口,查找我们想要的那个,取得窗口句柄,或者按钮ID.这就要请出
BOOL EnumWindows(WNDENUMPROC EnumWindowsProc,LPARAM lParam);
BOOL EnumChildWindows(HWND hWndParent,WNDENUMPROC EnumChildProc,LPARAM lParam);
前者用于扫描主窗口,后者用于扫描子窗口,在WNDENUMPROC回调函数中取得窗口的标题,然后通过标题的对比,找到那个窗口.
回调函数的原型如下:
BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam);
第一个参数是不断扫描到的窗口,第二个参数是用户自定义的参数( 我用它来传递类的this指针)
我们可以在此函数里调用GetWindowText(hwnd,lpszWindowTitle),来取得窗口的标题.
这就引出了一个问题:标题的查找是不是全部字符都要匹配?
这就是为什么不用
FindWindow( NULL,lpszParent );
FindWindowEx(m_hParent,NULL,NULL,lpszChild );
这两个函数的原因,因它是全字匹配的,也就是我要实现的是模糊匹配区分大小写查找标题
得到了标题,就动手写个模糊比较函数吧
inline bool isTextInStr(TCHAR* text,TCHAR *str) //查找str中是否含有text,如果有返回true,否则返回false;严格 区分大小写
{
const int lenStr=lstrlen(str);
const int lenText=lstrlen(text);
bool bFound=false;
TCHAR *lpszSubStr=new TCHAR[ lenText+2];
for(int i=0;i<=lenStr-lenText;++i)
{
lstrcpyn( lpszSubStr ,&str[i], lenText+1);
if( 0==lstrcmp( lpszSubStr,text ) )//equal found return zero//严格 区分大小写
{
bFound=true;
break;
}
}
if( lpszSubStr!=0 )
{
delete []lpszSubStr;
lpszSubStr=0;
}
return bFound;
}
接下我们要开始封装一个类 WindowKiller ,这就又引出了另一个问题: 像 EnumWindowsProc() 这样的CALLBACK函数是不能作为成员函数的.深入的会涉及到thunk技术的东西,算了还是降低点难度:把这样的函数写成静态成员函数:
static BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM p_this)
调用时使用
EnumWindows( EnumWindowsProc,reinterpret_cast<LPARAM>(this) );将参数转化为this指针;
然后在EnumWindowsProc()中再变回来 WindowKiller *pthis=reinterpret_cast<WindowKiller*>(p_this);
于是我们可以想象它是这样工作的:查找所有的窗口,检查它们的标题,列举子窗口,找到后,发送消息,以一种温柔的方式"杀掉"它
//WindowKiller类
//by wisepragma
//软件与代码版权所有,仅用于个人测试学习用途,作者不对使用本软件与代码产生的任何结果负责
//HOMEPAGE:http://blog.csdn.net/wisepragma
#pragma once
enum ACTION
{
ACTION_NULL,ACTION_PRESSBUTTON_BYID,ACTION_SHOW_WIN,ACTION_HIDE_WIN,ACTION_HIDE_WIN_CHILD,ACTION_SHOW_WIN_CHILD,ACTION_CLOSE_WIN,ACTION_CLOSE_WIN_CHILD,ACTION_PRESSBUTTON_BYTXT
};
struct WININFO
{
HWND hwnd;
TCHAR *title;
UINT id;
};
struct ACTIONINFO
{
bool bEnable;
ACTION act;
WININFO parent,child,button;
};
struct rule
{
ACTIONINFO actinfo;
rule *next;
public:
rule(ACTION act=ACTION_NULL,TCHAR *lpszParent=NULL,TCHAR* lpszChild=NULL,TCHAR *lpszButtonText=NULL,UINT idButton=0,bool bEnable=true)
{
memset(&actinfo,0,sizeof(actinfo));
next=NULL;
actinfo.act=act;
actinfo.parent.title=lpszParent;
actinfo.child.title=lpszChild;
actinfo.button.title=lpszButtonText;
actinfo.button.id=idButton;
actinfo.bEnable=bEnable;
}
};
class WindowKiller
{
private:
public:
rule *head,*tail;
WindowKiller()
{
head=NULL;
tail=NULL;
}
~WindowKiller()
{
while(NULL!=head)
{
rule *index=head;
head=head->next;
delete index;
//error
// rule *index=head;
//delete head;//不要走到马路中间再看两边有没有车
//head=index->next;//不能先拆桥再过河
}
}
void addrule(ACTION act=ACTION_NULL,TCHAR *lpszParent=NULL,TCHAR* lpszChild=NULL,TCHAR *lpszButtonText=NULL,UINT idButton=0)
{
rule *index=new rule(act,lpszParent,lpszChild,lpszButtonText,idButton);
if(NULL==head)
{
head=index;
tail=head;
}
else
{
tail->next=index;
tail=index;
}
}
void action()
{
EnumWindows( EnumWindowsProc,reinterpret_cast<LPARAM>(this) );
}
static BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM p_this)
{
WindowKiller *pthis=reinterpret_cast<WindowKiller*>(p_this);
TCHAR lpszWinTitle[MAX_PATH]={0};
::GetWindowText(hwnd,lpszWinTitle,MAX_PATH);
rule *index=pthis->head;
while(NULL!= index)
{
if( pthis->isTextInStr( index->actinfo.parent.title,lpszWinTitle) )
{
index->actinfo.parent.hwnd=hwnd;
if(index->actinfo.bEnable)
{
switch(index->actinfo.act)
{
case ACTION_HIDE_WIN:
::ShowWindow(hwnd,SW_HIDE);
break;
case ACTION_SHOW_WIN:
::ShowWindow(hwnd,SW_SHOW);
break;
case ACTION_CLOSE_WIN:
::SendMessage(hwnd,WM_CLOSE,0,0);
break;
case ACTION_HIDE_WIN_CHILD:
case ACTION_SHOW_WIN_CHILD:
case ACTION_PRESSBUTTON_BYTXT:
case ACTION_PRESSBUTTON_BYID:
case ACTION_CLOSE_WIN_CHILD:
EnumChildWindows(hwnd, &WindowKiller::EnumChildProc, (LPARAM)pthis);
break;
}
}
}
index=index->next;
}
return TRUE;
}
static BOOL CALLBACK EnumChildProc(HWND hwndChild,LPARAM p_this)
{
WindowKiller *pthis=reinterpret_cast<WindowKiller*>(p_this);
TCHAR lpszChildText[MAX_PATH];
::GetWindowText(hwndChild,lpszChildText,MAX_PATH);
rule *index=pthis->head;
while(NULL!= index)
{
if(index->actinfo.bEnable)
{
switch(index->actinfo.act)
{
case ACTION_SHOW_WIN_CHILD:
if( pthis->isTextInStr( index->actinfo.child.title,lpszChildText) )
{
index->actinfo.child.hwnd=hwndChild;
if(NULL!=index->actinfo.parent.hwnd)::ShowWindow(index->actinfo.parent.hwnd,SW_SHOW);
}
break;
case ACTION_HIDE_WIN_CHILD:
if( pthis->isTextInStr( index->actinfo.child.title,lpszChildText) )
{
index->actinfo.child.hwnd=hwndChild;
if(NULL!=index->actinfo.parent.hwnd)::ShowWindow(index->actinfo.parent.hwnd,SW_HIDE);
}
break;
case ACTION_PRESSBUTTON_BYTXT:
if( pthis->isTextInStr( index->actinfo.button.title,lpszChildText) )
{
index->actinfo.button.hwnd=hwndChild;
}
if( pthis->isTextInStr( index->actinfo.child.title,lpszChildText) ) //equal return zero
{
if(NULL!=index->actinfo.parent.hwnd &&
NULL!=index->actinfo.button.hwnd )
{
UINT idChild=::GetDlgCtrlID(index->actinfo.button.hwnd);
SendMessage( index->actinfo.parent.hwnd, WM_COMMAND, idChild,0); //
}
}
break;
case ACTION_PRESSBUTTON_BYID:
if( pthis->isTextInStr( index->actinfo.child.title,lpszChildText) ) //equal return zero
{
if( NULL!=index->actinfo.parent.hwnd )
{
SendMessage( index->actinfo.parent.hwnd,WM_COMMAND,index->actinfo.button.id,0 ); //(WPARAM)(BN_CLICKED<<16) |
}
}
break;
case ACTION_CLOSE_WIN_CHILD:
if( pthis->isTextInStr( index->actinfo.child.title,lpszChildText) )
{
index->actinfo.child.hwnd =hwndChild;
if(NULL!=index->actinfo.parent.hwnd )SendMessage( index->actinfo.parent.hwnd,WM_CLOSE,0,0 );
}
break;
}
}
index=index->next;
}
return TRUE;
}
///
inline bool isTextInStr(TCHAR* text,TCHAR *str) //查找str中是否含有text,如果有返回true,否则返回false;严格 区分大小写
{
const int lenStr=lstrlen(str);
const int lenText=lstrlen(text);
bool bFound=false;
TCHAR *lpszSubStr=new TCHAR[ lenText+2];
for(int i=0;i<=lenStr-lenText;++i)
{
lstrcpyn( lpszSubStr ,&str[i], lenText+1);
if( 0==lstrcmp( lpszSubStr,text ) )//equal found return zero//严格 区分大小写
{
bFound=true;
break;
}
}
if( lpszSubStr!=0 )
{
delete []lpszSubStr;
lpszSubStr=0;
}
return bFound;
}
};
最后的工程中加入定时器,每隔一时间扫描一次窗口
在程序初始化时加入
SetTimer(1,100,NULL);
killer.addrule(ACTION_PRESSBUTTON_BYTXT,TEXT("Layout Plus"),TEXT("This job's netlist has changed.") ,TEXT("否(&N)") );
//killer.addrule(ACTION_HIDE_WIN,TEXT("OrCAD Layout"));//方式1
killer.addrule(ACTION_CLOSE_WIN,TEXT("OrCAD Layout"));//方式2
killer.addrule(ACTION_PRESSBUTTON_BYTXT,TEXT("Layout Plus"),TEXT("Unable to write backup."),TEXT("确定"));
killer.addrule(ACTION_PRESSBUTTON_BYTXT,TEXT("Layout Plus"),TEXT("Enter new name?") ,TEXT("否") );
最后还在工程中加入了托盘图标及右键菜单,这是整个软件可以看得见的东西,还加入注册表修改自启动
软件运行时的提示是这样子的 右键菜单是这样子的
软件示例及完整代码:下载页面