You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C# WPF GUI中嵌入多C++ .exe实现多IP摄像头直播流显示

在WPF中嵌入多个C++ EXE视频窗口的实现方案

刚好做过类似的监控类应用需求,用来整合多个IP摄像头的C++ EXE视频流,下面给你详细的实现步骤和代码,亲测可行:

核心思路

WPF本身不直接支持嵌入Win32窗口,所以我们需要借助HwndHost(WPF的Win32窗口宿主类),配合Windows API来实现:

  1. 启动外部C++ EXE进程,获取其主窗口句柄
  2. 修改窗口样式,移除边框、标题栏、关闭按钮等多余元素
  3. 将外部窗口设置为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>

关键细节说明

  1. 窗口句柄获取:如果你的C++ EXE启动后会先显示启动画面,MainWindowHandle可能指向启动窗口而非视频窗口。这种情况下,你需要用EnumWindows API遍历进程的所有窗口,配合GetWindowThreadProcessId找到正确的视频窗口(可以根据窗口标题或类名筛选)。
  2. 权限问题:如果C++ EXE需要管理员权限运行,你的WPF程序也必须以管理员身份启动,否则SetParent会调用失败。
  3. 窗口样式调整:如果还有其他不需要的窗口元素(比如滚动条),可以继续添加对应的样式常量到位运算中,比如WS_VSCROLL或WS_HSCROLL。

注意事项

  • 测试时确保每个C++ EXE都能正常显示视频流,避免因EXE本身的问题导致嵌入失败。
  • 多个视频窗口同时运行会占用较多CPU和内存,建议根据硬件配置调整同时显示的窗口数量。
  • 如果需要动态添加/移除窗口,可以在代码中实例化CameraExeHost并添加到布局容器的Children集合中。

内容的提问来源于stack exchange,提问作者Laurens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:13:04