- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发我的库,它需要在运行时捕获和处理子进程的标准输出(和错误)。当使用 ReadFile 读取输出时出现问题,一旦进程结束(被杀死或退出)它就不会返回。
看起来像ReadFile
无法检测到管道的另一端(写句柄)已关闭。根据文档,它应该返回 FALSE
并将最后一个错误设置为 ERROR_BROKEN_PIPE
:
If an anonymous pipe is being used and the write handle has been closed, when ReadFile attempts to read using the pipe's corresponding read handle, the function returns FALSE and GetLastError returns ERROR_BROKEN_PIPE.
这是我的代码,我已经删除了不相关的部分:(注意:我已经更新了 allium_start
以遵循建议的更改,我保留原件以供引用,请使用更新的功能查找缺陷的代码)
bool allium_start(struct TorInstance *instance, char *config, allium_pipe *output_pipes) {
// Prepare startup info with appropriate information
SecureZeroMemory(&instance->startup_info, sizeof instance->startup_info);
instance->startup_info.dwFlags = STARTF_USESTDHANDLES;
SECURITY_ATTRIBUTES pipe_secu_attribs = {sizeof(SECURITY_ATTRIBUTES), NULL, true};
HANDLE pipes[2];
if (output_pipes == NULL) {
CreatePipe(&pipes[0], &pipes[1], &pipe_secu_attribs, 0);
output_pipes = pipes;
}
instance->startup_info.hStdOutput = output_pipes[1];
instance->startup_info.hStdError = output_pipes[1];
instance->stdout_pipe = output_pipes[0]; // Stored for internal reference
// Create the process
bool success = CreateProcessA(
NULL,
cmd,
NULL,
NULL,
config ? true : false,
0,
NULL,
NULL,
&instance->startup_info,
SecureZeroMemory(&instance->process, sizeof instance->process)
);
// Return on failure
if (!success) return false;
}
char *allium_read_stdout_line(struct TorInstance *instance) {
char *buffer = instance->buffer.data;
// Process the input
unsigned int read_len = 0;
while (true) {
// Read data
unsigned long bytes_read;
if (ReadFile(instance->stdout_pipe, buffer, 1, &bytes_read, NULL) == false || bytes_read == 0) return NULL;
// Check if we have reached end of line
if (buffer[0] == '\n') break;
// Proceed to the next character
++buffer; ++read_len;
}
// Terminate the new line with null character and return
// Special handling for Windows, terminate at CR if present
buffer[read_len >= 2 && buffer[-1] == '\r' ? -1 : 0] = '\0';
return instance->buffer.data;
}
allium_start
创建用于输出重定向的管道(它对 stdout 和 stderr 使用相同的管道来获取合并的流),然后创建子进程。另一个 allium_read_stdout_line
函数负责从管道读取输出并在遇到换行时返回它。
问题发生在 ReadFile
函数调用,如果进程退出后没有任何可读取的内容,它永远不会返回,根据我的理解,一个进程的所有句柄在它结束时都被 Windows 关闭,所以看起来 ReadFile
无法检测到另一端的管道(写句柄)已关闭。
我该如何解决这个问题?我一直在寻找解决方案,但到目前为止我还没有找到,一个可能的选择是使用多线程并将 ReadFile
放在一个单独的线程中,这样它就不会阻塞整个程序,通过使用该方法,我可以在等待读取完成时定期检查进程是否仍然存在...或者如果进程消失,则终止/停止线程。
我确实更喜欢解决问题而不是选择解决方法,但我愿意接受任何其他解决方案来使其发挥作用。提前致谢!
编辑:阅读@RemyLebeau 的回答和@RbMm 在该回答中的评论后,很明显我对句柄继承工作原理的理解存在根本性缺陷。所以我将他们的建议(SetHandleInformation
禁用读取句柄的继承并在创建子进程后关闭它)合并到我的 allium_start
函数中:
bool allium_start(struct TorInstance *instance, char *config, allium_pipe *output_pipes) {
// Prepare startup info with appropriate information
SecureZeroMemory(&instance->startup_info, sizeof instance->startup_info);
instance->startup_info.dwFlags = STARTF_USESTDHANDLES;
SECURITY_ATTRIBUTES pipe_secu_attribs = {sizeof(SECURITY_ATTRIBUTES), NULL, true};
HANDLE pipes[2];
if (output_pipes == NULL) {
CreatePipe(&pipes[0], &pipes[1], &pipe_secu_attribs, 0);
output_pipes = pipes;
}
SetHandleInformation(output_pipes[0], HANDLE_FLAG_INHERIT, 0);
instance->startup_info.hStdOutput = output_pipes[1];
instance->startup_info.hStdError = output_pipes[1];
instance->stdout_pipe = output_pipes[0]; // Stored for internal reference
// Create the process
bool success = CreateProcessA(
NULL,
cmd,
NULL,
NULL,
config ? true : false,
0,
NULL,
NULL,
&instance->startup_info,
SecureZeroMemory(&instance->process, sizeof instance->process)
);
// Close the write end of our stdout handle
CloseHandle(output_pipes[1]);
// Return on failure
if (!success) return false;
}
(以下文字原为 edit 2 之前)
但遗憾的是它仍然不起作用:(
编辑 2(接受答案后):它确实有效!请参阅我对已接受答案的最后评论。
最佳答案
您没有正确管理管道,或者更具体地说,您没有控制管道句柄的继承。不要让子进程继承您的管道 (output_pipes[0]
) 的读取句柄,否则当子进程结束时管道将无法正确中断。
阅读 MSDN 了解更多详情:
Creating a Child Process with Redirected Input and Output
使用 SetHandleInformation()
或 PROC_THREAD_ATTRIBUTE_LIST
来防止 CreateProcess()
将 output_pipes[0]
传递给子进程作为可继承的句柄。子进程不需要访问该句柄,因此无论如何都不需要将其传递到进程边界。它只需要访问管道的写入句柄 (output_pipes[1]
)。
关于winapi - ReadFile 在从子进程结束后读取 stdout 时不返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54416116/
一个非常简单的问题,如果我创建一个 HANDLE在 app1.exe 中,它得到值 0x01这个值是全局唯一的吗? 或者当其他一些进程创建一个 HANDLE 时是否有可能?也有值(value) 0x0
我正在使用winapi-rs crate并尝试获取cpu的使用率,但是我什至无法做到这一点。 PdhCollectQueryData转换为十六进制时将返回“-2147481643”,然后错误代码为“0
有人可以告诉我,在 winapi 中将进度条作为 TreeView 控件的一部分是否现实?我使用 GTK 制作了一个 GUI,并且使用进度条作为单元格元素效果很好,如下图所示。 我没有开发自定义控件的
有 getaddrinfo() 用于阻止主机解析,但是否有非阻塞方法? 最佳答案 我不认为有这样的事情,但你总是可以将它包装在一个线程中并使用信号量来表示完成。 关于winapi - 在 WINAPI
如果我知道 Hwnd,如何获取正在运行的应用程序的图标? 最佳答案 如果你有窗口的句柄,你可以使用 GetClassLong : HICON icon = (HICON)GetClassLong(wi
我正在尝试阅读 IMAGE_DOS_HEADER使用 definition of that structure 的模块来自 winapi箱。 这是我的工作代码: let mut IDH: IMAGE_
我目前正在阅读MSDN的文档,以将流渲染到音频渲染器。 换句话说,就是从麦克风播放我捕获的数据。 http://msdn.microsoft.com/en-us/library/dd316756%28
我有一个问题,希望你能帮我解决。已经没有我的研究运气了...尝试过 stackoverflow、google,甚至 yahoo... 如何在不使用鼠标的情况下强制显示工具提示? 我目前正在实现一些窗口
在 D 中,每次启动应用程序时,我的垃圾收集器都会崩溃。 Windows 模块: pragma(lib, "user32.lib"); import std.string; extern(Window
我正在学习 WinAPI C++ 的绘图形状 我试图在 WM_PAINT 上用一些代码绘制 2 个椭圆: PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps)
我使用 PostMessage 模拟鼠标事件并在记事本应用程序上进行了测试。 我不想通过发送鼠标事件来获得记事本应用程序的焦点。 仅当我在 PostMessage 参数中使用记事本的 ChildWin
如何使用 Win32 WinAPI 创建一个 EditBox,使其看起来像在 Visual C# 或 VB 中的 VS 设计器中放置一个编辑框(具有漂亮的顶部边框等)?这是一张图片,展示了它的外观以及
有CopyRect WinAPI function ,它只是复制一个 RECT到另一个。 自从我挖掘它以来,我一直对这个函数存在的原因很感兴趣。 是赋值运算符 ( = ) 还是 CopyMemory功
只是想知道是否有一种方法可以将数字打印到控制台通过调用。它可以是 10 进制,也可以是十六进制,我不介意。 我想看看一些函数返回的格式。 我宁愿不使用 WriteConsole 和大量 asm 来做这
这似乎部分有效,但我无法获取要打印的字符串值 pub fn test() { let mut buf: Vec = vec![0; 64]; let mut sz: DWORD = 0
在 Excel 中使用 Visual Basic,我可以使用 DECLARE 关键字声明 WinAPI 函数 - 例如 Declare Function SetLocaleInfo Lib "kern
..嗨,我有这个代码: #[cfg(windows)] extern crate winapi; use winapi::um::winuser::{FindWindowW, GetClientRec
我有一个 WH_CALLWNDPROC Hook 代码,它处理 WM_INITDIALOG 消息以获取有关消息框的信息。我可以获得“消息”、“标题”、“按钮”,但无法获得“图标”信息。我正在尝试使用如
这是我的源代码: extern crate user32; extern crate kernel32; use std::io::prelude::*; use std::net::TcpStrea
WinAPI OpenFile 函数返回 HFILE,例如 GetFileTime 需要 HANDLE。当我用 (HANDLE)some_hFile 喂它时,它似乎工作正常。这种类型有什么不同吗,或者
我是一名优秀的程序员,十分优秀!