Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Отследить запуск внешней программы


Автор: ВладимирЖуков 24.5.2006, 13:45
При запуске внешней программы процесс пошел, а окно еще не создалось и когда я пишу FindWindow(...), то оно не может найтись так как еще не создано. Я пробовал Sleep после запуска, но это не выход. Мне нужен Handle запускаемого окна. Подскажите, как это сделать?

Автор: Snowy 24.5.2006, 13:59
Крути цикл с FindWindow, пока не найдется. 

Автор: Nickel 24.5.2006, 14:01
Код

var Wnd:HWnd;
begin
  repeat
    Wnd:=FindWindow(nil,'Èìÿ îêîøêà');
    Application.ProcessMessages;
    if Application.Terminated then Halt;
    Sleep(50);
  until wnd<>0;
end;
 

Автор: ВладимирЖуков 24.5.2006, 15:05
Спасибо! Я подобное уже сделал. Но мне это как то не нравится, потомучто поиск окна происходит по заголовку или по классу. А можно какнибудь получить handle незная ни класса, ни заголовка. Имеется имя файла (запускаемой программы).
Может какнибудь через процессы или еще как-нибудь? Пожалуйста с кодом!

Автор: Romikgy 24.5.2006, 15:45
GetModuleHandle+EnumThreadWindows 

Автор: Yanis 24.5.2006, 22:54
Цитата(Nickel @ 24.5.2006,  15:01)
Код

var Wnd:HWnd;
begin
  repeat
    Wnd:=FindWindow(nil,'Èìÿ îêîøêà');
    Application.ProcessMessages;
    if Application.Terminated then Halt;
    Sleep(50);
  until wnd<>0;
end;

И не дай бог чужая программа не запустится smile  

Автор: BUGOR 25.5.2006, 08:35
В таблице открытых хендлов системы до того как окно не создано никаких записей об этом окне тоже не создано, поэтому пока окно не создано, то как ты его хендл-то узнаешь? Задача unreal)  

Автор: Nickel 25.5.2006, 11:21
Цитата(BUGOR @ 25.5.2006,  08:35)
В таблице открытых хендлов системы до того как окно не создано никаких записей об этом окне тоже не создано, поэтому пока окно не создано, то как ты его хендл-то узнаешь? Задача unreal)

А почему бы не подождать пока они не появятся?
Цитата(Yanis @ 24.5.2006,  22:54)
И не дай бог чужая программа не запустится smile

Ну что, я всё должен чтоли предусматривать?  smile 
Цитата(ВладимирЖуков @ 24.5.2006,  15:05)
Может какнибудь через процессы или еще как-нибудь? Пожалуйста с кодом!

Пожалуйста:
Код

uses TlHelp32;

function GetProcessName(PID: Cardinal): string;
var
 Snap: dword;
 Process: TPROCESSENTRY32;
begin
  Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Snap <> INVALID_HANDLE_VALUE then
     begin
      Process.dwSize := SizeOf(TPROCESSENTRY32);
      if Process32First(Snap, Process) then
         repeat
          if Process.th32ProcessID = PID then
             begin
              Result := Process.szExeFile;
              CloseHandle(Snap);
              Exit;
             end;
         until not Process32Next(Snap, Process);
      Result := '';
      CloseHandle(Snap);
     end;
end;

function FindWindowByExeName(ExeName: string): Hwnd;
var
  wnd: HWnd;
  PID : Cardinal;
begin
  wnd := GetWindow(Application.Handle, GW_HWNDFIRST);
  while wnd > 0 do
  begin
    GetWindowThreadProcessId(wnd, PID);
    if GetProcessName(PID) = ExeName then
    begin
      Result := wnd;
      Exit;
    end
    else
      wnd := GetWindow(wnd, GW_HWNDNEXT);
  end;
  Result := 0;
end;

...


procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(FindWindowByExeName(ExtractFileName
           (Application.ExeName)))+' - '+IntToStr(Handle));
end;


Зацикли FindWindowByExeName по аналогии с FindWindow. Если есть вероятность, что программа может не запуститься, то, во-первых, проверь что возвратил WinExec (если используешь его), если значение больше 31, то всё окей, иначе - ошибка. Во-вторых, ограничь по времени поиск окна, ну например секунд 5 (сгодится даже TTimer с закладки System). 

Автор: аЛексус 26.5.2006, 06:10
Что-то не выходит!!! :-(
Может еще что-то есть?! 

Автор: Nickel 26.5.2006, 06:58
А что не выходит? Каков результат? Как делаешь? 

Автор: аЛексус 26.5.2006, 11:44
Интерфейс второй программы, то встраивается то не встраивается. 
1. Интерфейс визуально не встраивается(выходит за рамки окна), хотя относится к окну главной программы. и при этом в панели задач нет  кнопки для второй программы, хотя окно есть.
2. Интерфейс втраивается и в панели задач появляется кнопка.

Вот код проги:

Код

function FindWindowByExeName(ExeName: string): Hwnd;
var
  Wnd: HWnd;
  PID : Cardinal;
begin
  Wnd := GetWindow(Application.Handle, GW_HWNDFIRST);
  Result := 0;
  while Wnd <> 0 do
  begin
    GetWindowThreadProcessId(Wnd, PID);
    if GetProcessName(PID) = ExeName then
    begin
      Result := Wnd;
      Exit;
    end
    else
      Wnd := GetWindow(Wnd, GW_HWNDNEXT);
  end;
end;

function GetProcessName(PID: Cardinal): string;
var
  Snap: DWORD;
  Process: TProcessEntry32;
begin
  Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Snap <> INVALID_HANDLE_VALUE then
  begin
    Process.dwSize := SizeOf(TPROCESSENTRY32);
    if Process32First(Snap, Process) then
      repeat
        if Process.th32ProcessID = PID then
        begin
          Result := Process.szExeFile;
          CloseHandle(Snap);
          Exit;
        end;
      until not Process32Next(Snap, Process);
    Result := '';
    CloseHandle(Snap);
  end;
end;

procedure TfrmMain.Button2Click(Sender: TObject);
var
  Wnd: HWND;
begin
  Wnd := 0;
  if odFile.Execute then
    if ShellExecute(Handle, nil, PAnsiChar(odFile.FileName), nil, nil, SW_SHOW) > 32 then
      if ExtractFileName(odFile.FileName) <> ExtractFileName(Application.ExeName) then
      begin
        repeat
          if Application.Terminated then Halt;

          Wnd := FindWindowByExeName(ExtractFileName(odFile.FileName));

          if Wnd <> 0 then
          begin
            if Windows.SetParent(Wnd, Handle) = 0 then
            begin
              SendMessage(Wnd, WM_CLOSE, 0, 0);
              ShowMessage('Невозможно встроить окно!');
              Exit;
            end;
          end;
          Sleep(10);
        until Wnd <> 0;
      end;
end;

 

Автор: Nickel 26.5.2006, 12:16
Понятно, мой код не очень надёжный, поскольку ищет первое попавшееся окошко данного процесса, а у процесса может быть много всяких невидимых окошек, поэтому нужно как минимум отфильтровать в функции FindWindowByExeName невидимые окошки, окошки с нулевым размером и, наверно показанные за пределом экрана (можно ещё ввести ограничения по стилям типа WS_POPUP...). 

Автор: Демо 26.5.2006, 14:43
Цитата(ВладимирЖуков @  24.5.2006,  13:45 Найти цитируемый пост)
Подскажите, как это сделать?


См. WaitForInputIdle 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)