问题 C ++执行CMD命令


我在这里遇到了严重的问题。我需要通过C ++执行CMD命令行,而不显示控制台窗口。所以我不能用 system(cmd),因为窗口将显示。

我努力了 winExec(cmd, SW_HIDE),但这也不起作用。 CreateProcess 是我试过的另一个。但是,这适用于运行程序或批处理文件。

我结束了尝试 ShellExecute

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

任何人都可以看到上述代码有什么问题吗?我用过 SW_SHOWNORMAL 直到我知道这是有效的。

我真的需要一些帮助。没有任何事情发生,我已经尝试了很长一段时间。任何人都可以给出的任何建议都会很棒:)


4849
2017-07-19 15:51


起源

你检查过返回代码了吗? - Collin
我知道你已经得到了答案,但通常一个好主意是说它不起作用。 - Deanna
为什么不调用WMI_函数并将结果写入文件。没有窗口,只有您需要的数据。 - graham.reeds


答案:


将输出重定向到您自己的管道是一个更整洁的解决方案,因为它避免创建输出文件,但这工作正常:

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

您没有看到cmd窗口,并且输出按预期重定向。

你的代码可能失败了(除了 /C 因为你指定路径为 "c:\projects\b" 而不是 "c:\\projects\\b"


7
2017-07-19 17:33





你应该用 CreateProcess的 上 cmd.exe 随着 /C 用于隧道ipconfig命令的参数。 >在命令行上本身不起作用。你必须 以编程方式重定向标准输出


4
2017-07-19 15:59



如果是的话 cmd /c 命令行,然后当然 > 重定向将起作用。 - eryksun


这是我的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;
}

3
2018-03-11 08:28



感谢您的示例代码! - Jason Harrison


我在github上有一个类似的程序[windows7和10测试]

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

这是服务器程序

  1. 在Windows的UDP端口(5555)上侦听名为“Local Area Connection”的接口并接收udp数据包。
  2. 收到的udp数据包内容在cmd.exe上执行[请不要在运行命令后关闭cmd.exe并且输出字符串[执行的命令的输出]通过相同的udp端口反馈到客户端程序]。
  3. 换一种说法, 在udp数据包中收到的命令 - >解析的udp数据包 - >在cmd.exe上执行 - >输出在同一端口上发送回客户端程序

这不会显示“控制台窗口” 无需人员在cmd.exe上手动执行命令 remwin.exe可以在后台运行,也可以是瘦服务器程序


0
2017-10-30 00:28



嗨,看起来太多的监管,我把一个有效的测试链接,它通过代码测试的具体答案回答具体问题,不明白你的删除审查建议。您运行代码[MSVC],检查其输出,测试它,如果它不适合,删除它。 - particlereddy
对不起,我删除了我的评论。我的触发太快了...... - Jolta
阅读你的答案,我觉得你解决了这个问题。但是,Stack Overflow不鼓励以外部链接形式提供解决方案的答案。 - Jolta