2012-09-05 11 views
5

Chcę uruchomić aplikację z Delphi i uzyskać do niej uchwyt, dzięki czemu mogę osadzić główne okno aplikacji na ramce typu TFrame. Do tej pory próbowałem:Jak uruchomić aplikację i uzyskać do niej dostęp za pomocą Delphi?

Function TFrmEmbeddedExe.StartNewApplication : Boolean; 
var 
    SEInfo: TShellExecuteInfo; 
    ExitCode : DWORD; 
begin 

    FillChar(SEInfo, SizeOf(SEInfo), 0) ; 
    SEInfo.cbSize := SizeOf(TShellExecuteInfo) ; 
    with SEInfo do 
    begin 
    fMask := SEE_MASK_NOCLOSEPROCESS; 
    Wnd := self.Handle; 
    lpFile := PChar(self.fexecuteFileName) ;// Example could be 'C:\Windows\Notepad.exe' 
    nShow := SW_SHOWNORMAL;//SW_HIDE; 
    end; 

    if ShellExecuteEx(@SEInfo) then 
    begin 
    sleep(1500); 
    self.fAppWnd := FindWindow(nil, PChar(self.fWindowCaption)); //Example : 'Untitled - Notepad' 
    if self.fAppWnd <> 0 then 
    begin 
     Windows.SetParent(self.fAppWnd, SEInfo.Wnd); 
     ShowWindow(self.fAppWnd, SW_SHOWMAXIMIZED); 
     result := true; 
    end 
    else 
     result := false; 

    end 

    else 
    result := false; 
end ; 

Powyższy kod faktycznie działa, ale FindWindow znajdzie danym instans danej aplikacji zacząłem. Chcę osadzić dokładnie te instancje, które przeszedłem. Jeśli więc Notepad był uruchamiany kilka razy, nie ma możliwości, aby uzyskać poprawny za pomocą FindWindow.

Próbowałem:

Function TfrmEmbeddedExe.CreateProcessNewApplication : Boolean; 
var 
zAppName: array[0..512] of char; 
StartupInfo: TStartupInfo; 
ProcessInfo: TProcessInformation; 
Res : DWORD; 
DoWait : Boolean; 
begin 
    DoWait := False; 
    StrPCopy(zAppName, self.fexecuteFileName); //'C:\Windows\Notepad.exe' 
    FillChar(StartupInfo, Sizeof(StartupInfo), #0); 
    StartupInfo.cb := Sizeof(StartupInfo); 
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW; 
    StartupInfo.wShowWindow := SW_SHOWNORMAL; 

    if CreateProcess (zAppName, 
    nil, { pointer to command line string } 
    nil, { pointer to process security attributes } 
    nil, { pointer to thread security attributes } 
    false, { handle inheritance flag } 
    CREATE_NEW_CONSOLE or { creation flags } 
    NORMAL_PRIORITY_CLASS, 
    nil, { pointer to new environment block } 
    nil, { pointer to current directory name } 
    StartupInfo, { pointer to STARTUPINFO } 
    ProcessInfo) then { pointer to PROCESS_INF } 
    begin 
    if DoWait then //just set it to false... so it will never enter here 
    begin 
     WaitforSingleObject(ProcessInfo.hProcess, INFINITE); 
     GetExitCodeProcess(ProcessInfo.hProcess, Res); 
    end 
    else 
    begin 
     self.fAppWnd := ProcessInfo.hProcess; 

     Windows.SetParent(self.fAppWnd, self.Handle); 
     ShowWindow(self.fAppWnd, SW_SHOWMAXIMIZED); 
     CloseHandle(ProcessInfo.hProcess); 
     CloseHandle(ProcessInfo.hThread); 


    end; 

    result := true; 
    end 
    else begin 
    Result := false; 
    end; 
end; 

Proszę nie uruchamiać Powyższy kod! Daje to dziwne rezultaty, polegające na wybieraniu pozornie losowego okna w dowolnym miejscu we wszystkich działających aplikacjach i osadzaniu (nawet pozycje menu z menu startowego systemu Windows).

Więc w zasadzie potrzebuję, jak uruchomić aplikację i zgarnąć uchwyt do głównego okna aplikacji.

Każda pomoc jest bardzo ceniona

Pozdrowienia

Jens Fudge

+5

Uchwyt procesu nie jest uchwytem okna. Zobacz http://stackoverflow.com/questions/1888863/how-to-get-main-window-handle-from-process-id –

+0

Czytając tytuł, miałem właśnie wejść i nalegać, że to * musi * być duplikat, ale po zobaczeniu, że osadzasz tę aplikację na własną, to odróżnia ją od siebie. Świetne pytanie. –

+0

Nie dodawaj podpisów do swojego posta. [StackOverflow pokazuje już dla ciebie] (http://stackoverflow.com/faq#signatures). – Deanna

Odpowiedz

9

tutaj jest szorstki zarys tego, co trzeba zrobić. Zostawię kodowanie do ciebie:

  1. rozpocząć proces z obu ShellExecuteEx lub CreateProcess. Da to uchwyt procesu.
  2. Zadzwoń na WaitForInputIdle w uchwycie procesu. Daje to procesowi możliwość załadowania i uruchomienia pętli komunikatów.
  3. Przekaż uchwyt procesu do GetProcessId, aby uzyskać identyfikator procesu.
  4. Użyj EnumWindows, aby wyliczyć okna najwyższego poziomu.
  5. Przekaż każde z tych okien do GetWindowThreadProcessId, aby sprawdzić, czy nie znaleziono okna najwyższego poziomu w procesie docelowym.
  6. Po znalezieniu okna, którego identyfikator procesu pasuje do procesu docelowego, gotowe!

Nie zapomnij zamknąć uchwytów procesów, gdy skończysz z nimi.

+0

David Heffernan, to naprawdę brzmi jak droga do przodu, i zrobię to, kiedy znajdę czas. Wielkie dzięki za wyjaśnienie. –

Powiązane problemy