2012-07-19 319 views
10

我在這裏有一個嚴重的問題。我需要通過C++執行CMD命令行,而不顯示控制檯窗口。因此,我不能使用system(cmd),因爲窗口將顯示。C++執行CMD命令

我已經試過winExec(cmd, SW_HIDE),但這也不管用。 CreateProcess是我試過的另一個。但是,這是爲了運行程序或批處理文件。

我已經結束了試圖ShellExecute

ShellExecute(NULL, "open", 
    "cmd.exe", 
    "ipconfig > myfile.txt", 
    "c:\projects\b", 
    SW_SHOWNORMAL 
); 

有人能看到什麼毛病上面的代碼?我用SW_SHOWNORMAL直到我知道這工作。

我真的需要一些幫助與此有關。沒有任何東西顯露出來,我一直在嘗試一段時間。任何人可以給的建議將是偉大的:)

+0

您是否檢查了返回碼? – Collin 2012-07-19 15:58:32

+1

我知道你已經有了一個答案,但通常說出它不工作是個好主意。 – Deanna 2012-07-20 08:18:58

+0

爲什麼不調用WMI_函數並將結果寫入文件。沒有窗口,只有你需要的數據。 – 2016-03-11 08:35:03

回答

6

將輸出重定向到自己的管道是一個整潔的解決方案,因爲它避免了創建輸出文件,但這個工作得很好:

ShellExecute(0, "open", "cmd.exe", "/C ipconfig > out.txt", 0, SW_HIDE); 

你沒有看到cmd窗口和預期輸出重定向。

您的代碼可能會失敗(除了/C之外),因爲您將路徑指定爲"c:\projects\b"而不是"c:\\projects\\b"

3

這裏是我的DosExec函數的實現,它允許(靜默)執行任何DOS命令並以unicode字符串的形式檢索生成的輸出。

// Convert an OEM string (8-bit) to a UTF-16 string (16-bit) 
#define OEMtoUNICODE(str) CHARtoWCHAR(str, CP_OEMCP) 

/* Convert a single/multi-byte string to a UTF-16 string (16-bit). 
We take advantage of the MultiByteToWideChar function that allows to specify the charset of the input string. 
*/ 
LPWSTR CHARtoWCHAR(LPSTR str, UINT codePage) { 
    size_t len = strlen(str) + 1; 
    int size_needed = MultiByteToWideChar(codePage, 0, str, len, NULL, 0); 
    LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed); 
    MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed); 
    return wstr; 
} 

