在C# WPF GUI中嵌入多C++ .exe实现多IP摄像头直播流显示
在WPF中嵌入多个C++ EXE视频窗口的实现方案
刚好做过类似的监控类应用需求,用来整合多个IP摄像头的C++ EXE视频流,下面给你详细的实现步骤和代码,亲测可行:
核心思路
WPF本身不直接支持嵌入Win32窗口,所以我们需要借助HwndHost(WPF的Win32窗口宿主类),配合Windows API来实现:
- 启动外部C++ EXE进程,获取其主窗口句柄
- 修改窗口样式,移除边框、标题栏、关闭按钮等多余元素
- 将外部窗口设置为WPF宿主的子窗口,固定到指定位置并自适应大小
具体实现代码
第一步:自定义HwndHost实现类
这个类负责启动外部进程、获取窗口句柄、修改样式并嵌入到WPF中:
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; namespace WpfCameraMonitor { public class CameraExeHost : HwndHost { private readonly Process _cameraProcess; private IntPtr _cameraWindowHandle; // Win32 API声明 [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int width, int height, bool repaint); // 窗口样式常量(用来移除不需要的元素) private const int GWL_STYLE = -16; private const int WS_BORDER = 0x00800000; private const int WS_CAPTION = 0x00C00000; private const int WS_SYSMENU = 0x00080000; private const int WS_THICKFRAME = 0x00040000; private const int WS_MINIMIZEBOX = 0x00020000; private const int WS_MAXIMIZEBOX = 0x00010000; public CameraExeHost(string exePath) { // 启动摄像头EXE进程 _cameraProcess = new Process { StartInfo = new ProcessStartInfo(exePath) { UseShellExecute = false, CreateNoWindow = false // 必须设为false,否则无法获取窗口句柄 } }; _cameraProcess.Start(); _cameraProcess.WaitForInputIdle(2000); // 等待程序初始化,避免找不到窗口 // 获取主窗口句柄(如果你的EXE有多个窗口,可能需要用EnumWindows遍历找视频窗口) _cameraWindowHandle = _cameraProcess.MainWindowHandle; if (_cameraWindowHandle == IntPtr.Zero) throw new InvalidOperationException($"无法找到[{exePath}]的窗口句柄,请检查程序是否正常启动"); } protected override HandleRef BuildWindowCore(HandleRef hwndParent) { // 将摄像头窗口设置为WPF宿主的子窗口 SetParent(_cameraWindowHandle, hwndParent.Handle); // 移除所有多余的窗口样式 int currentStyle = GetWindowLong(_cameraWindowHandle, GWL_STYLE); int cleanStyle = currentStyle & ~(WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); SetWindowLong(_cameraWindowHandle, GWL_STYLE, cleanStyle); // 让窗口填满宿主容器 MoveWindow(_cameraWindowHandle, 0, 0, (int)ActualWidth, (int)ActualHeight, true); return new HandleRef(this, _cameraWindowHandle); } protected override void DestroyWindowCore(HandleRef hwnd) { // 关闭摄像头进程,避免残留 if (!_cameraProcess.HasExited) { _cameraProcess.CloseMainWindow(); if (!_cameraProcess.WaitForExit(1000)) _cameraProcess.Kill(); } _cameraProcess.Dispose(); } // 宿主大小变化时,同步调整摄像头窗口大小 protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) { base.OnRenderSizeChanged(sizeInfo); if (_cameraWindowHandle != IntPtr.Zero) MoveWindow(_cameraWindowHandle, 0, 0, (int)ActualWidth, (int)ActualHeight, true); } } }
第二步:在WPF XAML中使用宿主类
你可以把多个CameraExeHost放到Grid、UniformGrid等布局容器中,实现分屏显示:
<Window x:Class="WpfCameraMonitor.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfCameraMonitor" Title="多摄像头监控" Height="900" Width="1200"> <UniformGrid Rows="2" Columns="2"> <!-- 第一个摄像头 --> <local:CameraExeHost exePath="D:\CameraApps\Camera1.exe"/> <!-- 第二个摄像头 --> <local:CameraExeHost exePath="D:\CameraApps\Camera2.exe"/> <!-- 第三个摄像头 --> <local:CameraExeHost exePath="D:\CameraApps\Camera3.exe"/> <!-- 第四个摄像头 --> <local:CameraExeHost exePath="D:\CameraApps\Camera4.exe"/> </UniformGrid> </Window>
关键细节说明
- 窗口句柄获取:如果你的C++ EXE启动后会先显示启动画面,
MainWindowHandle可能指向启动窗口而非视频窗口。这种情况下,你需要用EnumWindowsAPI遍历进程的所有窗口,配合GetWindowThreadProcessId找到正确的视频窗口(可以根据窗口标题或类名筛选)。 - 权限问题:如果C++ EXE需要管理员权限运行,你的WPF程序也必须以管理员身份启动,否则
SetParent会调用失败。 - 窗口样式调整:如果还有其他不需要的窗口元素(比如滚动条),可以继续添加对应的样式常量到位运算中,比如
WS_VSCROLL或WS_HSCROLL。
注意事项
- 测试时确保每个C++ EXE都能正常显示视频流,避免因EXE本身的问题导致嵌入失败。
- 多个视频窗口同时运行会占用较多CPU和内存,建议根据硬件配置调整同时显示的窗口数量。
- 如果需要动态添加/移除窗口,可以在代码中实例化
CameraExeHost并添加到布局容器的Children集合中。
内容的提问来源于stack exchange,提问作者Laurens
相关产品推荐
相关产品推荐

