Inno Setup Убить запущенный процесс - PullRequest
3 голосов
/ 05 апреля 2011

Я уже реализовал способ узнать, запущен ли процесс ("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 ++, я мог бы написать DLL в C #, однако я не знаю, Inno Setup будет взаимодействовать с этим).

Эта C # DLL будет получать список процессов, перебирать имена процессов, находить совпадения (== "iexplorer") и затем убивать процессы с этим именем ... однако я все еще надеюсь найти более простое решение чтобы мне не пришлось взаимодействовать со сценарием на Паскале.

Заранее спасибо!

Ответы [ 4 ]

4 голосов
/ 03 июня 2014

Версия с использованием Win32_Process, вы вызываете процедуру с помощью ie '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;
2 голосов
/ 07 апреля 2011

Ваш код делает несколько ошибочных предположений, и вы должны решить их все:

  • Плохая идея закрыть любую программу, не спрашивая пользователя. Рассмотрим случай Internet Explorer: у пользователя могут быть открыты некоторые веб-страницы с частично заполненными формами - если вы закрываете их безоговорочно, вы можете активно разозлить пользователя, потому что он потерял работу.
    Что вы должны сделать вместо этого: Проверьте, открыта ли какая-либо программа, которая мешает нормальному прогрессу вашей установки, и, если она найдена, предупреждает пользователя, что он должен закрыть ее. Спросите их в цикле, отменить или повторить проверку, и не продолжайте, пока не будут закрыты все мешающие программы.

  • Если вам действительно нужно отправить сообщение WM_CLOSE в окно, функция поддержки FindWindowByWindowName() не будет работать. Почему имя окна окна Internet Explorer будет "iexplore.exe"? Это будет заголовок открытой веб-страницы, поэтому вы заранее не будете знать, что это такое.
    Что вы должны сделать вместо этого: Использовать гораздо более подходящую функцию FindWindowByClassName(). С помощью такого инструмента, как Spy ++ или UI Spy или аналогичного, вы можете узнать, как называется класс окна программы. Для Internet Explorer в моей системе это «IEFrame», но можете ли вы действительно на это положиться? Опять же, лучше предоставьте пользователю контроль над вещами и повторяйте проверку запущенного процесса, пока все мешающие программы не будут закрыты.

  • Может быть недостаточно закрыть одно окно с соответствующим окном или именем класса. В одном процессе Windows может быть открыто более одного окна, и может быть несколько запущенных экземпляров одного и того же исполняемого файла, каждый с одним или несколькими открытыми окнами.
    Что вы должны сделать вместо этого: Выполнить проверочный (и закрывающий) код в цикле, пока все не будет готово к продолжению.

  • Но даже в этом случае вы должны быть готовы к тому, что что-то пойдет не так - Windows - это многозадачная система, и новые процессы могут быть созданы или окна могут быть открыты в любое время. Если автозапуск включен, то вставка компакт-диска или USB-накопителя может открыть окно Internet Explorer, если вы думаете, что закрыли их все.

1 голос
/ 30 октября 2011
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;

Работает нормально ..

Используя этот код, я могу отследить приложение выхода, которое работает ...

1 голос
/ 15 июня 2011

У меня была эта проблема, и я написал короткую программу на C ++, чтобы убить некоторые процессы, которые могут находиться в зависшем состоянии и, таким образом, не могут отвечать на сообщения, в которых говорится о смерти. Я делал это только с приложениями, которые были частью моего продукта, а не с системными приложениями.

Вы могли бы сделать то же самое в скрипте Pascal, если хотите испытать боль от правильности получения параметров вызова. Вот схема того, что я сделал:

Получить местоположение CSIDL_PROGRAM_FILES. Inno setup может сделать это с помощью констант {pf} или {pf32}. Или вызовите функцию API SHGetSpecialFolderLocation для Windows.

Установите строку, равную пути к процессу, который вы хотите уничтожить, например Строка target = pf + "Mycompany / MyAppFolder / myHelperApp.exe"

Вызовите API-функцию Windows CreateToolhelp32Snapshot, которая возвращает список запущенных процессов.

Просмотрите этот возвращенный список для своей цели, используя OpenProcess и API-интерфейс GetModuleFleNameEx Windows API.

Когда вы находите целевой объект, вызовите API-интерфейс Windows TerminateProcess для дескриптора целевого процесса.

...