2014-10-03 66 views
-1

我正在使用此代碼,我在互聯網上找到它,並在某些設備上等待,但在其他設備上沒有。有人可以解釋我哪裏出錯了。我的應用程序在Truecrypt中加載,然後等待用戶輸入密碼。退出Truecrypt後,它會啓動我的菜單程序。我的聯想Miix 2 8「平板電腦,win8.1(所有最新)將等待,我爸爸的win8.0(全部最新)將等待,但我朋友的華碩M80TA 8」win8.1平板電腦(所有最新)將等待,我的朋友的華碩M80TA 8「win8.1平板電腦(所有最新)不會。另一位朋友的win7筆記本電腦(全部是最新的)不會等待以太網。執行和等待有時不工作

var 
    aTSI : TStartupInfo; 
    aTPI : TProcessInformation; 
    iRet : Integer; 
    ExitCode: Cardinal; 
begin 
    FillChar(aTSI, SizeOf(aTSI), #0); 
    FillChar(aTPI, SizeOf(aTPI), #0); 
    aTSI.CB:=SizeOf(aTSI); 
    if not CreateProcess(nil, PChar(sEXE), nil, nil, False, 
         NORMAL_PRIORITY_CLASS, 
         nil, nil, aTSI, aTPI) then 
    RaiseLastWin32Error; 
    repeat 
    iRet:=MsgWaitForMultipleObjects(1, aTPI.hProcess, 
    False, INFINITE, (QS_ALLINPUT)); 
    if iRet <> (WAIT_OBJECT_0) then 
     Application.ProcessMessages; 
    until iRet = (WAIT_OBJECT_0); // use this for normal programs 
    ExitCode:= 0; 
    if not GetExitCodeProcess(aTPI.hProcess, ExitCode) then 
    RaiseLastWin32Error; 
    Result:= ExitCode; 
    CloseHandle(aTPI.hProcess); 
end; 
+0

很難說。你有沒有做過任何調試?添加跟蹤記錄。此外,代碼至少泄漏一個,有時還會泄漏兩個句柄。你完全理解代碼嗎?如果不是,那麼這將是痛苦的。 – 2014-10-03 14:58:46

+0

此代碼是否在工作線程中?用'QS_ALLINPUT'標誌和'ProcessMessages'結合等待* loop *看起來非常可疑。 – TLama 2014-10-03 15:04:09

+0

此外,它應該只在'iRet =(WAIT_OBJECT_0 + 1)'時調用'Application.ProcessMessages',而不是在'iRet <> WAIT_OBJECT_0'時調用。'RaiseLastWin32Error'已被棄用一段時間,而是使用'RaiseLastOSError'。並且使用'try/finally'來確保無論是否引發異常,句柄總是處於關閉狀態。 – 2014-10-03 18:24:39

回答

0

可能的解釋如下:

  1. 你打電話的CreateProcess這將創建一個新的進程,並返回一個句柄這一進程。
  2. 第一個新過程反過來開始一個不同的過程,並立即返回。第二個過程就是您所看到的過程,並且相信這是您創建的過程。
  3. 您等待第一個進程句柄返回。

爲了解如何處理這個問題,您需要提供一些關於您嘗試啓動的過程的詳細信息。至於爲什麼代碼可以在某些機器上運行,而不是其他機器上運行的代碼,那很可能是目標應用程序的實現細節,即您所啓動的外部應用程序。據推測,它不同於機器。

看着代碼,它總是泄漏aTPI.hThread中返回的線程句柄。如果GetExitCodeProcess失敗,它會泄漏aTPI.hProcess

您還需要確保傳遞給命令行參數CreateProcess的字符串是可編輯的字符串,而不是存儲在只讀存儲器中的文字。

初始化ExitCode然後立即覆蓋它也是毫無意義的。更重要的是,您可以刪除ExitCode變量並將Result直接傳遞給GetExitCodeProcess

您的代碼也無法確認等待函數返回的錯誤。

我可能會寫這樣的:

function ExecAndWait(CommandLine: string): DWORD; 
var 
    si: TStartupInfo; 
    pi: TProcessInformation; 
    iRet: Integer; 
begin 
    UniqueString(CommandLine); 
    si := Default(TStartupInfo); 
    si.cb := SizeOf(si); 
    Win32Check(CreateProcess(nil, PChar(CommandLine), nil, nil, False, 
    NORMAL_PRIORITY_CLASS, nil, nil, si, pi)); 
    CloseHandle(pi.hThread); 
    try 
    while True do 
    begin 
     iRet := MsgWaitForMultipleObjects(1, pi.hProcess, False, INFINITE, QS_ALLINPUT); 
     Win32Check(iRet <> WAIT_FAILED); 
     case iRet of 
     WAIT_OBJECT_0: 
     break; 
     WAIT_OBJECT_0+1: 
     Application.ProcessMessages; 
     end; 
    end; 
    Win32Check(GetExitCodeProcess(pi.hProcess, Result)); 
    finally 
    CloseHandle(pi.hProcess); 
    end; 
end; 

在我的機器,當我通過'notepad.exe'這個函數,該函數不返回,直到記事本進程被關閉。

另一方面,如果我將'explorer.exe'傳遞給進程,則該函數立即返回。這裏發生的是一個新的瀏覽器進程啓動,但它檢測到一個已經運行,並要求該進程打開一個新窗口。新啓動的瀏覽器進程立即終止。

+0

謝謝。我不明白泄漏位,所以會研究比較你的變化的代碼。 ExitCode被初始化爲Delphi顯示警告「ExitCode可能沒有被初始化」我嘗試過使用Result ddirectly,但得到了一個關於「正式和var參數必須相等」的錯誤,但我現在意識到那是因爲函數被聲明瞭整數而不是DWORD。很多學習。 :)在所有情況下,機器都在「等待」之前和「等待」之前運行相同的應用程序。 – 2014-10-03 17:10:04

+0

不要期望答案中的代碼改變等待行爲。它不會。正如我試圖解釋你必須深入挖掘 – 2014-10-03 17:36:22

+0

謝謝,我明白,但它會返回一個Windows 998錯誤,「無效訪問內存」。我現在要辭職了。無論如何,因爲它變得越來越詭異。使用原始代碼和記事本作爲運行和等待的第一個應用程序,它不會在任何設備上等待。與正在啓動的應用程序有關。將不得不檢查Windows兼容性和安全設置。 – 2014-10-03 17:53:46