怎样实现通过一个程序来控制其它程序,比如控制安装向导程序自动完成程序的安装过程而不用手动干预。我们知道对于windows图形界面程序只要获取窗体的句柄就可以向窗体发送消息,或者是获取窗体的子窗体和控件,也就获得了去整个窗体的控制权。在windows api函数中FindWindow用于获取窗体句柄,函数原型声明如下:
HWND FindWindow(
LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);
参数
lpClassName:窗体类名字符串指针。
lpWindowName:窗体的标题字符串指针。
返回值: 如果调用成功返回相应窗体的句柄,如果失败返回NULL。
同时基于MFC的应用程序对上面的函数进行了封装,作为CWnd类的一个静态函数,为了使用方便本例以基于MFC的应用为例,函数声明如下:
static CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );
参数含义和上面的API函数相同,此处就不在傲述。
应用程序窗体的类名以及窗体标题可以借助VC++自带的Spy++进行分析获取(使用VC的不会对此工具陌生,功能非常强大),本例以完成 jdk1.4.2.exe程序的安装为例。首先启动jdk1.4.2.exe出现安装界面的第一步,然后打开Spy++工具,会自动捕捉到正在运行的程序一切进程信息,从中找到jdk1.4.2.exe安装程序对应的项目,即可获取 Windows Caption和Class Name ,然后进一步获取子控件(比如 下一步)的指针,向子控件发送单击消息即模拟手工单击按钮的操作。具体实现代码如下:
int InstallJ2sdk()
{
/***************************************************
* version:
* last modify time:
* author:
* 功能:安装JDK
* 参数:无
* 返回值:成功返回 0 ,否则返回 -1
***************************************************/
int nRet = -1 ;
int nCount = 0 ;
CString strProsname = _T("J2SDK1.4.2.exe") ;
CString strClassName = _T( "MsiDialogCloseClass" ) ;
CString strWidLicense = _T("Java 2 SDK, SE v1.4.2 - License") ;
CString strWidCustom = _T("Java 2 SDK, SE v1.4.2 - Custom Setup") ;
CString strWidReg = _T("Java 2 SDK, SE v1.4.2 - Browser Registration") ;
CString strWidComplete = _T("Java 2 SDK, SE v1.4.2 - Complete") ;
CWnd *pWndLicense , *pWndCustom , *pWndReg , *pWndComplete ;
CButton *pBut ;
//!QueryProcessByName为自定义函数,用于判断指定的进程是否存在
while( !QueryProcessByName( strProsname ) && nCount < 20 )
{
Sleep(1000) ;
nCount = nCount + 1 ;
}
//安装向导第1步,认证许可界面
nCount = 0 ;
//获取认证许可界面的窗体
pWndLicense = ( CWnd *) CWnd::FindWindow( strClassName , strWidLicense );
while( QueryProcessByName( strProsname ) == true &&
pWndLicense == NULL &&
nCount < 60 )
{
nCount = nCount + 1 ;
pWndLicense = ( CWnd *)CWnd::FindWindow( strClassName , strWidLicense );
Sleep( 1000 ) ;
}
if( pWndLicense != NULL )
{ //获取“同意”按钮控件的指针,可以通过Spy++工具来获取“同意”按钮的Control ID
pBut = (CButton *)pWndLicense->GetDlgItem( 0x10d9);
if( pBut != NULL )
{
CButton *pButAcept = (CButton *) pBut ->GetDlgItem( 0x565); //同意 按钮对应Control ID
pButAcept->SendMessage(BM_CLICK, 0, 0);
Sleep(1000) ;
pButAcept->SendMessage(BM_CLICK, 0, 0);
Sleep(1000) ;
pButAcept->SendMessage(BM_CLICK, 0, 0);
Sleep(1000) ;
CButton *pButNext = (CButton *) pWndLicense->GetDlgItem( 0x5c9); //next 按钮对应Control ID //向控件发送单击消息,为了保证成功连续发送多次。
pButNext->SendMessage(BM_CLICK, 0, 0);
Sleep(1000) ;
pButNext->SendMessage(BM_CLICK, 0, 0);
Sleep(1000) ;
pButNext->SendMessage(BM_CLICK, 0, 0);
}
else
{
nRet = -1 ;
}
}
//安装向导第2步,安装路径设置界面
Sleep(2000) ;
if( !QueryProcessByName( strProsname ) )
nRet = -1 ;
nCount = 0 ;
pBut = NULL ;
pWndCustom = ( CWnd *)CWnd::FindWindow( strClassName, strWidCustom );
while( QueryProcessByName( strProsname ) == true &&
pWndCustom == NULL &&
nCount < 10 )
{
Sleep( 1000 ) ;
nCount = nCount + 1 ;
pWndCustom = ( CWnd *)CWnd::FindWindow( strClassName, strWidCustom );
}
if( pWndCustom != NULL )
{
CButton *pBut2 = (CButton *)pWndCustom->GetDlgItem( 0x5c9); //next 按钮对应Control ID
if( pBut2 != NULL )
{
pBut2->SendMessage(BM_CLICK, 0, 0);
Sleep(1000);
pBut2->SendMessage(BM_CLICK, 0, 0);
Sleep(1000);
pBut2->SendMessage(BM_CLICK, 0, 0);
}
else
{
nRet = -1 ;
}
}
Sleep(2000) ;
if( !QueryProcessByName( strProsname ) )
nRet = -1 ;
nCount = 0 ;
pBut = NULL ;
//安装向导第3步,注册界面
pWndReg= ( CWnd *)CWnd::FindWindow( strClassName, strWidReg );
while( QueryProcessByName( strProsname ) == true &&
pWndReg == NULL &&
nCount < 10 )
{
Sleep( 1000 ) ;
nCount = nCount + 1 ;
pWndReg= ( CWnd *)CWnd::FindWindow( strClassName, strWidReg );
}
if( pWndReg != NULL )
{
pBut = (CButton *)pWndReg->GetDlgItem( 0x5c9); //next 按钮对应Control ID
if( pBut != NULL )
{
pBut->SendMessage(BM_CLICK, 0, 0);
Sleep(1000);
pBut->SendMessage(BM_CLICK, 0, 0);
Sleep(1000);
pBut->SendMessage(BM_CLICK, 0, 0);
}
else
{
nRet = -1 ;
}
}
Sleep(2000) ;
if( !QueryProcessByName( strProsname ) )
nRet = -1 ;
nCount = 0 ;
pBut = NULL ;
//安装向导第4步,完成界面
pWndComplete = ( CWnd *)CWnd::FindWindow( strClassName, strWidComplete );
while( QueryProcessByName( strProsname ) == true &&
pWndComplete == NULL &&
nCount < 500 )
{
nCount = nCount + 1 ;
pWndComplete = ( CWnd *)CWnd::FindWindow( strClassName, strWidComplete );
Sleep( 1000 ) ;
}
if( pWndComplete != NULL )
{
Sleep(2000) ;
pBut = (CButton *)pWndComplete->GetDlgItem( 0x5dd); //finish 按钮对应Control ID
if( pBut != NULL )
{
pBut->SendMessage(BM_CLICK, 0, 0);
Sleep(1000);
pBut->SendMessage(BM_CLICK, 0, 0);
Sleep(1000);
pBut->SendMessage(BM_CLICK, 0, 0);
return 0 ;
}
else
{
nRet = -1 ;
}
}
return nRet ;
}
bool QueryProcessByName( CString strProsName )
{
/***************************************************
* version:
* last modify time:
* author:
* 功能:查看strProsName指定的进程是否存在
* 参数:strProsName 要关闭进程名子
* 返回值:关闭成功返回 true ,否则返回 false
***************************************************/
bool nRet = false ;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe)) {
//显示错误信息
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL );
//AfxMessageBox( (LPCTSTR)lpMsgBuf);
LocalFree( lpMsgBuf );
return nRet;
}
while (Process32Next(hSnapshot, &pe)) {
if ( strcmp( strProsName , pe.szExeFile) == 0 ){
return true ;
}
}
return nRet ;
}
通过类似的方法也可以对其它的程序进行控制,完成安装。