windows C/C++ 在一個程式中開啟,關閉和監視其它的exe程式
本文要實現的功能就是在windows下,實現用一個程式來開啟,關閉和監視其它的exe程式,我這裡的的exe程式是我自己實現的。
1.監視exe是否崩潰
首先如果一個程序不在了,它的程序ID就是0, 那麼通過檢測程序ID是否為0,就可以知道程序是否還在執行。
假設程式崩潰了,它的程序ID會變成0,那麼通過檢測程序ID是否為0,就可以知道程式是否崩潰。
但是在windows下,情況並不是假設的那樣,程式崩潰了,它就彈出一個錯誤對話方塊,如下圖所示,並且如果不關掉掉這個框,程式就永遠死在這個視窗上,不會退出,程序ID也不會變成0,那麼就不能通過檢測程序ID來判斷程式是否崩潰。所以現在必須讓程式崩潰後直接退出而不是死在錯誤視窗上。
解決辦法就是SetUnhandledExceptionFilter函式,使用這個函式就可以讓程式崩潰後直接退出,而不是死在錯誤視窗上。這個函式的返回值有三種情況:
EXCEPTION_EXECUTE_HANDLER 表示下面執行__except塊內及其後面的程式碼
EXCEPTION_CONTINUE_SEARCH 表示回到丟擲異常處繼續向下執行
EXCEPTION_CONTINUE_EXECUTION 表示查詢下一個異常處理例程入口
SetUnhandledExceptionFilter函式用法示例:
long __stdcall callback(EXCEPTION_POINTERS *excp)
{
return EXCEPTION_EXECUTE_HANDLER;
}
int main()
{
SetUnhandledExceptionFilter(callback);
//只是為了讓程式崩潰
_asm int 3;
return 0;
}
如何獲取程序ID呢?
因為在這裡我是用一個程式來監視另一個exe程式的,所以我可以通過exe程式的名字來獲取這個程序的程序ID,方法如下,GetProcessIdFromName函式輸入的就是exe程式的名字,例如"test.exe"。
DWORD GetProcessIdFromName(const char*processName)
{
PROCESSENTRY32 pe;
DWORD id = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe.dwSize = sizeof(PROCESSENTRY32);
if( !Process32First(hSnapshot,&pe) )
return 0;
char pname[300];
do
{
pe.dwSize = sizeof(PROCESSENTRY32);
if( Process32Next(hSnapshot,&pe)==FALSE )
break;
//把WCHAR*型別轉換為const char*型別
sprintf(pname,"%ws",pe.szExeFile);
//比較兩個字串,如果找到了要找的程序
if(strcmp(pname,processName) == 0)
{
id = pe.th32ProcessID;
break;
}
} while(1);
CloseHandle(hSnapshot);
return id;
}
如果這個exe程式崩潰了,如何重新開啟exe呢?
這裡我採用最簡單的WinExec()函式:
WinExec("C:\\exams\\test.exe",SW_SHOW);
如何主動關閉exe程式呢?
//通過程序名獲取程序ID
DWORD pid = GetProcessIdFromName("test.exe");
//獲取程序的最大許可權
HANDLE token = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
//關閉程序
TerminateProcess(token, 0);
注意啦!!!!!!!!!
在上面獲取程序ID的時候,一定是"test.exe",只是exe程式的名字,沒有路徑!沒有路徑!沒有路徑!重要的事情說三遍!否則獲取不到程序ID。但是WinExec開啟的時候就要加上路徑了,當然如果控制程式和exe程式在相同目錄下,就不必啦。
我寫的時候是char filename[] = "C:\\exams\\test.exe",然後後面開啟和獲取程序ID的時候都用的是filename,導致我在關exe的時候一直關不掉,困擾了我好久。
我新增的標頭檔案有:
#include<windows.h>
#include<tlhelp32.h>
#include<comdef.h>
關於windows關閉視窗的API
剛開始以為是 CLoseWindow(控制代碼); 然而這個介面只是視窗最小化
百度後以為是 DestroyWindow(控制代碼) : 然後這介面執行沒有任何效果,不知為何
正確的應該是 ::SendMessage(控制代碼,WM_CLOSE,0,0,)
HWND m_handle = 0;
int num = 0;
while(m_handle == 0 && num < 60){
m_handle = ::FindWindowA(NULL, "untitled1");
++num;
Sleep(100);
}
if(m_handle != 0)
{
::SendMessageA(m_handle,WM_CLOSE,0,0);
}