将CreateProcess输入流重定向到文件

3
我正在使用CreateProcess来替代我的代码中的system()调用。我之前使用的是:
system(xfoil.exe < create_results.txt");

我将使用以下内容替代它:
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter

LPCWSTR input_file = _tcsdup(TEXT(".\\create_results.txt"));

HANDLE inpfl = CreateFile(input_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
StartupInfo.hStdInput = inpfl;

ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo; //Only compulsory field
LPCWSTR exe_path =_tcsdup(TEXT(".\\xfoil.exe"));

if (CreateProcess(exe_path, NULL,
    NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
    NULL, &StartupInfo, &ProcessInfo))
{
    WaitForSingleObject(&ProcessInfo.hProcess, 2000);
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(inpfl);
}

else
{
    CloseHandle(inpfl);
    std::cout << "Could not create xfoil process" << std::endl;
}

原因是我需要控制进程允许运行的时间(在这种情况下为2000ms),但似乎这种方法不起作用。 我将进程的输入重定向到我想要作为输入的文件的句柄(以替换<运算符),但进程没有收到任何东西。它确实在单独的控制台中启动了xfoil.exe。


1
顺序很重要!你在哪里设置 hStdInput,在哪里调用 ZeroMemory - Some programmer dude
1
在为hStdInput赋值之前,您需要调用ZeroMemory。 - Martin Bonner supports Monica
1
将“vtc”翻译为“简单的排版错误”。 - Martin Bonner supports Monica
该死,这是一个新手错误。我已经改变了顺序,但它仍然不能按预期工作。 - Erdorath
文件已经正确打开了吗? - Some programmer dude
2个回答

4

您需要设置文件安全属性以允许句柄被继承,同时设置启动信息标志以使子进程使用传递的句柄:

::STARTUPINFO startup_information{};

::SECURITY_ATTRIBUTES security_attributes
{
    sizeof(::SECURITY_ATTRIBUTES)
,   nullptr
,   TRUE // allow handle to be inherited
};

::HANDLE const inpfl{::CreateFileW(input_file, GENERIC_READ, FILE_SHARE_READ, ::std::addressof(security_attributes), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)};
if(INVALID_HANDLE_VALUE == inpfl)
{
    auto const last_error{::GetLastError()};
    // handle error...
}

startup_information.cb = sizeof(startup_information);
startup_information.dwFlags = STARTF_USESTDHANDLES;
startup_information.hStdInput = inpfl;

为了完整起见,您应该提到原始代码中有两个错误:未设置dwFlags,并在分配hStdInput后调用ZeroMemory - Martin Bonner supports Monica
1
@MartinBonner 实际上有三个错误:提供空指针给安全属性会使句柄不可继承,因此子进程将无法使用它。我猜操作员已经想到了ZeroMemory的问题。 - user7860670
我正在尝试这个解决方案,肯定是正确的方向。ZeroMemory 是一个我没有立即注意到的愚蠢错误。我不知道标志和安全属性。 - Erdorath
看起来工作正常,我确实遇到了一些文件被另一个进程打开的错误,但我会很快解决,谢谢。从中学到了很多。 - Erdorath
1
如果创建(父)进程是控制台进程,则不 必须 使用 STARTUPINFO 标准句柄。例如,cmd.exe 从不使用它们。在这种情况下,当前的标准句柄(即通过 SetStdHandle 设置的句柄)将被继承到子控制台进程中,无论它们是否可继承以及子进程是否通过继承创建。非控制台的子进程也会继承其标准句柄中的句柄值,但实际上要继承句柄则需要将它们设置为可继承并使用继承创建进程,而 cmd.exe 总是使用这种方式。 - Eryk Sun

0
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter

LPCWSTR input_file = _tcsdup(TEXT(".\\create_results.txt"));

HANDLE inpfl = CreateFile(input_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
StartupInfo.hStdInput = inpfl;

在下一次调用之后,StartupInfo.hStdInput会发生什么?

ZeroMemory(&StartupInfo, sizeof(StartupInfo));

哎呀... hStdInput 现在被清零了

一开始需要这样做...

PROCESS_INFORMATION ProcessInfo = {};
STARTUPINFO StartupInfo = {};

...将防止您需要把任何东西归零... 查看

此外,根据CreateProcess StartupInfo 文档,对于hStdInput,必须将dwFlags设置为STARTF_USESTDHANDLES,否则默认输入是键盘缓冲区


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接