Delphi 异常死亡进程的自动复活

原理

通常,把一个应用程序的一次运行实例叫做一个进程,在一个进程内又可包含多条可并发执行的路径,每条执行路径叫做一个线程,一个进程至少包含一个主线程。主线程负责执行运行的启动代码。另外,一个进程可以创建若干子进程。当进程被创建时,系统自动产生主线程,主线程然后可创建更多的线程。

我们可以编写一个程序,让其创建、启动子进程,并监视进程的运行情况,在其出现异常终止时,立即重新创建并启动子进程即可。

相关函数

创建一个子进程函数

1
2
3
4
5
6
7
8
9
10
11
12
OOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);

参数说明:

  • lpApplicationName:新进程将要使用的可执行文件的名字,必须包含扩展名。
  • LpCommandLine:新进程的命令行。若lpApplicationName为NULL,LpCommandLine 的第一个参数是新进程将要使用的可执行文件的名字,可以不包含扩展名,系统假定是exe文件。
  • LpProcessAttributes和lpThreadAttributes:分别是给进程对象和线程对象指定的安全属性。
  • BInheritHandles:指定该进程是否继承其父进程中的句柄。
  • dwCreationFlags:指定新进程产生方式的标志,可用逻辑操作符or相连接。
  • LpEnvironment:指向含有新进程将要使用的环境块字符串的一块内存,一般为NULL,使子进程继承父进程的一组环境块。
  • LpCurrentDirectory:设置子进程的当前驱动器和工作目录, 为NULL,子进程继承父进程的当前驱动器和工作目录。
  • LpStartupInfo:指向STARTUPINFO 的结构。一般让子进程使用缺省值。但要把该结构中的所有成员初始化为0,并设置cb为结构大小。

STARTUPINFO 结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ypedef struct _STARTUPINFO {
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
```
lpProcessInformation 参数指向LPPROCESS_INFORMATION结构,CreateProcess在返回之前,填入有关子进程的信息,父进程正是利用该信息监测子进程是否终止。该结构如下:
```dpr
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;

Process和hThread分别是子进程的句柄和子进程的主线程的句柄,dwProcessId和dwThreadId分别是子进程的标识号和子进程的主线程的标识号。

子进程终止检测函数

1
GetEXitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode );

process:进程句柄,lpExitCode:进程终止时的退出码。
如果一个进程没有终止,lpExitCode 的返回值是STILL_ACTIVE,否则返回其他值。

方法的Delphi语言实现

创建一个新的项目 Project1

选择File,New Application。在表单Form1上放一Memo组件,一个OK按钮组件,改变OK按钮组件的Cation属性为 CreateProcess。再放一个timer组件。设置timer组件的Interval值为1000,每秒检查一次进程是否终止。

在Unit1 Use节的Type后定义一个过程

1
piProcInfoGPS:PROCESS_INFORMATION;

在Unit1 implementation节中编写EstablishProcess过程的实现代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
procedure EstablishProcess;
Var
siStartupInfo:STARTUPINFO;
saProcess,saThread:SECURITY_ATTRIBUTES;
fSuccess:boolean;
begin
fSuccess:=false;
ZeroMemory(@siStartupInfo,sizeof(siStartupInfo));
siStartupInfo.cb:=sizeof(siStartupInfo);
saProcess.nLength:=sizeof(saProcess);
saProcess.lpSecurityDescriptor:=PChar(nil);
saProcess.bInheritHandle:=true;
saThread.nLength:=sizeof(saThread);
saThread.lpSecurityDescriptor:=PChar(nil);
saThread.bInheritHandle:=true;
fSuccess:=CreateProcess(PChar(nil),'c:\sr350\Sr350buff',@saProcess,@saThread,false,
CREATE_DEFAULT_ERROR_MODE,Pchar(nil),Pchar(nil),siStartupInfo,piProcInfoGPS);
if( not fSuccess)then
Form1.Memo1.Lines.Add('Create Process Sr350buff fail.')
else
Form1.Memo1.Lines.Add('Create Process Sr350buff success.')
end;

在CreateProcess按钮的OnClick事件中调用过程

EstablishProcess;

为Timer1的OnTimer事件编写代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Procedure TForm1.Timer1Timer(Sender: TObject);
Var
dwExitCode:DWORD;
fprocessExit:boolean;
Begin
 
dwExitCode:=0;
fprocessExit:=false;
fprocessExit:=GetExitCodeProcess(piProcInfoGPS.hProcess,dwExitCode);
if(fprocessExit and (dwExitCode<>STILL_ACTIVE))then
begin
Memo1.Lines.Add('SR350buff.exe进程终止');
CloseHandle(piProcInfoGPS.hThread);
CloseHandle(piProcInfoGPS.hProcess);
EstablishProcess;
end;
End;

程序中设可执行文件名为c:350350buff.exe,所以c:盘350目录下需有sr350buff.exe文件。

编译联接,运行project1,单击CreateProcess可见c:350350buff.exe启动。关掉sr350buff.exe进程,可见sr350buff.exe自动再启动

热评文章