2013-12-20 57 views
-1

我正在使用的代碼波紋管運行幾個「Netsh的WLAN」,以檢查無線網絡連接狀態,連接到WiFi配置命令等CreateProcess的使用Netsh掛起/響應的應用[德爾福]

的我遇到的問題是,有時候應用程序會掛在任何命令上,這只是一個隨機的事情,再加上,有時候返回的輸出會被「無」覆蓋,當我調試它時似乎是一個計時問題。

我試着用Pascal運行命令的傳統方法,但它不能與netsh一起使用,方法是「cmd.exe/C netsh wlan ....」。

我很感激任何建議,讓這個凍結程序更好地工作或其他方法。

我正在運行DelphiXE5。

感謝

的樣本命令:netsh的WLAN顯示配置,netsh的WLAN顯示接口等

procedure GetDosOutput(const ACommand, AParameters: String; CallBack: TArg<PAnsiChar>); 
const 
CReadBuffer = 2400; 
var 
saSecurity: TSecurityAttributes; 
hRead: THandle; 
hWrite: THandle; 
suiStartup: TStartupInfo; 
piProcess: TProcessInformation; 
pBuffer: array [0 .. CReadBuffer] of AnsiChar; 
dBuffer: array [0 .. CReadBuffer] of AnsiChar; 
dRead: DWord; 
dRunning: DWord; 
begin 
saSecurity.nLength := SizeOf(TSecurityAttributes); 
saSecurity.bInheritHandle := True; 
saSecurity.lpSecurityDescriptor := nil; 

if CreatePipe(hRead, hWrite, @saSecurity, 0) then 
begin 
    FillChar(suiStartup, SizeOf(TStartupInfo), #0); 
    suiStartup.cb := SizeOf(TStartupInfo); 
    suiStartup.hStdInput := hRead; 
    suiStartup.hStdOutput := hWrite; 
    suiStartup.hStdError := hWrite; 
    suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; 
    suiStartup.wShowWindow := SW_HIDE; 

    if CreateProcess(nil, pChar(ACommand + ' ' + AParameters), @saSecurity, @saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess) then 
    begin 
     repeat 
      dRunning := WaitForSingleObject(piProcess.hProcess, 100); 
      Application.ProcessMessages(); 
      repeat 
       dRead := 0; 
       ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil); 
       pBuffer[dRead] := #0; 

       //OemToAnsi(pBuffer, pBuffer); 
       //Unicode support by Lars Fosdal 
       OemToCharA(pBuffer, dBuffer); 
       CallBack(dBuffer); 
      until (dRead < CReadBuffer); 
     until (dRunning <> WAIT_TIMEOUT); 
     CloseHandle(piProcess.hProcess); 
     CloseHandle(piProcess.hThread); 
    end; 
    CloseHandle(hRead); 
    CloseHandle(hWrite); 
end; 
end; 

以下後,所有的建議我改變了這個代碼部分,到目前爲止,該應用程序不是招再也不弔死了。 非常感謝!

procedure GetDosOutput(const ACommand, AParameters: String; CallBack: TArg<PAnsiChar>); 
const 
CReadBuffer = 2400; 
var 
saSecurity: TSecurityAttributes; 
hRead: THandle; 
hWrite: THandle; 
suiStartup: TStartupInfo; 
piProcess: TProcessInformation; 
pBuffer: array [0 .. CReadBuffer] of AnsiChar; 
dBuffer: array [0 .. CReadBuffer] of AnsiChar; 
dRead: DWord; 
dRunning: DWord; 
begin 
saSecurity.nLength := SizeOf(TSecurityAttributes); 
saSecurity.bInheritHandle := True; 
saSecurity.lpSecurityDescriptor := nil; 

if CreatePipe(hRead, hWrite, @saSecurity, 0) then 
begin 
    FillChar(suiStartup, SizeOf(TStartupInfo), #0); 
    suiStartup.cb := SizeOf(TStartupInfo); 
    suiStartup.hStdInput := hRead; 
    suiStartup.hStdOutput := hWrite; 
    suiStartup.hStdError := hWrite; 
    suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; 
    suiStartup.wShowWindow := SW_HIDE; 

    if CreateProcess(nil, pChar(ACommand + ' ' + AParameters), @saSecurity, @saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess) then 
    begin 
     Application.ProcessMessages(); 
     repeat 
      dRunning := WaitForSingleObject(piProcess.hProcess, 100); 

      repeat 
       dRead := 0; 

       try 
        ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil); 
       except on E: Exception do 
        Exit; 
       end; 

       pBuffer[dRead] := #0; 

       //OemToAnsi(pBuffer, pBuffer); 
       //Unicode support by Lars Fosdal 
       OemToCharA(pBuffer, dBuffer); 
       CallBack(dBuffer); 
      until (dRead < CReadBuffer); 

     until (dRunning <> WAIT_TIMEOUT); 
     CloseHandle(piProcess.hProcess); 
     CloseHandle(piProcess.hThread); 
    end; 
    CloseHandle(hRead); 
    CloseHandle(hWrite); 
