【发布时间】:2021-10-12 22:16:52
【问题描述】:
背景
我正在构建一个基本的 MFC 应用程序,它可以帮助我运行测试。 GUI 非常简洁。一个按钮开始测试,另一个按钮停止测试,加上一个静态文本对象显示几个字母和数字,指示测试正在执行的阶段。几周以来,这一直令人满意。
如果我的应用程序在执行测试时还进行了视频屏幕录制,我会发现它很有用。大计划是将 FFmpeg 库函数调用编译到代码中以实现此功能,但这肯定需要我数周的时间来学习、尝试和完成。同时,一个快速但足够的解决方案是从下载的 Windows 二进制构建中调用预编译的 ffmpeg.exe。
我在::OnBnClickedButtonStarttest() 方法中添加了代码以通过CreateProcess() 调用ffmpeg.exe。这工作正常。 FFmpeg 屏幕录制过程在一个新的控制台窗口中开始,并且很好地完成了它的预期工作。当我选择该控制台窗口并按 Ctrl+C 时,录制将停止并且我拥有所需的视频文件。我还在::OnBnClickedButtonStoptest() 方法中添加了代码,以将所需的Ctrl+C 发送到ffmpeg.exe 进程的STDIN,并在单击STOP 按钮时完成录制。这也工作正常。 大部分时间。
我的源代码的这两部分基于 Microsoft 在https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output 上发布的示例。
问题
大部分时间停止屏幕录制过程意味着它不会总是停止。有时解决方案不起作用。而且我找不到任何原因为什么大多数时间都有效的相同解决方案在其他时间碰巧失败。最终我宁愿隐藏 FFmpeg 控制台窗口并让它在幕后工作,但这需要一种可靠的方法来停止子进程,而我当前的代码被证明不能可靠地工作。注意:源代码顶部有一个#define BUFSIZE 128 行。
DWORD dwNumOfBytesToWrite = 7;
DWORD dwWritten = 0;
CHAR chBuf[BUFSIZE] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x0A, 0x0D, 0x03, 0x0A, 0x0D };
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwNumOfBytesToWrite, &dwWritten, NULL);
虽然发送单个 Ctrl+C (0x03) 应该会停止 ffmpeg 进程,但我还是发送了更多输入以确保。尽管如此,出于某种原因,我必须两次发送上述WriteFile 指令,才能真正看到进程停止。我不知道为什么。不过,这对我来说并不重要,只要第二次确实有效。
让我担心的是,有时子进程不会停止。无论我发送多少次以上WriteFile 行。
我发现了另一个有希望的例子。这次没有匿名管道 - 我怀疑这是不可靠行为的根源。
https://www.techpowerup.com/forums/threads/c-c-c-console-redirection-with-sockets-win32.62350/
这似乎使用自己的命名通道来访问子进程的标准输入。我更喜欢这种方法。不幸的是,它不仅不起作用,而且也无法编译。 Socket thisSocket; 行指的是不存在的类型。没有像Socket 这样的类型,没有大写的S 和小写的ocket。我尝试在其位置使用所有大写的SOCKET 类型,它确实可以编译,但相应修改的WriteFile((HANDLE)thisSocket, chBuf, dwNumOfBytesToWrite, &dwWritten, NULL); 行总是返回FAILURE,并且不会停止子进程。
为了让我的调查更加困难,大量的互联网搜索结果将我带到了与 WINSOCK 相关的主题。
我错过了什么吗?
为了巧妙地要求它完成录制,向 ffmpeg.exe 进程发送 Ctrl+C 的可靠方法是什么?
请注意,我可以通过TerminateProcess(g_ffmpeg_process_handle, 0) 残酷地杀死 FFmpeg 控制台窗口,但这并不总是允许孩子正确关闭视频文件,从而导致屏幕录制损坏。
【问题讨论】:
-
您是否尝试关闭输入管道以发出 EOF 条件的信号?类似this。
-
不要使用
WriteFile()将字节0x03发送到衍生进程的STDIN,而是尝试使用GenerateConsoleCtrlEvent()将CTRL-C 信号发送到衍生进程的控制台。见Can I send a ctrl-C (SIGINT) to an application on Windows? -
@rustyx:是的,我尝试关闭所有 I/O 句柄以及进程和线程句柄。这没什么区别。当 FFmpeg 进程确实停止时,即使这些句柄仍处于打开状态,它也会停止(并且我在进程停止后关闭它们)。并且当 FFmpeg 进程没有停止时,关闭这些句柄不会触发子进程的停止。我尝试放置第三个按钮,将“发送 Ctrl+C”和“关闭句柄”代码部分分开。
-
@RemyLebeau:在尝试 WriteFile(0x03) 之前,我也尝试过。不幸的是
GenerateConsoleCtrlEvent()从未关闭子进程。 -
Windows.Graphics.Capture不是 UWP API。事实上,甚至没有 UWP API 这样的东西。 UWP 是一个平台,它限制了针对该平台的程序的可用 API 表面。 API 本身作为 Windows 运行时类型公开,其中大部分可用于经典桌面应用程序。将系统服务用作备份计划的评级听起来像是优先级倒置问题。