1. 程式人生 > >windows C/C++ 在一個程式中開啟,關閉和監視其它的exe程式

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);
    }