这两天一直在跟这东东较劲,今天终于有了点结果。
其实思路很简单:第一步找到Message的窗口句柄,第二步关掉它。
找句柄有若干的方法,这两天重点研究的是FindWindowEx() 和 GetLastActivePopup()。各有利弊。后述。
关窗口也有若干方法。可以发送WM_CLOSE/调用CloseWindow(), 发送WM_DESTROY/DestroyWindow(),PoseMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDCANCEL,BN_CLICKED) , (LPARAM)::GetDlgItem( hWnd ,IDCANCEL ) )(发送点击button事件。根据Messagebox类型改变ID),以及EndDialog()实现。
CloseWindow()最不好用。因为它实际上只是将Messageox最小化了,并没有真正销毁。
DestroyWindo()虽然销毁了Messagebox,却没有重新激活其父窗口。在多窗口的时候会造成界面的混乱。
模拟点击Button比较万能,因为可以实现不同的逻辑效果,只是有点麻烦。
EndDialog最好用,能够安全地干掉Messagebox,并且模拟返回值(第二个参数)。
下面是查找句柄的两个例程:
一、使用GetLastActivePopup()。
前提条件:需要知道父窗口。
优点:简单明了。
缺陷:当焦点不在MessageBox上时无法将其关闭。
void DestroyMsg(HWND parent)
{
if (parent)
{
HWND hWnd = GetLastActivePopup( parent ) ; //查找激活的MessageBox
if (hWnd)
{
EndDialog( hWnd, 0 ) ;
}
}
}
二、使用FindWindowEx()。
前提条件:MessageBox的标题和内容
优点:可以找到任意MessageBox。
缺点:代码长,消耗资源大。
static BOOL CALLBACK EnumCommonProc( HWND hwnd, LPARAM lParam )
{
stMsgFeature* pstMsg = (stMsgFeature*)lParam ;
char szQuestionMsg[255] = { 0 } ;
GetWindowText( hwnd , szQuestionMsg , 255 ) ;
if ( ( strcmp( pstMsg->pszContent , szQuestionMsg ) == 0 ) )
{
// found , and exit enum
pstMsg->bFound = true ;
return false ;
}
return true ;
}
bool IsMsgWnd ( HWND hWnd , char* pszContent )
{
stMsgFeature stMsg ;
stMsg.pszContent = pszContent ;
stMsg.bFound = false ;
EnumChildWindows( hWnd,
EnumCommonProc,
LPARAM(&stMsg)) ;
return stMsg.bFound ;
}
void DestroyWnd(const char* pszCaption , const char* pszContent )
{
HWND hJigCaption = FindWindowEx(
NULL , // parent
NULL , // child after
NULL , // class
pszCaption ) ; // caption
while ( hJigCaption )
{
if ( IsMsgWnd( hJigCaption , pszContent ) )
{
break ;
}
// find next window
hJigCaption = FindWindowEx(
NULL , // parent
hJigCaption , // child after
NULL , // class
pszCaption ) ; // caption
}
if (hJigCaption)
{
::EndDialog( hJigCaption , 0 ) ;
}
}