2012-07-19 321 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