代码在CLR项目中有效,但在Win32中无效

Code works in CLR project but not Win32

本文关键字:但在 Win32 无效 有效 CLR 项目 代码      更新时间:2023-10-16

我正在尝试运行

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。

如文档所述:

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

因此,在这种情况下,Win32代码实际上是启动cmd.exe的一个实例,然后通过管道将字符串发送到它

CCD_ 2对CCD_ 3具有特殊意义。由于将命令放入cmd.exe涉及管道,因此它实际上最终将|解释为命令重定向运算符(即使它位于输入字符串中的引号内)。它获取左侧命令的输出,并将其发送到右侧命令的输入。因此,在您的情况下,您实际上是在尝试执行命令:

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; }"");

有关更多详细信息,请参阅本页:

语法:转义符、分隔符和引号

转义符

^  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():从中读取

创建具有重定向输入和输出的子进程

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

相关文章: