全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:6981
推到 Plurk!
推到 Facebook!

用CreateProcess 怎麼截取輸出的結果阿

尚未結案
Egn
一般會員


發表:29
回覆:54
積分:16
註冊:2005-04-14

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-05-19 16:10:31 IP:61.230.xxx.xxx 未訂閱
我用createprocess去執行一個dos的command,但請問要怎麼把結果抓回來阿,我要用視窗顯示訊息,我有找到用shellexecute可以配何 > readme.txt 來抓取結果,可是我的程式一定要用createprocess才行..也有看到說寫一個bat檔,然後叫createprocess去執行它.. 我知道bat檔可以執行程式,但要怎麼把結果書出到檔案呢...
chris_shieh
高階會員


發表:46
回覆:308
積分:240
註冊:2004-04-26

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-05-19 17:39:02 IP:61.58.xxx.xxx 未訂閱
請參考 如何在delphi下跑DOS批次檔,並讀出DOS執行結果畫面 http://delphi.ktop.com.tw/topic.php?topic_id=47504 Creating a Child Process with Redirected Input and Output http://delphi.ktop.com.tw/topic.php?TOPIC_ID=23904 Using anonymous pipes to redirect standard input/output of a child process. http://delphi.ktop.com.tw/topic.php?TOPIC_ID=23905 @瞭解越多.懂得越少@ 發表人 - chris_shieh 於 2005/05/19 17:45:03
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-05-19 23:31:01 IP:219.137.xxx.xxx 未訂閱
Egn 您好:    我不清楚您在使用 CreateProcess() 時是如何設定參數的?但是提醒您,如果您是使用 AnsiString 去設定參數,那麼就必須要在有導向符號的位置前加上一個反斜線符號 (\) 才能正常使用導向符號,針對您本篇的狀況,給您一個範例如下:
UINT Result;
bool err = false;
DWORD dwExitCode;
STARTUPINFO StartupInfo = {0};
PROCESS_INFORMATION ProcessInfo;    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.wShowWindow = SW_HIDE;
AnsiString cmd = getenv("COMSPEC");
AnsiString msgfile = "msg.txt";
AnsiString cmdline = cmd " /c rasdial.exe \> " msgfile;    Result = CreateProcess(NULL, cmdline.c_str(), NULL, NULL, false, 0, NULL, NULL, &StartupInfo, &ProcessInfo);    if (Result) {
    CloseHandle(ProcessInfo.hThread);
    if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) != WAIT_FAILED) {
        GetExitCodeProcess(ProcessInfo.hProcess,&dwExitCode);
    }        CloseHandle(ProcessInfo.hProcess);        if(FileExists(msgfile)){
        Memo1->Lines->LoadFromFile(msgfile);
    }else{
        err = true;
    }
}else{
    err = true;
}    if(err) ShowMessage(msgfile   " not found!");
如果您想改用批次檔來處理,可參考這一篇討論中的方式: http://delphi.ktop.com.tw/topic.php?TOPIC_ID=70854 發表人 - RedSnow 於 2005/05/19 23:51:44
Egn
一般會員


發表:29
回覆:54
積分:16
註冊:2005-04-14

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-05-20 12:10:13 IP:61.230.xxx.xxx 未訂閱
好像可以了ㄝ...RedSnow你真神阿.. AnsiString cmd = getenv("COMSPEC"); AnsiString msgfile = "msg.txt"; AnsiString cmdline = cmd " /c rasdial.exe \> " msgfile; 為什麼這樣寫呢?不懂為什麼還有getenv...還有要加 /c... 而且我執行的時後,那個dos視窗之前會顯示訊息,現在不會,只是跑出一個dos視窗..用createprocess可以讓那個視窗不要出來嗎?還是只有用winexec,shellexecut才可已不要顯示呢~~~
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-05-20 13:20:36 IP:219.137.xxx.xxx 未訂閱
Egn 您好:
引言:好像可以了ㄝ...RedSnow你真神阿.. AnsiString cmd = getenv("COMSPEC"); AnsiString msgfile = "msg.txt"; AnsiString cmdline = cmd " /c rasdial.exe \> " msgfile; 為什麼這樣寫呢?不懂為什麼還有getenv...還有要加 /c... 而且我執行的時後,那個dos視窗之前會顯示訊息,現在不會,只是跑出一個dos視窗..用createprocess可以讓那個視窗不要出來嗎?還是只有用winexec,shellexecut才可已不要顯示呢~~~
getenv() 是取得系統環境變數的函式,COMSPEC 在環境變數中是設定 DOS 環境 command-line 解譯器的名稱,在 Windows 9x 等級的指令解譯器名稱是 COMMAND.COM,而 NT 等級 (WIN 2000, XP...) 的則為 CMD.EXE,因此透過 getenv("COMSPEC") 來取得指令解譯器的名稱,可以省略視窗版本的檢查與相關設定,以適用於不同版本的視窗環境。 加上 /c 參數是因為要告訴指令解譯器去執行後續所給予字串中所描述的指令,然後結束掉指令視窗,相關參數的說明可以開一個 DOS 視窗,然後輸入 cmd /? (或 command /?) 來查看。 我猜想是因為 DOS 視窗的設計問題,因此使用 CreateProcess() 配合 SW_HIDE 參數似乎會無效,DOS 視窗仍會一閃而過,您可以再試試看另一種方式,也就是用 ShellExecute() 來配合批次檔,當然啦~以您的 case 來看,其實也無需用到批次檔,例如:
AnsiString ProgPath = ExtractFilePath(ParamStr(0));
AnsiString prog = getenv("COMSPEC");
AnsiString msgfile = "msg.txt";
AnsiString parm = "/c rasdial.exe \> " msgfile;    ShellExecute(Application->Handle, "open", prog.c_str(), parm.c_str(), ProgPath.c_str(), SW_HIDE);
.....
不過您仍得另外加上一些檢查,待 msg.txt 檔案確實產生後,再去讀取檔案內容,動作類似我前一篇範例的後段一樣,您試試看吧。 發表人 - RedSnow 於 2005/05/20 13:33:41
Egn
一般會員