/* Execute a DOS command. 

If the function succeeds, the return value is a non-NULL pointer to the output of the invoked command. 
Command will produce a 8-bit characters stream using OEM code-page. 

As charset depends on OS config (ex: CP437 [OEM-US/latin-US], CP850 [OEM 850/latin-1]), 
before being returned, output is converted to a wide-char string with function OEMtoUNICODE. 

Resulting buffer is allocated with LocalAlloc. 
It is the caller's responsibility to free the memory used by the argument list when it is no longer needed. 
To free the memory, use a single call to LocalFree function. 
*/ 
LPWSTR DosExec(LPWSTR command){ 
    // Allocate 1Mo to store the output (final buffer will be sized to actual output) 
    // If output exceeds that size, it will be truncated 
    const SIZE_T RESULT_SIZE = sizeof(char)*1024*1024; 
    char* output = (char*) LocalAlloc(LPTR, RESULT_SIZE); 

    HANDLE readPipe, writePipe; 
    SECURITY_ATTRIBUTES security; 
    STARTUPINFOA  start; 
    PROCESS_INFORMATION processInfo; 

    security.nLength = sizeof(SECURITY_ATTRIBUTES); 
    security.bInheritHandle = true; 
    security.lpSecurityDescriptor = NULL; 

    if (CreatePipe(
        &readPipe, // address of variable for read handle 
        &writePipe, // address of variable for write handle 
        &security, // pointer to security attributes 
        0   // number of bytes reserved for pipe 
        )){ 


     GetStartupInfoA(&start); 
     start.hStdOutput = writePipe; 
     start.hStdError = writePipe; 
     start.hStdInput = readPipe; 
     start.dwFlags  = STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW; 
     start.wShowWindow = SW_HIDE; 

// We have to start the DOS app the same way cmd.exe does (using the current Win32 ANSI code-page). 
// So, we use the "ANSI" version of createProcess, to be able to pass a LPSTR (single/multi-byte character string) 
// instead of a LPWSTR (wide-character string) and we use the UNICODEtoANSI function to convert the given command 
     if (CreateProcessA(NULL,     // pointer to name of executable module 
          UNICODEtoANSI(command), // pointer to command line string 
          &security,    // pointer to process security attributes 
          &security,    // pointer to thread security attributes 
          TRUE,     // handle inheritance flag 
          NORMAL_PRIORITY_CLASS, // creation flags 
          NULL,     // pointer to new environment block 
          NULL,     // pointer to current directory name 
          &start,     // pointer to STARTUPINFO 
          &processInfo    // pointer to PROCESS_INFORMATION 
         )){ 

      // wait for the child process to start 
      for(UINT state = WAIT_TIMEOUT; state == WAIT_TIMEOUT; state = WaitForSingleObject(processInfo.hProcess, 100)); 

      DWORD bytesRead = 0, count = 0; 
      const int BUFF_SIZE = 1024; 
      char* buffer = (char*) malloc(sizeof(char)*BUFF_SIZE+1); 
      strcpy(output, ""); 
      do {     
       DWORD dwAvail = 0; 
       if (!PeekNamedPipe(readPipe, NULL, 0, NULL, &dwAvail, NULL)) { 
        // error, the child process might have ended 
        break; 
       } 
       if (!dwAvail) { 
        // no data available in the pipe 
        break; 
       } 
       ReadFile(readPipe, buffer, BUFF_SIZE, &bytesRead, NULL); 
       buffer[bytesRead] = '\0'; 
       if((count+bytesRead) > RESULT_SIZE) break; 
       strcat(output, buffer); 
       count += bytesRead; 
      } while (bytesRead >= BUFF_SIZE); 
      free(buffer); 
     } 

    } 

    CloseHandle(processInfo.hThread); 
    CloseHandle(processInfo.hProcess); 
    CloseHandle(writePipe); 
    CloseHandle(readPipe); 

    // convert result buffer to a wide-character string 
    LPWSTR result = OEMtoUNICODE(output); 
    LocalFree(output); 
    return result; 
} 
+0

感謝您的示例代碼! – 2016-03-24 00:28:45

0

我有一個類似的方案[windows7的和10測試]在github

https://github.com/vlsireddy/remwin/tree/master/remwin

這是服務器程序,其

  1. 偵聽 「本地連接」 命名接口在窗口爲UDP端口(5555)並接收udp數據包。
  2. 收到的udp數據包內容在cmd.exe上執行[運行該命令後輸出字符串[執行命令的輸出]通過同一個udp端口反饋給客戶端程序],請不要關閉cmd.exe。 >解析UDP包 - - >上的cmd.exe執行 - 在UDP分組中接收
  3. 換句話說, 命令>發回同一端口上的客戶端程序輸出

這並不顯示「控制檯窗口」 沒有必要讓某人在cmd.exe上執行手動命令 remwin.exe可以在後臺運行並且它的瘦服務器程序

+0

嗨,看起來像太多的治安,我把一個有效的測試鏈接,並回答具體問題的具體答案與代碼測試,不明白你的刪除審查建議。你運行代碼[MSVC],檢查它的輸出,測試它,如果它不適合,刪除它。 – particlereddy 2017-10-30 19:19:38

+0

對不起,我刪除了我的評論。我的觸發器太快了...... – Jolta 2017-10-31 10:28:29

+0

閱讀你的答案,它看起來像我解決了這個問題。但是,堆棧溢出不利於以外部鏈接的形式提供解決方案。 – Jolta 2017-10-31 10:31:40