我已经实现了一种方法来查找进程(“iexplore.exe”)是否正在运行,我现在需要找到一种方法来关闭它(终止进程)来自Inno Setup。
strProg := 'iexplore.exe';
winHwnd := FindWindowByWindowName(strProg);
MsgBox('winHwnd: ' + inttostr(winHwnd), mbInformation, MB_OK );
if winHwnd <> 0 then
retVal:=postmessage(winHwnd,WM_CLOSE,0,0);
上例中的消息框将始终返回0,因此无法获取句柄。
(示例中的WM_CLOSE
常量已正确初始化)
我需要另一种方法来做到这一点,并且希望不涉及编写执行此操作的C ++ DLL(我不熟练使用C ++,我可能能够在C#中编写DLL,但是我不知道是否Inno Setup将与那个人互动。
这个C#DLL将获取进程列表,通过进程名称进行迭代,找到匹配项(==“iexplorer”)然后使用该名称终止进程...但是我仍然希望找到一个更简单的解决方案所以我不得不用Pascal脚本来互操作。
提前致谢!
答案 0 :(得分:4)
使用Win32_Process
的版本,您使用ie&#39; notepad.exe调用该程序&#39;:
const wbemFlagForwardOnly = $00000020;
procedure CloseApp(AppName: String);
var
WbemLocator : Variant;
WMIService : Variant;
WbemObjectSet: Variant;
WbemObject : Variant;
begin;
WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
WMIService := WbemLocator.ConnectServer('localhost', 'root\CIMV2');
WbemObjectSet := WMIService.ExecQuery('SELECT * FROM Win32_Process Where Name="' + AppName + '"');
if not VarIsNull(WbemObjectSet) and (WbemObjectSet.Count > 0) then
begin
WbemObject := WbemObjectSet.ItemIndex(0);
if not VarIsNull(WbemObject) then
begin
WbemObject.Terminate();
WbemObject := Unassigned;
end;
end;
end;
答案 1 :(得分:2)
您的代码会做出一些错误的假设,您应该全部解决这些问题:
关闭任何程序而不先询问用户是个坏主意。考虑到Internet Explorer的情况,用户可能会打开一些网页,其中部分填写表格 - 如果您无条件地关闭它们,您可能会因为失去工作而积极地惹恼用户。
您应该做什么:检查是否有任何程序打开会干扰您正常的安装进度,如果发现有任何程序提醒用户需要关闭它。问他们是否取消或重复检查,除非所有干扰程序都关闭,否则不要继续。
如果您确实需要向窗口发送WM_CLOSE
消息,则支持功能FindWindowByWindowName()
将无效。为什么Internet Explorer窗口的窗口名称是“iexplore.exe”?它将是开放网页的标题,因此您不会事先知道它是什么
您应该做什么:使用更合适的FindWindowByClassName()
功能。使用Spy ++或UI Spy等工具,您可以找到程序窗口的类名。对于我系统上的Internet Explorer,它是“IEFrame”,但你真的可以依赖它吗?再次,更好地让用户控制事物,并重复运行过程检查,直到所有干扰程序都已关闭。
使用匹配的窗口或类名关闭单个窗口可能不够。单个Windows进程可能打开多个窗口,并且可能有多个同一个可执行文件的实例正在运行,每个实例都打开一个或多个窗口。
你应该做什么:在循环中执行你的检查(和关闭)代码,直到一切都准备好继续。
但即便如此,你应该为出错的事做好准备 - Windows是一个多任务系统,可能会产生新的进程或随时打开窗口。如果启用了自动播放,那么当您认为已关闭它们时,插入CD或USB记忆棒可能会打开Internet Explorer窗口。
答案 2 :(得分:1)
我遇到了这个问题,并编写了一个简短的C ++程序来杀死可能处于挂起状态的某些进程,从而无法响应告诉他们死亡的消息。我只使用属于我的产品的应用程序,而不是系统应用程序。
如果您想要使调用参数正确的痛苦,您可以在Pascal脚本中执行相同的操作。以下是我所做的概述:
获取CSIDL_PROGRAM_FILES的位置。 Inno setup可以使用{pf}或{pf32}常量来完成此操作。或者调用Windows api SHGetSpecialFolderLocation函数。
例如,设置一个字符串,该字符串等于要杀死的进程的路径 String target = pf +“Mycompany / MyAppFolder / myHelperApp.exe”
调用Windows api函数CreateToolhelp32Snapshot,它返回正在运行的进程列表。
使用Windows api的OpenProcess和GetModuleFleNameEx查看目标的返回列表。
当你发现目标调用目标进程句柄上的Windows api TerminateProcess时。
答案 3 :(得分:1)
const
WM_QUIT = 18;
function InitializeUninstall(): Boolean;
var
winHwnd: longint;
retVal : boolean;
strProg: string;
begin
Result := true;
strProg := 'Readme.txt - Notepad';
winHwnd := FindWindowByWindowName(strProg);
MsgBox('winHwnd: ' + inttostr(winHwnd), mbInformation, MB_OK );
if winHwnd<>0 then begin { no module found or ignored pressed}
MsgBox('ravi:' #13#13 'Bye bye!', mbInformation, MB_OK);
abort(); { continue setup }
end;
end;
工作正常..
使用该代码,我能够跟踪正在运行的退出应用程序......