發表:29
回覆:54
積分:16
註冊:2005-04-14

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-05-20 13:40:56 IP:61.230.xxx.xxx 未訂閱
可是用shellexecute跟witforsingleobject,我的程式就停不下來,我還是要用createprocess才會讓程式先停下來,讓外部呼叫的跑完再繼續跑...不知道為什麼,我用網業尚說的配合waitforsingleobject就是聽不下來...這個問題之前也有跟你討論過了...所以我只能繼續走createprocess這條路
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-05-20 16:53:57 IP:219.137.xxx.xxx 未訂閱
Egn 您好:    我在前一篇回覆的結尾處不是提醒您得另外加上一些檢查,待 msg.txt 檔案確實產生後,再去讀取檔案內容了嗎? 對於等待的動作,您可以在執行 ShellExecute() 動作後,使用一個迴圈來做等待與檢查的動作,當確認那個 msg.txt 檔案被產生了之後,再去做讀取的動作,並且跳出前述的迴圈即可。 只不過當您在使用迴圈作上述動作時,您必須要加上容錯處理,以免程式陷入無限迴圏的狀態,再給您一個範例吧:
AnsiString ProgPath = ExtractFilePath(ParamStr(0));
AnsiString cmd = getenv("COMSPEC");
AnsiString msgfile = ProgPath "msg.txt";
AnsiString parm = "/c rasdial.exe \> \"" msgfile "\"";    DeleteFile(msgfile);
Memo1->Clear();    ShellExecute(Application->Handle, "open", cmd.c_str(), parm.c_str(), ProgPath.c_str(), SW_HIDE);    int timeout = 3000;  // 設定等待時間,若超過等待時間就跳出迴圈
bool err = true;
DWORD BeginTime = GetTickCount();
do {
    if(FileExists(msgfile)){  // 如果檔案確實存在
        int handle;
        long filelen;
        handle = open(msgfile.c_str(), O_RDONLY);
        filelen = filelength(handle);
        close(handle);
        if(filelen > 0){ // 如果檔案大小大於 0
            Sleep(200);  // 緩衝一下,讓檔案確實處於關閉狀態 (若檔案尚未關閉完成就進行讀取會產生錯誤)
            Memo1->Lines->LoadFromFile(msgfile); // 讀取檔案內容給 Memo 物件
            err = false;
            break;  // 跳出 while 迴圈
        }
    }
    Application->ProcessMessages();
} while ((GetTickCount() - BeginTime) < timeout);    if (err) ShowMessage("error! please try again.");
以上等待時間的設定值可以視個人的需要來做調整,Sleep() 所設定的緩衝值 200 也是隨意設的值,若發現無法獲得足夠的緩衝時間,那麼您可以自己再試著將該值調大些。
Egn
一般會員


