2011-12-20 116 views
0

我需要啓動一個啓動命令行的進程(它不應該彈出,所以像後臺進程)。打開cmd並讀取和寫入它

然後我需要寫東西給它並定期讀取cmd的最後一行。

由於我的C++技能不是很好,我不知道如何實現這一點。

在僞方式我想過這樣的事情:

startProcess(); 
writeToCmd(); 
readFromCmd() { // Call that every given interval (e.g. 1000 ms) 
    if(returnValue >= 100) { 
     stopProcess(); 
    } 
} 

我敢肯定它會不會是那麼容易。如果有人能幫助我,這將是非常好的。 這個程序是用於windows的。建議操作後

編輯: 這是我到目前爲止已經做了(我做了一點點不同)

int errorCode; 

// Variables for CreateProcess() 
SECURITY_ATTRIBUTES sa; 
STARTUPINFO si; 
PROCESS_INFORMATION pi; 
PHANDLE hInRead, hInWrite; 
LPDWORD bytesWritten, bytesRead; 

// The CommandLine input 
TCHAR tcsCommandLine[] = _T("cmd /c format H: /fs:FAT32 /V:device"); 
//TCHAR tcsCommandLine[] = _T("cmd /c start D:\\foo.txt"); 

sa.nLength = sizeof(sa); 
sa.lpSecurityDescriptor = NULL; 
sa.bInheritHandle = true; 

ZeroMemory(&si, sizeof(si)); 
si.cb = sizeof(si); 
si.wShowWindow = SW_SHOW; // SW_HIDE FOR PRODUCTION 
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; 
si.hStdInput = hInRead; 
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 

ZeroMemory(&pi, sizeof(pi)); 

errorCode = CreatePipe(hInRead, hInWrite, &sa, 0); 

info = GetDriveInfo(m_wsNANDMountPoint); 

if(info.m_uSizeInMB > 2048) { 
    log("Wrong Mounting Point. Device has more than 2GB space."); 

    return false; 
} 
else { 
    // Start Formatting 
    if(!CreateProcess(NULL, tcsCommandLine, 
     NULL, NULL, 
     TRUE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL, NULL, 
     &si, 
     &pi)) { 

     log("CreateProcess failed. Could not format Drive"); 
     return false; 
    } 

    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 

    WriteFile(hInWrite, "#13#10'J'#13#10", 5, bytesWritten, NULL); 
    CloseHandle(hInWrite); 

    // Wait until child process exits 
    WaitForSingleObject(pi.hProcess, 1100); 
} 

return true; 

調試的一點點後,我認識到,沒有按代碼」在ZeroMemory()牛逼突破,但

errorCode = CreatePipe(hInRead, hInWrite, &sa, 0); 

Access violation writing location錯誤。我不知道我在做什麼錯。 如果你們能夠幫助我,這將會非常棒。

+2

這並沒有多大意義。你能否提供一些有關實際問題的更多細節,而不是你如何設想解決方案的外觀。無論問題出在哪,每秒輪詢肯定不是解決方案。 – 2011-12-20 13:16:55

回答

1

命令行由兩個部分組成,你會感興趣的

  1. 執行程序
  2. 一種無論是在屏幕

既然你不上寫緩衝的地方t需要屏幕可見,那麼你的程序需要這兩樣東西。所以從這裏開始,忘了cmd。

要在程序中執行程序,您有很多方法。如果您希望執行行完全按照您在cmd中編寫它的方式進行操作,則可以使用system(儘管fork/exec的Windows版本更有意義)。例如:

system("my_prog.exe --option file.txt"); 

其執行my_prog.exe--optionfile.txt作爲參數。

現在第二個,你說你想讀cmd的最後一行。實現這一點的想法是在文件中輸出所有內容,而不是在cmd中。

如果你只在每個實例中的最後一行有興趣,你可以在你的程序的輸出重定向到一個像這樣的文件:

system("my_prog.exe --option file.txt > output.txt"); 

,或者如果你想保持整個歷史,你可以追加而不是覆蓋:

system("my_prog.exe --option file.txt >> output.txt"); 

如果你也想重定向stderr,你可以寫:

system("my_prog.exe --option file.txt &> output.txt"); 

符號可能是linuxy,請在您的Windows中嘗試它,看看它是否工作(手動在一個普通的cmd中)。你也可以搜索谷歌的「外殼重定向」,你會得到很多結果。

無論如何,如果你想讓cmd的最後一行也包含命令本身,你可以在程序中覆蓋/附加命令行。

+0

好主意。在Windows 7上,命令語法也適用於我,關於'>'和'>>'。 – 2017-01-04 16:38:08

2

在這種情況下你需要做的是創建一個帶有隱藏窗口的控制檯。如果您使用CreateProcess啓動控制檯,則應該可以通過STARTUPINFO結構設置窗口的可見性。

下一步是重定向控制檯的輸入和輸出。您可以通過將3個控制檯句柄(輸入,輸出,錯誤)附加到管道並從父進程讀取它來完成此操作。 This MSDN article描述瞭如何做到這一點。

+0

我試過了。但是我總是在這一行上遇到'訪問衝突寫入位置...'錯誤:'ZeroMemory(&si,sizeof(STARTUPINFO));' – 2011-12-20 14:24:53

+0

除非'si'被寫保護(讀-只要)。在原始問題中發佈您當前的努力,我們可以爲您提供更多幫助。 – 2011-12-20 15:23:50

-1

讓我將它添加到這些優秀的答案:

這個偉大的鏈接演示控制檯讀取和寫入:http://www.adrianxw.dk/SoftwareSite/Consoles/Consoles2.html

要定期做的東西,使用SetTimer()http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

SetTimer函數每x毫秒執行一次函數。 示例: 以下控制檯程序的工作原理如下:它使用SetTimer 設置一個計時器,然後在消息循環中循環。消息循環接收並處理WM_TIMER消息 並且還針對每個時間間隔調用定時器回調。 簡單地把你想做的東西放在TimerProc()函數中。

#define STRICT 1 
#include <windows.h> 
#include <iostream.h> 

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) 
{ 
    //put the stuff you want done in here 

    cout << "Doing stuff Time: " << dwTime << '\n'; 
    cout << "--------------------------------------------------\n" ; 
    cout.flush(); 
} 

int main(int argc, char *argv[], char *envp[]) 
{ 
    int Counter=0; 
    int usage_Time_millisec=1000; 
    MSG Msg; 

    UINT TimerId = SetTimer(NULL, 0, usage_Time_millisec, &TimerProc); //bind TimerProc() to SetTimer() 

    cout << "TimerId: " << TimerId << '\n'; 

    if (!TimerId) return 16; 

    while (GetMessage(&Msg, NULL, 0, 0)) 
    { 
     ++Counter; 
     if (Msg.message == WM_TIMER) 
     cout << "Doing stuff Counter: " << Counter << "; timer message\n"; 
     else 
     cout << "Doing stuff Counter: " << Counter << "; message: " << Msg.message << '\n'; 
     DispatchMessage(&Msg); 
    } 

    KillTimer(NULL, TimerId); 

return 0; 

} 
+0

用計時器輪詢不是答案。 – 2011-12-21 07:54:10