Как получить дескриптор, который выполняется в winexec или shellexecute? - PullRequest
0 голосов
/ 15 июня 2010

Я использую для создания пользовательской функции, такой как winexec (...): Hwnd, которая будет повторно обрабатывать дескриптор исполняемого приложения.

Я использовал findwindow (), но у меня возникли проблемы, если он изменил заголовок окна.

Ответы [ 3 ]

8 голосов
/ 15 июня 2010

Нет общего способа получить «дескриптор окна» приложения, потому что нет гарантии, что у любой программы есть один дескриптор окна.Программа может иметь много дескрипторов верхнего уровня (т. Е. Microsoft Word, по одному для каждого документа), или у нее может не быть окон вообще.Вы можете спросить, для чего вам действительно нужен дескриптор окна;могли бы быть более эффективные способы сделать то, что вы пытаетесь сделать, не требуя какого-либо определенного дескриптора окна.

WinExec (который устарел в течение почти 15 лет, поэтому вам следует серьезно подуматьбольше не использовать) и ShellExecute не возвращает абсолютно никакой информации о программах, которые они запускают, если они вообще запускают какую-либо программу.(ShellExecute может использовать DDE для отправки команды уже запущенному экземпляру приложения.) И если они запустят приложение, оно может завершиться до того, как ваша программа перестанет работать.

Вы можете использоватьCreateProcess или ShellExecuteEx вместо.Если они запустят программу, они дадут вам дескриптор процесса, представляющий программу, которую они запустили.Вы можете использовать это, чтобы помочь вам получить дополнительную информацию о программе, такую ​​как список ее окон.Не беспокойтесь о FindWindow;класс заголовка и окна не обязательно должен быть уникальным;программа может использовать одно и то же имя класса для множества разных окон, и несколько экземпляров программы будут использовать одно и то же имя класса без особого способа выбрать то, что вам действительно нужно.

EnumWindows - это функция, которую вы можете использоватьиспользуйте, чтобы получить список возможных оконных дескрипторов.Вы даете ему указатель на функцию, и она будет вызывать эту функцию один раз для каждого окна верхнего уровня на рабочем столе.Вам понадобится способ сообщить, какой процесс вас интересует, и способ вернуть список результатов.Функция принимает только один параметр, поэтому этот параметр должен быть указателем на структуру, которая содержит больше информации:

type
  PWindowSearch = ^TWindowSearch;
  TWindowSearch = record
    TargetProcessID: DWord;
    ResultList: TWndList;
  end;

TWndList - это тип, который я составил для хранения списка HWndценности.Если у вас Delphi 2009 или более поздняя версия, вы можете использовать TList<HWnd>;для более ранних версий вы можете использовать TList потомка или что-то еще, что вы выберете.

CreateProcess сообщит вам новый идентификатор процесса в dwProcessID члене записи TProcessInformation, которую он заполняет;ShellExecuteEx возвращает только дескриптор процесса, поэтому используйте GetProcessID для этого.Функция перечисления окон нуждается в функции обратного вызова, соответствующей этой сигнатуре:

function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;

. Вы можете использовать EnumWindows, чтобы получить список дескрипторов, подобный этому:Функция обратного вызова выглядит следующим образом:

function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
  SearchRec: PWindowSearch;
  WindowPid: DWord;
begin
  SearchRec := PWindowSearch(Param);
  Assert(Assigned(SearchRec));
  GetWindowThreadProcessID(Wnd, WindowPid);
  if WindowPid = SearchRec.TargetProcessID then
    SearchRec.ResultList.Add(Wnd);
  Result := True;
end;

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

Когда вы закончите использовать дескриптор процесса, убедитесь, что вы вызвали CloseHandle для него, чтобыОС может очистить учетную информацию процесса.

2 голосов
/ 15 июня 2010

Есть функция с именем EnumWindows. Я думаю, что это будет полезно для вас.

Проверьте следующие ссылки для получения дополнительной информации

http://delphi.about.com/od/windowsshellapi/l/aa080304a.htm

http://www.swissdelphicenter.ch/torry/showcode.php?id=327

0 голосов
/ 27 июля 2016

Попробуйте пример 6 с этой страницы (http://delphidabbler.com/tips/134) и просто немного его измените. Вот что я сделал.

если вы хотите разделить, где вы проверяете и где вы просматриваете свой результат, вы можете сделать что-то вроде

var
  //...
  runNext : Boolean;
  //...

begin
{ startup code from other sample here }

// but instead of if
runNext := ShellExecuteEx(@SEInfo);

{ some more code here }

    // need delay before running next process
    // run loop until window with Handle is closed
if runNext then
    with SEInfo do
     repeat
      GetExitCodeProcess(SEInfo.hProcess, ExitCode);
      Sleep(20);
      Application.ProcessMessages;
      CheckSynchronize();
    until (ExitCode <> STILL_ACTIVE) or Application.Terminated;

{ next process code here }
end;

Я понимаю, что некоторые из вас будут бросать ненавистную почту за то, что добавили Sleep (), но я бы предпочел не закрывать окна, пока не завершится выполнение, когда я обрабатываю кучу вещей и жду.

...