gpt4 book ai didi

c++ - 使用 C/C++ 通过管道向/从 Powershell 设置 UTF-8 输入和获取 UTF-8 输出

转载 作者:行者123 更新时间:2023-12-05 05:56:51 26 4
gpt4 key购买 nike

我无法将正确的 utf-8 字符串写入 powershell 子进程。 ASCII 字符有效,但 utf-8 字符有效,例如'ü', 会有不同的解释。从同一个 powershell 子进程读取时出现同样的问题。

总结:我想通过我的程序使用 utf-8 编码的 powershell。

更新:使用 AllocConsole(); 分配控制台,然后调用 SetConsoleCP(CP_UTF8);SetConsoleOutputCP(CP_UTF8);,正如@mklement 在他的文章中提到的回答,对我有用,如果你有一个没有任何控制台的 GUI 应用程序。如果您有控制台应用程序,则无需手动分配控制台。

更新 2:如果您有一个 GUI 并调用了 AllocConsole(),您可以在之后调用 ShowWindow(GetConsoleWindow(), SW_HIDE); 来隐藏控制台,如前所述 here .

到目前为止我尝试了什么:

  • 将输入和输出编码设置为 utf-8$OutputEncoding = [System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8 进程内
  • 对 UTF-16 执行相同的操作以防出现错误,例如...ext.Encoding]::Unicode
  • 对 ISO-Latin 1 (cp1252) 做同样的事情
  • 使用 wchar_t 作为所有测试编码的缓冲区和输入
  • 测试给定字符串的字节顺序
  • 测试 Unicode(每个字符 4 个字节,而不是 2 个)
  • 自己一点一点地构建字符串
  • 将编译器标志设置为\D UNICODE

编写代码示例:

std::string test("ls ä\n");
DWORD ret = WriteFile(std_in_write, test.c_str(), test.size(), &number_of_bytes_written, nullptr);
if (ret == 0) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_WRITE_TO_FILE, GetLastError());
}

输出:ls├ñ

示例代码:

HANDLE std_in_read = nullptr;
HANDLE std_in_write = nullptr;
HANDLE std_out_read = nullptr;
HANDLE std_out_write = nullptr;
SECURITY_ATTRIBUTES security_attr;
STARTUPINFO startup_info;
PROCESS_INFORMATION process_information;
DWORD buffer_size = 1000000;

security_attr = {sizeof(SECURITY_ATTRIBUTES), nullptr, true};

if (!CreatePipe(&std_in_read, &std_in_write, &security_attr, buffer_size)) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_CREATE_IN_PIPE, GetLastError());
}

if (!CreatePipe(&std_out_read, &std_out_write, &security_attr, buffer_size)) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_CREATE_OUT_PIPE, GetLastError());
}

GetStartupInfo(&startup_info);
startup_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
startup_info.wShowWindow = SW_HIDE;
startup_info.hStdOutput = std_out_write;
startup_info.hStdError = std_out_write;
startup_info.hStdInput = std_in_read;

if (!CreateProcess(TEXT(default_powershell_path), nullptr, nullptr, nullptr, TRUE, 0, nullptr, TEXT(default_windows_path), &startup_info, &process_information)) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_CREATE_PROCESS, GetLastError());
}

std::string test("ls ä\n");
DWORD ret = WriteFile(std_in_write, test.c_str(), test.size(), &number_of_bytes_written, nullptr);
if (ret == 0) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_WRITE_TO_FILE, GetLastError());
}

DWORD dword_read;
while (true) {
DWORD total_bytes_available;
if (PeekNamedPipe(std_out_read, nullptr, 0, nullptr, &total_bytes_available, nullptr) == 0) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_COPY_FROM_PIPE, GetLastError());
}

if (total_bytes_available != 0) {
DWORD minimum = min(buffer_size, total_bytes_available);
char buf[buffer_size];
if (ReadFile(std_out_read, buf, minimum, &dword_read, nullptr) == 0) {
throw PowershellHelper::Exception(PowershellHelper::Exception::Error::COULD_NOT_READ_FILE, GetLastError());
}

std::string tmp(buf);
std::cout << tmp << std::endl;
}

if (total_bytes_available == 0) {
break;
}

std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

注意:redirect-input-and-output-of-powershell-exe-to-pipes-in-c 没有重复项,因为该代码仅适用于 ASCII 字符,根本无法处理 utf-8 字符。

也没有重复 c-getting-utf-8-output-from-createprocess ,因为建议的解决方案不会像上面提到的那样工作,我想输入 utf-8 以及读取 utf-8。

最佳答案

您需要将控制台输入和输出代码页设置为65001 (UTF-8)创建您的 PowerShell 进程,通过SetConsoleCPSetConsoleOutputCP WinAPI 函数,因为 PowerShell CLI使用它们来解码其 stdin 输入并对其 stdout 输出进行编码。

(相比之下,$OutputEncoding = [System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8 仅适用于 PowerShell 内部- PowerShell 进行外部程序调用时的 session 。)

注意:如果调用进程本身不是控制台应用程序,您可能必须在调用 SetConsoleCP 之前分配一个控制台SetConsoleOutputCP,使用 AllocConsole WinAPI 函数,但坦率地说,我不清楚 (a) 这是否使该控制台立即可见(这可能是不受欢迎的)和 (b) CreateProcess 是否然后调用会自动使用此控制台。

它不起作用,您可以通过 cmd.exe 调用并在调用 powershell.exe 之前调用 chcp,沿着这些行cmd/c "chcp 65001 >NUL & powershell -c ..."; chcp 65001 将控制台代码页设置为 65001,即 UTF-8。

(这会引入额外的开销,但与 powershell.exe 进程相比,cmd.exe 进程相对轻量级,chcp 也是如此。 com).

这是一个示例命令,您可以从 PowerShell 运行以进行演示:

& {

# Save the current code pages.
$prevInCp, $prevOutCp = [Console]::InputEncoding, [Console]::OutputEncoding

# Write the UTF-8 encoded form of string 'kö' to a temp. file.
# Note: In PowerShell (Core) 7+, use -AsByteStream instead of -Encoding Byte
Set-Content temp1.txt -Encoding Byte ([Text.UTF8Encoding]::new().GetBytes('kö'))

# Switch to UTF-8, pipe the UTF-8 file's content to PowerShell's stdin,
# verify that it was decoded correctly, and output it, again encoded as UTF-8.
cmd /c 'chcp 65001 >NUL & type temp1.txt | powershell -nop -c "$stdinLine = @($input)[0]; $stdinLine -eq ''kö''; Write-Output $stdinLine" > temp2.txt'

# Read the temporary file as UTF-8 and echo its content.
Get-Content -Encoding Utf8 temp2.txt

# Clean up.
Remove-Item temp[12].txt
# Restore the original code pages.
[Console]::InputEncoding = $prevInCp; [Console]::OutputEncoding = $prevOutCp

}

这会输出以下内容,表明 powershell 调用正确读取了 UTF-8 编码的输入并将其输出为 UTF-8:

True
ö

注意:

您可以使用进程内的 PowerShell SDK绕过 字符编码问题 作为创建 powershell.exe 子进程的替代方法,尽管我不知道从 C++ 中这样做有多痛苦。有关 C# 示例,请参阅 this answer .

关于c++ - 使用 C/C++ 通过管道向/从 Powershell 设置 UTF-8 输入和获取 UTF-8 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68988696/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com