2012-09-05 3 views
5

Delphi에서 응용 프로그램을 시작하고 핸들을 얻으려는 경우,이 응용 프로그램의 기본 창을 TFrame 유형의 프레임에 포함시킬 수 있습니다.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 ; 

위의 코드는 실제로 작동하지만를 FindWindow 내가 시작 응용 프로그램의 특정 instans을 발견 할 것이다 : 지금까지 나는 노력했다. Shellexecuted가 설치 한 정확한 instans를 포함하고 싶습니다. 메모장을 두 번 시작했다면 FindWindow를 사용하여 올바른 방법을 얻을 수있는 방법이 없습니다.

나는 시도했다 :

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; 

위의 코드를 실행하지 마십시오! 그것은 모든 실행중인 응용 프로그램에서 어디서든 겉보기 임의의 창을 선택하고 그 포함 (Windows 시작 메뉴에서 메뉴 항목조차도 포함)과 관련된 이상한 결과를 생성합니다.

그래서 기본적으로 내가 응용 프로그램을 시작하고 잡는 방법입니다 응용 프로그램 주 창의 핸들.

어떤 도움은 매우

감사

옌스 퍼지

+5

프로세스 핸들은 창 핸들이 아닙니다. http://stackoverflow.com/questions/1888863/how-to-get-main-window-handle-from-process-id –

+0

제목을 읽고, 나는 들어 와서 이것이 * 반드시 *되어야한다고 주장했다. 중복되지만이 응용 프로그램을 자신의 것으로 포함시키는 것을 본 후에는이를 구분하지 않습니다. 좋은 질문입니다. –

+0

게시물에 서명을 추가하지 마십시오. [StackOverflow 이미 하나를 보여줍니다] (http://stackoverflow.com/faq#signatures). – Deanna

답변

9

이 여기에 당신이해야 할 일의 거친 개요입니다 감사합니다. 나는 당신에게 코드를 남겨 둘 것입니다.

  1. ShellExecuteEx 또는 CreateProcess으로 프로세스를 시작하십시오. 그러면 프로세스 핸들이 생성됩니다.
  2. 프로세스 핸들에서 WaitForInputIdle으로 전화하십시오. 이렇게하면 프로세스가 메시지 루프를로드하고 시작할 수 있습니다.
  3. 프로세스 ID를 얻기 위해 프로세스 핸들을 GetProcessId으로 전달하십시오.
  4. EnumWindows을 사용하면 최상위 창을 열거 할 수 있습니다.
  5. 각 창을 GetWindowThreadProcessId으로 전달하여 대상 프로세스의 최상위 창을 찾았는지 확인하십시오.
  6. 프로세스 ID가 대상 프로세스와 일치하는 창을 찾으면 완료됩니다!

작업 처리가 끝나면 프로세스 핸들을 닫는 것을 잊지 마십시오.

+0

데이비드 헤 퍼넌 (David Heffernan), 앞으로 나아갈 길과 같을 것입니다. 시간이 지나면 바로 그걸 할 것입니다. 설명해 주셔서 감사합니다. –

관련 문제