代码适用于CLR项目但不适用于Win32

时间:2015-12-22 22:02:32

标签: c++ visual-studio winapi

我正在尝试运行

std::string exec(const char* cmd) {
    std::shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while (!feof(pipe.get())) {
         if (fgets(buffer, 128, pipe.get()) != NULL)
            result += buffer;
    }
    return result;
}

string domainNameList = exec("powershell.exe -Command \"$computers = Get-WsusComputer -All; $computers | foreach-object{ Write-Output $_.FullDomainName; }\"");

它似乎在我的纯CLR应用程序中工作正常,但是当我尝试在Win32应用程序中执行它时。我收到回复说

foreach-object{ is not recognized as a batch command

我不确定为什么管道会破坏一个字符串而不是另一个字符串,但我希望这可以在我的Win32应用程序中工作,所以我可以链接必要的DLL。

1 个答案:

答案 0 :(得分:2)

正如documentation所述:

  

_popen 函数创建一个管道,并使用指定的字符串命令异步执行命令处理器的衍生副本。

因此,在这种情况下,您的Win32代码实际上是启动cmd.exe的实例,然后将您的字符串传递给它。

|cmd.exe有特殊意义。由于涉及将命令输入cmd.exe所涉及的管道,它实际上最终将|解释为command redirection operator(即使它在输入字符串中的引号内)。它从左侧的命令获取输出并将其发送到右侧命令的输入。因此,在您的情况下,您实际上是在尝试执行命令:

powershell.exe -Command "$computers = Get-WsusComputer -All; $computers

并将其输出发送到此命令的输入:

foreach-object{ Write-Output $_.FullDomainName; }"

这就是为什么你得到一个关于foreach-object{是一个未知命令的错误。

要执行您尝试的操作,请尝试转义|字符,以便在解析过程中将其视为普通字符:

exec("powershell.exe -Command \"$computers = Get-WsusComputer -All; $computers ^| foreach-object{ Write-Output $_.FullDomainName; }\"");

有关详细信息,请参阅此页:

Syntax : Escape Characters, Delimiters and Quotes

  

逃脱角色

^  Escape character.
     

在命令符号之前添加转义字符允许将其视为普通文本。    在管道或重定向任何这些字符时,您应该使用转义字符作为前缀:& \ < > ^ |

 e.g.  ^\  ^&  ^|  ^>  ^<  ^^ 

或者,请考虑直接使用CreateProcess()代替_popen()。您可以使用命令字符串作为命令行参数而不是管道输入运行cmd.exe,然后您不必转义引号内的|字符(但您必须逃避额外的引用自己):

std::basic_string<TCHAR> cmd = TEXT("cmd.exe /C \"powershell.exe -Command \"\"$computers = Get-WsusComputer -All; $computers | foreach-object{ Write-Output $_.FullDomainName; }\"\"\"");
CreateProcess(NULL, const_cast<TCHAR*>(cmd.c_str()), ...);

要阅读输出,您可以告诉CreateProcess()将已启动流程的STDOUT句柄重定向到CreatePipe()的匿名管道,然后您可以使用ReadFile()从中读取:

Creating a Child Process with Redirected Input and Output

至于为什么一切都在CLR中正常工作,我不知道。我只能猜测CLR使用的命令处理器可能与cmd.exe不同,而且它正在以不同的方式解析命令字符串。