2009-11-11 3 views
13

높은 권한으로 내 프로그램에서 다른 응용 프로그램을 시작하려고 시도하고 있습니다. 계속하기 전에 종료 될 때까지 기다립니다.Delphi : 높은 상태의 응용 프로그램을 시작하고 종료 될 때까지 기다리는 방법?

웹상에서 여러 가지 솔루션을 시도했지만 제대로 작동하는 솔루션을 찾을 수 없습니다.

아래의 코드는 내가 올바르게 작동하는 데 가장 가까운 코드입니다. 높은 권한으로 앱을 실행하고 앱이 종료 될 때까지 대기하지만 외부 앱이 종료되면 앱이 정지됩니다. 즉, 실행 된 앱이 닫히면 처리를 계속하지 않습니다.

내가 여기있는 것을 어떻게 성취 할 수 있습니까?

procedure TfMain.RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string); 
var 
    sei: TShellExecuteInfo; 
begin 
    FillChar(sei, SizeOf(sei), 0); 
    sei.cbSize := SizeOf(sei); 
    sei.Wnd := hWnd; 
    sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; 
    sei.lpVerb := 'runas'; 
    sei.lpFile := PChar(aFile); 
    sei.lpParameters := PChar(aParameters); 
    sei.nShow := SW_SHOWNORMAL; 

    if not ShellExecuteEx(@sei) then 
    RaiseLastOSError 
    else 
    while WaitForSingleObject(sei.hProcess, 50) <> WAIT_OBJECT_0 do 
     Application.ProcessMessages; 

    CloseHandle(sei.hProcess); 
end; 

업데이트 :

나는 다음과 같은 기능을 마련했지만, 나는 그것을 호출 후 ShowMessage 문이있는 경우에만 작동합니다. 그래서, 나는 가지고 있어야한다 :

RunFileAsAdminWait(Handle, ExtractFilePath(Application.Exename) + 'AutoUpdate.exe', '/auto'); 
ShowMessage('test'); 

기능을 작동하게하기 위해. ShowMessage 호출없이 어떻게 작동시킬 수 있습니까? 여기

업데이트 된 기능입니다 :

procedure TfMain.RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string); 
var 
    sei: TShellExecuteInfo; 
begin 
    FillChar(sei, SizeOf(sei), 0); 
    sei.cbSize := SizeOf(sei); 
    sei.Wnd := hWnd; 
    sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; 
    sei.lpVerb := 'runas'; 
    sei.lpFile := PChar(aFile); 
    sei.lpParameters := PChar(aParameters); 
    sei.nShow := SW_SHOWNORMAL; 

    if not ShellExecuteEx(@sei) then 
    RaiseLastOSError 
    else 
    if sei.hProcess <> 0 then 
     WaitForSingleObject(sei.hProcess, 50) 
    else 
     Exit; 

    CloseHandle(sei.hProcess); 
end; 

답변

15

다음 코드는 나를 위해 작동은 :

procedure RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string); 
var 
    sei: TShellExecuteInfo; 
begin 
    FillChar(sei, SizeOf(sei), 0); 
    sei.cbSize := SizeOf(sei); 
    sei.Wnd := hWnd; 
    sei.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS; 
    sei.lpVerb := 'runas'; 
    sei.lpFile := PChar(aFile); 
    sei.lpParameters := PChar(aParameters); 
    sei.nShow := SW_SHOWNORMAL; 

    if not ShellExecuteEx(@sei) then 
    RaiseLastOSError; 
    if sei.hProcess <> 0 then begin 
    while WaitForSingleObject(sei.hProcess, 50) = WAIT_TIMEOUT do 
     Application.ProcessMessages; 
    CloseHandle(sei.hProcess); 
    end; 
end; 

당신이 기다리는 프로세스 핸들을 얻을 수있는 SEE_MASK_NOCLOSEPROCESS 플래그를 전달합니다. 또한 WaitForSingleObject()이 시간 초과와 함께 반환하는 한 코드를 루프로 변경했습니다.

플래그에 대한 자세한 내용은 SHELLEXECUTEINFO 구조의 MSDN 페이지를 참조하십시오.

+0

완벽하게 작동했습니다! – croceldon

+1

WaitForSingleObject() 대신에'MsgWaitForMultipleObjects()'를 사용하는 것이 더 효율적일 것입니다. 그래서 메시지가 처리되기를 기다리고 있다고 말할 때만'Application.ProcessMessages()'를 호출 할 수 있습니다. t 맹목적으로'ProcessMessages()'를 불필요하게 호출. –

0

귀하의 대기 (50 밀리가 너무 짧다),

WaitForSingleObject(sei.hProcess, INFINITE) 

유효한 프로세스 핸들에 대한 확인을 시도 (sei.hProcess <> 0) 할 수 빠져 나가지.

수정 답변 :

while MsgWaitForMultipleObjects(1, sei.hProcess, False, INFINITE, QS_ALLINPUT) 
    <> WAIT_OBJECT_0 do 
    begin 
    while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do 
    begin 
     DispatchMessage(Msg); 
    end; 
    end; 
+1

이렇게하면 더 이상 메시지를 처리하지 않아 호출 응용 프로그램이 중단 된 것처럼 보입니다. – mghie

+0

죄송합니다. 동결에 ​​관한 부분을 간과 했으므로 대답을 수정했습니다. – Remko

+0

'MsgWaitForMultipleObjects() '가 WAIT_OBJECT_0 + 1 만 반환하는 경우에만 메시지를 처리해야합니다. 그에 따라 다른 반환 값을 처리하십시오. –

3

@ mghie의 대답에있는 코드는 일반적으로 올바른 생각이지만 프로세스 핸들을 기다리는 동안 메시지를 처리하는 코드가 더 좋을 수 있습니다. 시도해보십시오.

procedure RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string); 
var 
    sei: TShellExecuteInfo; 
    Ret: DWORD; 
begin 
    FillChar(sei, SizeOf(sei), 0); 
    sei.cbSize := SizeOf(sei); 
    sei.Wnd := hWnd; 
    sei.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS; 
    sei.lpVerb := 'runas'; 
    sei.lpFile := PChar(aFile); 
    sei.lpParameters := PChar(aParameters); 
    sei.nShow := SW_SHOWNORMAL; 

    if not ShellExecuteEx(@sei) then 
    RaiseLastOSError; 
    if sei.hProcess <> 0 then 
    try 
    repeat 
     Ret := MsgWaitForMultipleObjects(1, sei.hProcess, False, INFINITE, QS_ALLINPUT); 
     if Ret = (WAIT_OBJECT_0+1) then Application.ProcessMessages 
     else if Ret = WAIT_FAILED then RaiseLastOSError; 
    until Ret = WAIT_OBJECT_0; 
    finally 
    CloseHandle(sei.hProcess); 
    end; 
end; 
+0

이 상세한 답변을 작성해 주셔서 감사합니다, 레미. –

관련 문제