end; 
end; 

我創造了這個包裝簡化流程:

function GetDosOutputSimple(const ACommand, AParameters: String) : String; 
var 
    Tmp, S : String; 
begin 
    GetDosOutput(ACommand, AParameters, procedure (const Line: PAnsiChar) 
    begin 
    Tmp := Line; 
    S := S + Tmp; 
    end); 

    GetDosOutputSimple := S; 
end; 
+0

你是不是檢查錯誤。很難看到過去。你爲什麼要調用Win32函數,遇到問題,而忽略錯誤檢查? –

+0

對不起,我沒有寫這個,如果你可以發佈任何改進,那就太好了。 –

+0

@David - 這隻會導致在這種情況下更好地描述該問題,因爲這是關於api沒有返回的。 –

回答

2

如果因任何原因,你叫ReadFile的時候,過程還沒有完成寫操作,或者你的緩衝區未填寫,ReadFile將阻止。通常它會失敗,但它不能,因爲你持有寫入端的句柄。見documentation

...父進程調用ReadFile的之前關閉其句柄到管道的 寫結束是很重要的。如果沒有完成, 讀取文件操作不能返回零,因爲父進程 有一個打開句柄到管道的寫入結束。

在從管道讀取之前如此接近'hWrite'。

請注意,在這種情況下 - 如果進程尚未能夠向管道寫入任何內容,而不是阻塞,ReadFile將正常失敗 - 並且GetLastError將報告ERROR_BROKEN_PIPE。在這種情況下,你可能會優雅地失敗。所以更好的檢查返回ReadFile


或者,等到過程終止。那麼你不會冒險ReadFile阻止等待寫作,因爲兒童側的把手將被關閉。

... 
repeat 
    dRunning := WaitForSingleObject(piProcess.hProcess, 100); 
    Application.ProcessMessages(); 
until (dRunning <> WAIT_TIMEOUT); 
repeat 
    dRead := 0; 
    ... 

如果有一個機會,你將有一些相當大的輸出,在應用程序運行時,從管道中讀取:

saSecurity.nLength := SizeOf(TSecurityAttributes); 
    saSecurity.bInheritHandle := True; 
    saSecurity.lpSecurityDescriptor := nil; 

    if CreatePipe(hRead, hWrite, @saSecurity, 0) then begin 
    try 
     FillChar(suiStartup, SizeOf(TStartupInfo), #0); 
     suiStartup.cb := SizeOf(TStartupInfo); 
     suiStartup.hStdInput := hRead; 
     suiStartup.hStdOutput := hWrite; 
     suiStartup.hStdError := hWrite; 
     suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; 
     suiStartup.wShowWindow := SW_HIDE; 

     if CreateProcess(nil, pChar(ACommand + ' ' + AParameters), @saSecurity, 
         @saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, 
         suiStartup, piProcess) then begin 
     CloseHandle(hWrite); 
     try 
      repeat 
      dRunning := WaitForSingleObject(piProcess.hProcess, 100); 
      Application.ProcessMessages(); 

      repeat 
       dRead := 0; 
       if ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil) then begin 
       pBuffer[dRead] := #0; 
       OemToCharA(pBuffer, dBuffer); 
       CallBack(dBuffer); 
       end; 
      until (dRead < CReadBuffer); 

      until (dRunning <> WAIT_TIMEOUT); 
     finally 
      CloseHandle(piProcess.hProcess); 
      CloseHandle(piProcess.hThread); 
     end; 

     end; 
    finally 
     CloseHandle(hRead); 
     if GetHandleInformation(hWrite, flags) then 
     CloseHandle(hWrite); 
    end; 
    end; 
+0

夥計們,我不太擅長這個API的東西,這完全是從互聯網上覆制,不記得我在哪裏。 我會盡量按照建議進行更改,但如果您可以在此發佈任何改進,我將不勝感激。 –

+1

@paul - 在這種情況下,如果你不明白你的代碼在做什麼,那麼你最好的選擇就是等待直到過程結束並從管道中讀取數據。將外部'直到'移到'Application.ProcessMessages'之後。我相信你可以檢查'ReadFile'的返回值,如果你自己出現任何問題,你可以退出。 –