我在阅读 WPF 源代码,在 HwndWrapper 的静态构造函数看到了申请了 HwndWrapper.GetGCMemMessage 这个 Windows 消息,好奇这个消息是什么功能的。通过阅读 WPF 源代码和写测试应用,了解到这是一个完全用来内部测试或调试的消息,没有任何业务上的功能

在 WPF 的 HwndWrapper 的静态构造函数有以下代码

    internal class HwndWrapper : DispatcherObject, IDisposable
{
static HwndWrapper()
{
s_msgGCMemory = UnsafeNativeMethods.RegisterWindowMessage("HwndWrapper.GetGCMemMessage");
} private static WindowMessage s_msgGCMemory;
}

这个 Windows 消息包含了 GC 字符串,让我以为这是一个和 GC 内存相关的消息。阅读代码才了解到这是一个完全用来调试的消息

唯一的使用是在 HwndWrapper 以下 WndProc 的函数里面。如方法的命名,这个方法就是用来接收所有的 Windows 消息的。而在 WPF 里面,每个 WPF 的 Window 对象都会创建 HwndWrapper 对象,也就是说每个 Window 对象能收到的消息,都会进入此 WndProc 方法里面

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// The default result for messages we handle is 0.
IntPtr result = IntPtr.Zero;
WindowMessage message = (WindowMessage)msg; // 忽略其他代码 if (message == s_msgGCMemory)
{
// This is a special message we respond to by forcing a GC Collect. This
// is used by test apps and such.
IntPtr lHeap = (IntPtr)GC.GetTotalMemory((wParam == new IntPtr(1) )? true : false);
result = lHeap;
handled = true;
} CheckForCreateWindowFailure(result, true); // return our result
return result;
}

通过以上有删减的代码可以了解到,在收到这个消息时,仅仅只是调用 GC.GetTotalMemory 获取到一个值,用于传入 CheckForCreateWindowFailure 方法里面

如 CheckForCreateWindowFailure 方法的命名,可以看到这是一个判断是否创建窗口失败的方法,方法里面的代码如下

        private void CheckForCreateWindowFailure( IntPtr result, bool handled )
{
if( ! _isInCreateWindow )
return; if( IntPtr.Zero != result )
{
System.Diagnostics.Debug.WriteLine("Non-zero WndProc result=" + result);
if( handled )
{
if( System.Diagnostics.Debugger.IsAttached )
System.Diagnostics.Debugger.Break();
else
throw new InvalidOperationException();
}
}
}

先判断 _isInCreateWindow 字段。接着判断 result 如果非零且 handled 是 true 将尝试触发断点或炸一下。而显然,调用 GC.GetTotalMemory 一定会返回一个非 0 的值,且 handled 一定被设置为 true 的值。也就是说,如果 _isInCreateWindow 被设置为 true 的话,那在调试下将进入断点

继续看看 _isInCreateWindow 字段是在哪里使用的

只有在 HwndWrapper 构造时,才会给 _isInCreateWindow 字段设置值,有删减的代码如下

        public HwndWrapper(...)
{
// 忽略其他代码
_isInCreateWindow = true; try
{
_handle = new SecurityCriticalDataClass<IntPtr>(UnsafeNativeMethods.CreateWindowEx(...));
}
finally
{
_isInCreateWindow = false;
}
// 忽略其他代码
}

也就是只有在调用 Win32 的 CreateWindowEx 方法过程才会设置 _isInCreateWindow 字段。换句话说,基本上能够接收到 HwndWrapper.GetGCMemMessage 消息时,此 _isInCreateWindow 字段不是 true 的值,也就是说断点是不会进入的

因为一旦_isInCreateWindow 字段是 false 的值,那么在 CheckForCreateWindowFailure 方法的以下判断代码里面,将会返回

        private void CheckForCreateWindowFailure( IntPtr result, bool handled )
{
if( ! _isInCreateWindow )
return; // 忽略其他代码
}

也就是说即使应用程序接收到了 HwndWrapper.GetGCMemMessage 消息,也是不会炸掉或进入调试断点。但是会调用 GC.GetTotalMemory 方法,也就是可能可以强行触发一次回收

例如新建一个 WPF 应用,给 MainWindow 不断发送 HwndWrapper.GetGCMemMessage 消息,可以在 VS 调试看到不断触发 GC 回收

        var windowMessage = PInvoke.RegisterWindowMessage("HwndWrapper.GetGCMemMessage");

        var windowInteropHelper = new WindowInteropHelper(this);
for (int i = 0; i < 100; i++)
{
PInvoke.SendMessage(new HWND(windowInteropHelper.Handle), windowMessage, new WPARAM(1), new LPARAM(0)); await Task.Delay(100);
}

以上的代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 36b22cef80ec382a7467b2b3cbb77f21d68073aa

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 36b22cef80ec382a7467b2b3cbb77f21d68073aa

获取代码之后,进入 LaiwurhiroJaqadihawaho 文件夹

