当前位置: 首页 > news >正文

System.InvalidOperationException:“寄宿 HWND 必须是子窗口。”

当试图在 WPF 窗口中嵌套显示 Win32 子窗口的时候,你有可能出现错误:“System.InvalidOperationException:“寄宿 HWND 必须是子窗口。””。

这是很典型的 Win32 错误,本文介绍如何修复此错误。


本文内容

    • 一个最简的嵌入其他窗口的例子
    • 寄宿 HWND 必须是子窗口

一个最简的嵌入其他窗口的例子

我们在 MainWindow 中嵌入一个其他的窗口来承载新的 WPF 控件。一般情况下我们当然不会这么去做,但是如果我们要跨越进程边界来完成 WPF 渲染内容的融合的时候,就需要嵌入一个新的窗口了。

WPF 中可以使用 HwndSource 来包装一个 WPF 控件到 Win32 窗口,使用自定义的继承自 HwndHost 的类可以把 Win32 窗口包装成 WPF 控件。由于窗口句柄是可以跨越进程边界传递的,所以这样的方式可以完成跨进程的 WPF 控件显示。

下面是最简单的一个例子,为了简单,没有跨进程传递 Win32 窗口句柄,而是直接创建出来。

using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace Walterlv.Demo.HwndWrapping
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            Content = new HwndWrapper();
        }
    }

    public class HwndWrapper : HwndHost
    {
        private HwndSource _source;

        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
        {
            var parameters = new HwndSourceParameters("walterlv");
            _source = new HwndSource(parameters);
            // 这里的 ChildPage 是一个继承自 UseControl 的 WPF 控件,你可以自己创建自己的 WPF 控件。
            _source.RootVisual = new ChildPage();
            return new HandleRef(this, _source.Handle);
        }

        protected override void DestroyWindowCore(HandleRef hwnd)
        {
            _source?.Dispose();
        }
    }
}

寄宿 HWND 必须是子窗口

当运行此代码的时候,会提示错误:

System.InvalidOperationException:“寄宿 HWND 必须是子窗口。”

或者英文版:

System.InvalidOperationException:“Hosted HWND must be a child window.”

这是一个 Win32 错误,因为我们试图将一个普通的窗口嵌入到另一个窗口中,而实际上要完成嵌入需要子窗口才行。

那么如何设置一个 Win32 窗口为子窗口呢?使用 SetWindowLong 来设置 Win32 窗口的样式是可以的。不过我们因为使用了 HwndSource,所以可以通过 HwndSourceParameters 来更方便地设置窗口样式。

我们需要将 HwndSourceParameters 那一行改成这样:

++  const int WS_CHILD = 0x40000000;
--  var parameters = new HwndSourceParameters("walterlv");
++  var parameters = new HwndSourceParameters("walterlv")
++  {
++      ParentWindow = hwndParent.Handle,
++      WindowStyle = WS_CHILD,
++  };

最关键的是两点:

  1. 需要设置此窗口为子窗口,也就是设置 WindowStyleWS_CHILD
  2. 需要设置此窗口的父窗口,也就是设置 ParentWindowhwndParent.Handle(我们使用参数中传入的 hwndParent 作为父窗口)。

现在再运行,即可正常显示此嵌套窗口:

嵌套窗口

另外,WindowStyle 属性最好加上 WS_CLIPCHILDREN,详情请阅读:

  • 解决 WPF 嵌套的子窗口在改变窗口大小的时候闪烁的问题

参考资料

  • WPF嵌入式调用Win32应用程序的问题—提示异常:寄宿的HWND必须是指定父级的子窗口

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 通过 AppSwitch 禁用 WPF 内置的触摸让 WPF 程序可以处理 Windows 触摸消息
  • 如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全
  • 通过 mklink 收集本地文件系统的所有 NuGet 包输出目录来快速调试公共组件代码
  • 设计一个 .NET 可用的弱引用集合(可用来做缓存池使用)
  • 使用 C# 中的 dynamic 关键字调用类型方法时可能遇到的各种问题
  • 程序员可能会使用的各种命名规则
  • System.InvalidOperationException:“BuildWindowCore 无法返回寄宿的子窗口句柄。”
  • System.InvalidOperationException:“寄宿的 HWND 必须是指定父级的子窗口。”
  • 在使用 .NET Remoting 技术开发跨进程通信时可能遇到的各种异常
  • 使用 SetParent 跨进程设置父子窗口时的一些问题(小心卡死)
  • System.ComponentModel.Win32Exception (0x80004005): 无效的窗口句柄。
  • 解决 WPF 嵌套的子窗口在改变窗口大小的时候闪烁的问题
  • WPF 的 Application.Current.Dispatcher 中,为什么 Current 可能为 null
  • WPF 的 Application.Current.Dispatcher 中,Dispatcher 属性一定不会为 null
  • 提高使用 Visual Studio 开发效率的键盘快捷键
  • 【RocksDB】TransactionDB源码分析
  • 10个最佳ES6特性 ES7与ES8的特性
  • Android单元测试 - 几个重要问题
  • angular2 简述
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • echarts的各种常用效果展示
  • github从入门到放弃(1)
  • golang中接口赋值与方法集
  • JavaScript HTML DOM
  • javascript 总结(常用工具类的封装)
  • Protobuf3语言指南
  • Spring声明式事务管理之一:五大属性分析
  • vue的全局变量和全局拦截请求器
  • vue脚手架vue-cli
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 给第三方使用接口的 URL 签名实现
  • 关于Flux,Vuex,Redux的思考
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 马上搞懂 GeoJSON
  • 软件开发学习的5大技巧,你知道吗?
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • UI设计初学者应该如何入门?
  • (1)常见O(n^2)排序算法解析
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (多级缓存)缓存同步
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)Unity3DUnity3D在android下调试
  • **PHP分步表单提交思路(分页表单提交)
  • .bashrc在哪里,alias妙用
  • .cn根服务器被攻击之后
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .Net Core与存储过程(一)
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理
  • .net中生成excel后调整宽度
  • .Net组件程序设计之线程、并发管理(一)