發表:29
回覆:54
積分:16
註冊:2005-04-14

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-05-20 17:18:26 IP:61.230.xxx.xxx 未訂閱
我現在最怕的是檔案還在開啟狀太,因為我是用一個while(1)無窮迴圈趣讀它,輸出檔應該是要在,可是就怕讀的時後它還沒寫完...至於設一個time來限定多久沒讀到究跳出,基本上我是一定要讀到才行..所以才用無窮迴圈...我想說有沒有辦法判斷檔案是在open or close狀泰呢...
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-05-20 18:28:00 IP:219.137.xxx.xxx 未訂閱
引言:我現在最怕的是檔案還在開啟狀太,因為我是用一個while(1)無窮迴圈趣讀它,輸出檔應該是要在,可是就怕讀的時後它還沒寫完...至於設一個time來限定多久沒讀到究跳出,基本上我是一定要讀到才行..所以才用無窮迴圈...我想說有沒有辦法判斷檔案是在open or close狀泰呢...
如果您確定能夠排除其它可能意外狀況的發生,並且確定檔案一定會被產生,那麼您是可以使用無窮迴圈的。 但如果是我的話,我是不會鼓勵您那麼做的,因為 "意外" 或是 "例外" 狀況是很難全部都設想周全的,就算是您要連線到網路上,也是會有接不通的時候啊,沒有人可以確保每次都一定接得通的,況且連 WaitForSingleObject() 也有 time-out 的參數可供設置,除非您將它設為 INFINITE。 因此預留一個緩衝機制是很重要的,要不然很可能造成系統的不正常運作。 發表人 - RedSnow 於 2005/05/20 18:30:03
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-05-20 19:28:07 IP:219.137.xxx.xxx 未訂閱
告訴您一個好消息 - 我找到方法在 CreateProcess() 執行時不顯示 DOS 視窗的辦法了,其實這是設定參數的問題,我看我們兩個當初大概都太懶了,都沒有仔細的查看 Help 上的說明,您修改原敘述如下後再試試看:
.....
StartupInfo.wShowWindow = SW_HIDE;
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
.....
Result = CreateProcess(NULL, cmdline.c_str(), NULL, NULL, false, 0, NULL, NULL, &StartupInfo, &ProcessInfo);
.....
紅色的那一行是新增的。
chris_shieh
高階會員


發表:46
回覆:308
積分:240
註冊:2004-04-26

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-05-23 10:29:58 IP:202.133.xxx.xxx 未訂閱
這些在我提供給您參考的第一篇有提到 如何在delphi下跑DOS批次檔,並讀出DOS執行結果畫面 http://delphi.ktop.com.tw/topic.php?topic_id=47504 這篇是直接利用Pipe 重導執行結果到我們設定的地方 另外 ShellExecute 所產生的Handle並非真正的Handle 所以他不會對你的WaitForSingleObject產生作用 請參考http://delphi.ktop.com.tw/topic.php?TOPIC_ID=38858 如果希望利用檔案做為重導媒介, 底下這篇也可以作為參考 "擷取 dos 下程式產生的結果" http://delphi.ktop.com.tw/topic.php?topic_id=19897 Ktop 是一座大寶庫 建議您常利用關鍵字尋找文章 或是一開始不清楚時可以利用網友回應的內容中來擷取關鍵字搜尋 自己解決問題的能力會越來越好 可以讓自己功力大增 @瞭解越多.懂得越少@
roller
一般會員


發表:9
回覆:20
積分:5
註冊:2004-11-05

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-12-07 18:52:32 IP:218.170.xxx.xxx 未訂閱
我最近也在這方面的程式 也是參考RedSnow版主提供的方法, 使用CreateProcess()    不過我發現到, 不管使用ShellExecute()或是CreateProcess() 如果執行指令中的路徑含有"空白", 處理上就很麻煩    像是C:\Documents and Settings\會被當成C:\Documents 我想到可以加上引號來解決這問題("C:\Documents and Settings\") 然後似乎產生了更多問題及麻煩!    若是我要執行以下指令  
cmd /c C:\Documents and Settings\ML /Zm C:\Documents and Settings\x.asm > C:\Documents and Settings\output.txt 
可能就必須改成
 cmd /c "C:\Documents and Settings\ML" /Zm "C:\Documents and Settings\x.asm" > "C:\Documents and Settings\output.txt"
看起來似乎可以解決掉問題, 但是執行之後卻又一堆問題 有時候ML根本不運作, 或是">"沒有產生任何作用, 我可能要多加幾個引號才能完整執行我要的指令 然而若是執行指令內有數個含有"空白"的路徑, 處理上就會變的很麻煩 不知道大家有沒碰過這樣的問題, 有沒有其他更好的解決辦法呢? 謝謝.
bugmans
高階會員


發表:95
回覆:322
積分:188
註冊:2003-04-12

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-12-08 08:05:25 IP:218.166.xxx.xxx 未訂閱
或許你可以參考這篇文章http://delphi.ktop.com.tw/topic.php?topic_id=81640 在雙引號前面在加個反斜線或是將路徑轉成短檔名
roller
一般會員


發表:9
回覆:20
積分:5
註冊:2004-11-05

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-12-08 08:20:39 IP:218.170.xxx.xxx 未訂閱
引言: 或許你可以參考這篇文章http://delphi.ktop.com.tw/topic.php?topic_id=81640 在雙引號前面在加個反斜線或是將路徑轉成短檔名
轉成短檔名, 這個厲害. 謝謝你的提醒.
系統時間:2024-04-19 23:28:20
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!