dotnet 读 WPF 源代码笔记 聊聊 HwndWrapper.GetGCMemMessage 调试消息的更多相关文章

  1. dotnet 读 WPF 源代码笔记 布局时 Arrange 如何影响元素渲染坐标

    大家是否好奇,在 WPF 里面,对 UIElement 重写 OnRender 方法进行渲染的内容,是如何受到上层容器控件的布局而进行坐标偏移.如有两个放入到 StackPanel 的自定义 UIEl ...

  2. dotnet 读 WPF 源代码笔记 渲染收集是如何触发

    在 WPF 里面,渲染可以从架构上划分为两层.上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令.上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GF ...

  3. 读Flask源代码学习Python--config原理

    读Flask源代码学习Python--config原理 个人学习笔记,水平有限.如果理解错误的地方,请大家指出来,谢谢!第一次写文章,发现好累--!. 起因   莫名其妙在第一份工作中使用了从来没有接 ...

  4. 《深入浅出WPF》笔记——绘画与动画

    <深入浅出WPF>笔记——绘画与动画   本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...

  5. 《深入浅出WPF》笔记——资源篇

    原文:<深入浅出WPF>笔记--资源篇 前面的记录有的地方已经用到了资源,本文就来详细的记录一下WPF中的资源.我们平时的“资源”一词是指“资财之源”,是创造人类社会财富的源泉.在计算机程 ...

  6. 在Linux上编译dotnet cli的源代码生成.NET Core SDK的安装包

    .NET 的开源,有了更多的DIY乐趣.这篇博文记录一下在新安装的 Linux Ubuntu 14.04 上通过自己动手编译 dotnet cli 的源代码生成 .net core sdk 的 deb ...

  7. [WPF源代码]QQ空间相册下载工具

    放一个WPF源代码,源代码地址 http://download.csdn.net/detail/witch_soya/6195987 代码没多少技术含量,就是用WPF做的一个QQ空间相册下载工具,效果 ...

  8. WPF学习笔记-用Expression Design制作矢量图然后导出为XAML

    WPF学习笔记-用Expression Design制作矢量图然后导出为XAML 第一次用Windows live writer写东西,感觉不错,哈哈~~ 1.在白纸上完全凭感觉,想象来画图难度很大, ...

  9. WPF 学习笔记-在WPF下创建托盘图标

    原文:WPF 学习笔记-在WPF下创建托盘图标 首先需要在项目中引用System.Windows.Forms,System.Drawing; using System; using System.Co ...

  10. WPF 学习笔记-设置属性使窗口不可改变大小

    原文:WPF 学习笔记-设置属性使窗口不可改变大小 调整Windows下的ResizeMode属性: ResizeMode = NoResize Resize属性是控制Windows是否可以改变大小, ...

随机推荐

  1. 使用systemd部署r-nacos

    1. 前言 r-nacos是一个用rust实现的nacos服务.相较于java nacos来说,是一个提供相同功能,启动更快.占用系统资源更小(初始内存小于10M).性能更高.运行更稳定的服务. r- ...

  2. CenterNet:Corner-Center三元关键点,检测性能全面提升 | ICCV 2019

    为了解决CornerNet缺乏目标内部信息的问题,提出了CenterNet使用三元组进行目标检测,包含一个中心关键点和两个角点.从实验结果来看,CenterNet相对于CornerNet只增加了少量推 ...

  3. Kingbase ES函数参数模式与Oracle的异同

    文章概要: 本文对主要就KES和Oracle的PLSQL中关于存储过程参数模式异同进行介绍,列举和验证了存在的差异 (如果想直接看差异的结论可直接跳到末尾). 一,存储过程的三种参数模式 重新回顾一下 ...

  4. CVS Excell乱码怎么修改

    问题描述 日常办公,从网页或者其他web端下载的表格(excel格式或csv格式),打开后发现中文乱码,如下: 常规解法 百度会发现,大部分提供的方法,就是通过excel的另存为,然后选择相应的编码, ...

  5. 第十三届蓝桥杯大赛软件赛省赛【Java 大学B 组】试题C: 字符统计

    1 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String args[]) { 5 Sca ...

  6. 如何自动申请免费的HTTPS证书?

    在购买域名的时候我相信很多人都遇到了对于证书的问题,之前我也是使用阿里云的免费一年的证书,那时候感觉还好,一年更换一次,但是近期阿里云对于证书的过期时间直接砍到了三个月!让我难以接受,所以我在想吧他直 ...

  7. #整体二分,树状数组#洛谷 3332 [ZJOI2013]K大数查询

    题目 分析 虽然树套树也可以做,这里考虑整体二分, 对于二分的答案\(mid\),1操作实际上就是如果\(c>mid\)就给区间整体加1, 2操作即询问区间和是否超过\(k\),如果超过\(k\ ...

  8. SkipList和java中ConcurrentSkipListMap的实现

    目录 简介 SkipList ConcurrentSkipListMap SkipList的实现 concurrent的实现 总结 SkipList和java中ConcurrentSkipListMa ...

  9. OpenHarmony应用实现二维码扫码识别

     本文转载自<OpenHarmony应用实现二维码扫码识别>,作者zhushangyuan_ 概念介绍 二维码的应用场景非常广泛,在购物应用中,消费者可以直接扫描商品二维码,浏览并购买产品 ...

  10. 本周四晚19:00知识赋能第七期第2课丨OpenHarmony WiFi扫描仪UX设计

    8月18日19:00~20:00,第七期知识赋能第二节直播就要开始啦!如果你是缺乏实战经验的学生,如果你是初出茅庐的职场新人,如果你是想参与开源的贡献者,那么本期的直播课将不容错过!通过本期直播,开发 ...