Inno Setup 终止正在运行的进程

发布于 2024-10-29 09:13:00 字数 650 浏览 4 评论 0 原文

我已经实现了一种方法来查找进程(“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 脚本进行互操作。

提前致谢!

I have already implemented a way to find whether a process ("iexplore.exe") is running, I now need to find a way to close it (terminate the process) from 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);

The message box in the example above will always return 0 therefore no handle is ever gotten.
(the WM_CLOSE constant in the example is properly initialized)
I need another way of doing this, and hopefully one that does not involve writing a C++ DLL that does this (I am not proficient in C++, I might be able to write a DLL in C#, however I don't know whether Inno Setup will interop with that).

This C# DLL would get the process list, iterate thru the names of processes, find a match (=="iexplorer") and then kill the processes with that name...however I am still hoping to find an easier solution so that I wouldnt have to interop it with Pascal script.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

人间不值得 2024-11-05 09:13:00

使用 Win32_Process 的版本,您可以使用“notepad.exe”调用该过程:

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;

Version with use of Win32_Process, you call the procedure with i.e. 'notepad.exe':

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;
你是暖光i 2024-11-05 09:13:00

您的代码做出了几个错误的假设,您应该解决所有这些问题:

  • 在不先询问用户的情况下关闭任何程序是一个坏主意。考虑一下 Internet Explorer 的情况,用户可能会打开一些网页,其中的表单已部分填写 - 如果您无条件关闭它们,您可能会因为用户丢失工作而主动激怒他们。
    您应该做什么:检查是否有任何程序打开,干扰安装的正常进度,如果发现,则提醒用户需要将其关闭。循环询问他们是否取消或重复检查,并且除非关闭所有干扰程序,否则不要继续。

  • 如果您确实需要向窗口发送 WM_CLOSE 消息,则支持函数 FindWindowByWindowName() 将不起作用。为什么 Internet Explorer 窗口的窗口名称是“iexplore.exe”?它将是打开网页的标题,因此您不会事先知道它是什么。
    您应该做什么:使用更合适的FindWindowByClassName()函数。使用 Spy++ 或 UI Spy 或类似工具,您可以找出程序窗口的类名。对于我系统上的 Internet Explorer,它是“IEFrame”,但您真的可以信赖它吗?再次强调,最好让用户控制事物,并重复运行进程检查,直到所有干扰程序都已关闭。

  • 关闭具有匹配窗口或类名的单个窗口可能还不够。单个 Windows 进程可能会打开多个窗口,并且可能会运行同一可执行文件的多个实例,每个实例都打开一个或多个窗口。
    您应该做什么:循环执行检查(和关闭)代码,直到一切准备就绪。

  • 但即便如此,您也应该做好出错的准备 - Windows 是一个多任务系统,随时可能会产生新进程或打开窗口。如果启用了自动播放,则当您认为已关闭所有 Internet Explorer 窗口时,插入 CD 或 USB 记忆棒可能会打开 Internet Explorer 窗口。

Your code makes several assumptions that are wrong, and you should address them all:

  • It's a bad idea to close any program without asking the user first. Consider the case of Internet Explorer, the user may have some web pages open with forms partially filled in - if you close them unconditionally you may actively piss off the user because they lost work.
    What you should do instead: Check whether any program is open that interferes with the normal progress of your installation, and if one is found alert the user that they need to close it. Ask them in a loop whether to cancel or to repeat the check, and do not continue unless all interfering programs are closed.

  • If you really need to send a WM_CLOSE message to a window, then the support function FindWindowByWindowName() won't work. Why would the window name of an Internet Explorer window be "iexplore.exe"? It will be the title of the open web page, so you won't know beforehand what it is.
    What you should do instead: Use the much more appropriate FindWindowByClassName() function. With a tool like Spy++ or UI Spy or similar you can find out what the class name of a program window is. For Internet Explorer on my system it is "IEFrame", but can you really rely on that? Again, better give the user control over things, and repeat the running process check until all interfering programs have been closed.

  • Closing a single window with the matching window or class name may not be enough. A single Windows process may have more than one window open, and there may be several instances of the same executable running, each with one or more windows open.
    What you should do instead: Execute your checking (and closing) code in a loop until everything is ready to proceed.

  • But even then you should be prepared for things to go wrong - Windows is a multitasking system, and new processes may be spawned or windows be opened at any time. If AutoPlay is enabled then inserting a CD or USB stick could open an Internet Explorer window right when you think that you have closed them all.

拔了角的鹿 2024-11-05 09:13:00

我遇到了这个问题,并编写了一个简短的 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。

I had this problem, and wrote a short C++ program to kill certain processes that might be in a hung state and thus unable to respond to messages telling them to die. I only did this with applications that were part of my product, not system applications.

You could do the same thing in Pascal script if you want to suffer the pain of getting the calling parameters correct. Here is an outline of what I did:

Get the location of CSIDL_PROGRAM_FILES. Inno setup can do this with its {pf} or {pf32} constants. Or call the Windows api SHGetSpecialFolderLocation function.

Set a string equal to the path to the process you want to kill, for example
String target = pf + "Mycompany/MyAppFolder/myHelperApp.exe"

Call the Windows api function CreateToolhelp32Snapshot, which returns a list of running processes.

Look through this returned list for your target using the Windows api's OpenProcess and GetModuleFleNameEx.

When you find the target call the Windows api TerminateProcess on the target process handle.

゛清羽墨安 2024-11-05 09:13:00
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;

它工作正常..

使用该代码,我可以跟踪正在运行的退出应用程序...

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;

It works fine..

Using that code, I'm able to trace exit application which is running...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文