“进程监控器”小工具的编写(包含整个项目源码)
一.思路
1.1【起因】:写的采集驱动在测试的时候发现,由于频繁通讯、数据量有些大,所以偶尔驱动会死掉,造成一段时间数据没采集到。所以打算写一个“进程监控器”,定时扫描驱动的情况,如果驱动没有运行则让驱动运行。
1.2【思路】:先从配置文件读取需要监控程序的信息,进程监控器运行时定时扫描驱动的情况,如果驱动没有运行则让驱动运行。
进程监控器写好后运行起来并拖到服务器的开机启动中,这样以后就可以避免驱动死掉,而数据没有采集了。
二.知识点讲解
2.1【知识点】:1.INI文件数据的读取;
2.用一个Timer组件,利用进程快照遍历被监控的进程是否运行,没有的话,运行进程;
2.2【知识点讲解】
2.2.1 delphi中如何让主窗体在程序运行之初不显示
无法实现的操作:
1、oncreate事件中设置visible属性或调用hide方法
2、onshow事件中设置visible属性或调用hide方法
3、对象观察器中设置visible属性
即设置主窗体的事件或属性都不能实现功能。
可实现的操作:
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.ShowMainForm:=False; //放在工程里也可以
end;
2.2.2 利用进程快照查找进程
从配置文件中智能读到进程的名称,需要查找它的运行情况,利用API函数CreateToolhelp32Snapshot(),建立进程快照,再用Process32First()和Process32Next()遍历,找到进程。
//名称:FindProcessFromName
//功能:用进程名称找到进程ID
//参数:可执行文件名称
//返回:若该可执行文件在运行,返回进程ID,
// 若该可执行文件没有运行则返回0
function TForm1.FindProcessFromName(name: string ): DWORD;//name为你要终止的进程的名称,Win9X则需包括路径
var
pe : TPROCESSENTRY32;//定义一个PROCESSENTRY32结类型的变量
hShot : THANDLE;
ProcessID : DWORD;
begin
ProcessID := 0;
Result := ProcessID;
hShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);// 创建快照句柄
pe.dwSize := sizeof(TPROCESSENTRY32);//一定要先为dwSize赋值
if (Process32First(hShot,pe)) then
begin
repeat
if pe.szExeFile = name then //判断此进程是否为你要终止的进程
begin
ProcessID := pe.th32ProcessID;
Result := ProcessID;
Break;
end;
until(not(Process32Next(hShot, pe)));
end;
CloseHandle(hShot); //最后别忘记Close
end;
2.2.3 运行进程
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。
(1).CreateProcess因为使用复杂,比较少用。
(2).WinExec主要运行EXE文件。如:WinExec(’Notepad.exe Readme.txt’, SW_SHOW); (3).ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。
我们这里用WinExec和ShellExecute都可以:
WinExec(PAnsiChar(ProcessInfo[i].PrcoessPath), SW_RESTORE); //WinExec也可以实现
ShellExecute(0,'Open', PAnsiChar(ProcessInfo[i].PrcoessPath), nil, nil, SW_RESTORE);
三.源码
3.1【INI文件】
文件内容如下:
[监视进程配置]
扫描周期(秒)=10
进程数量=2
程序运行周期(分钟)1=0
进程名称1=串口调试助手V2.2.exe
程序运行路径1=D:\串口调试助手V2.2.exe
程序运行周期(分钟)2=0
进程名称2=sscom32.exe
程序运行路径2=D:\sscom32.exe
3.2【数据定义】
新建CustomDef.pas来定义数据类型。
unit CustomDef;
interface
type TProjectInfo= record
ProcessNum: integer; //进程数量
Monitorcycle: integer; //扫描周期(秒)
end;
type TProcessInfo= record
IsUse : Boolean;
ProcessCycle : integer; //程序运行周期(分钟)
ProcessName : string; //进程名称
PrcoessPath : string; //程序运行路径
end;
implementation
end.
3.3【窗口界面】
3.4【Delphi源码】
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, CustomDef, ExtCtrls,
tlhelp32,
shellapi;
type
TForm1 = class(TForm)
tmr1: TTimer;
procedure FormCreate(Sender: TObject);
procedure GetInitPara(Filename: string);
procedure tmr1Timer(Sender: TObject);
private
{ Private declarations }
function FindProcessFromName(name: string ): DWORD;
public
{ Public declarations }
ProDirPath: string;
ProjectInfo: TProjectInfo;
ProcessInfo: array of TProcessInfo;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses IniFiles;
procedure TForm1.FormCreate(Sender: TObject);
begin
GetInitPara('Monitor.ini');
tmr1Timer(nil);
tmr1.Interval := ProjectInfo.Monitorcycle * 1000;
tmr1.Enabled := True;
Application.ShowMainForm := False;
end;
//名称:GetInitPara
//功能:获取系统初始化参数函数
//参数:Filename 配置文件名称
//返回:无
procedure TForm1.GetInitPara(Filename: string);
var
IniFile:TInifile;
i: integer;
tempProcessCycle,tempProcessName,tempPrcoessPath: string;
begin
ProDirPath:=ExtractFilePath(Application.ExeName);
if FileExists(ProDirPath + Filename) then
begin
IniFile:=TiniFile.Create(ProDirPath+Filename); //IniFile全路径
ProjectInfo.ProcessNum:=IniFile.ReadInteger('监视进程配置','进程数量',0);
ProjectInfo.Monitorcycle:=IniFile.ReadInteger('监视进程配置','扫描周期(秒)',10);
SetLength(ProcessInfo, ProjectInfo.ProcessNum);
for I := 0 to ProjectInfo.ProcessNum - 1 do
begin
tempProcessCycle:='程序运行周期(分钟)' + InttoStr(i+1);
tempProcessName:='进程名称' + InttoStr(i+1);
tempPrcoessPath:='程序运行路径' + InttoStr(i+1);
ProcessInfo[i].ProcessCycle := IniFile.ReadInteger('监视进程配置',tempProcessCycle,0);
ProcessInfo[i].ProcessName := IniFile.ReadString('监视进程配置',tempProcessName,'');
ProcessInfo[i].PrcoessPath := IniFile.ReadString('监视进程配置',tempPrcoessPath,'');
if (ProcessInfo[i].ProcessName<>'') and (ProcessInfo[i].PrcoessPath<>'') then
ProcessInfo[i].IsUse := True;
end;
IniFile.Free;
end
else
begin
showmessage('[报错:]"'+ProDirPath+'"路径下找不到文件"'+Filename+'",程序无法初始化!');
Exit;
end;
end;
//功能:定时器1定时响应
procedure TForm1.tmr1Timer(Sender: TObject);
var
i: integer;
ProID: DWORD;
begin
GetInitPara('Monitor.ini');
tmr1.Enabled := False;
tmr1.Interval := ProjectInfo.Monitorcycle * 1000;
tmr1.Enabled := True;
for I := 0 to ProjectInfo.ProcessNum - 1 do
begin
ProID := FindProcessFromName(ProcessInfo[i].ProcessName);
if ProID=0 then
begin
// WinExec(PAnsiChar(ProcessInfo[i].PrcoessPath), SW_RESTORE); //WinExec也可以实现
ShellExecute(0,'Open', PAnsiChar(ProcessInfo[i].PrcoessPath), nil, nil, SW_RESTORE);
end;
end;
end;
//名称:FindProcessFromName
//功能:用进程名称找到进程ID
//参数:可执行文件名称
//返回:若该可执行文件在运行,返回进程ID,
// 若该可执行文件没有运行则返回0
function TForm1.FindProcessFromName(name: string ): DWORD;//name为你要终止的进程的名称,Win9X则需包括路径
var
pe : TPROCESSENTRY32;//定义一个PROCESSENTRY32结类型的变量
hShot : THANDLE;
ProcessID : DWORD;
begin
ProcessID := 0;
Result := ProcessID;
hShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);// 创建快照句柄
pe.dwSize := sizeof(TPROCESSENTRY32);//一定要先为dwSize赋值
if (Process32First(hShot,pe)) then
begin
repeat
if pe.szExeFile = name then //判断此进程是否为你要终止的进程
begin
ProcessID := pe.th32ProcessID;
Result := ProcessID;
Break;
end;
until(not(Process32Next(hShot, pe)));
end;
CloseHandle(hShot); //最后别忘记Close
end;
end.