在微软的官方文档中,说 SetParent 可以在进程内设置,也可以跨进程设置。当使用跨进程设置窗口的父子关系时,你需要注意本文提到的一些问题,避免踩坑。


本文内容

  • 跨进程设置 `SetParent`
  • 消息循环强制同步
    • 消息循环
    • 强制同步
  • 如何解决

跨进程设置 SetParent

关于 SetParent 函数设置窗口父子关系的文档可以看这个:

  • SetParent function (winuser.h) - Microsoft Docs

在这篇文章的 DPI 感知一段中明确写明了在进程内以及跨进程设置父子关系时的一些行为。虽然没有明确说明支持跨进程设置父子窗口,不过这段文字就几乎说明 Windows 系统对于跨进程设置窗口父子关系还是支持的。

但 Raymond Chen 在 Is it legal to have a cross-process parent/child or owner/owned window relationship? 一文中有另一段文字:

If I remember correctly, the documentation for Set­Parent used to contain a stern warning that it is not supported, but that remark does not appear to be present any more. I have a customer who is reparenting windows between processes, and their application is experiencing intermittent instability.
如果我没记错的话,SetParent 的文档曾经包含一个严厉的警告表明它不受支持,但现在这段备注似乎已经不存在了。我就遇到过一个客户跨进程设置窗口之间的父子关系,然后他们的应用程序间歇性不稳定。

这里表明了 Raymond Chen 对于跨进程设置父子窗口的一些担忧,但从文档趋势来看,还是支持的。只是这种担忧几乎说明跨进程设置 SetParent 存在一些坑。

那么本文就说说跨进程设置父子窗口的一些坑。

消息循环强制同步

消息循环

我们会感觉到 Windows 中某个窗口有响应(比如鼠标点击有反应),是因为这个窗口在处理 Windows 消息。窗口进行消息循环不断地处理消息使得各种各样的用户输入可以被处理,并正确地在界面上显示。

一个典型的消息循环大概像这样:

while(GetMessage(ref msg, IntPtr.Zero, 0, 0))
{TranslateMessage(ref msg);DispatchMessage(ref msg);
}

对于显示了窗口的某个线程调用了 GetMessage 获取了消息,Windows 系统就会认为这个线程有响应。相反,如果长时间不调用 GetMessage,Windows 就会认为这个线程无响应。TranslateMessage 则是翻译一些消息(比如从按键消息翻译成字符消息)。真正处理 GetMessage 中的内容则是后面的调度消息 DispatchMessage,是这个函数的调用使得我们 UI 界面上的内容可以有可见的反映。

一般来说,每个创建了窗口的线程都有自己独立的消息循环,且不会互相影响。然而一旦这些窗口之间建立了父子关系之后就会变得麻烦起来。

强制同步

Windows 会让具有父子关系的所有窗口的消息循环强制同步。具体指的是,所有具有父子关系的窗口消息循环,其消息循环会串联成一个队列(这样才可以避免消息循环的并发)。

也就是说,如果你有 A、B、C、D 四个窗口,分属不同进程,A 是 B、C、D 窗口的父窗口,那么当 A 在处理消息的时候,B、C、D 的消息循环就会卡在 GetMessage 的调用。同样,无论是 B、C 还是 D 在处理消息的时候,其他窗口也会同样卡在 GetMessage 的调用。这样,所有进程的 UI 线程实际上会互相等待,所有通过消息循环执行的代码都不会同时执行。然而实际上 Windows GUI 应用程序的开发中基本上 UI 代码都是通过消息循环来执行的,所以这几乎等同于所有进程的 UI 线程强制同步成类似一个 UI 线程的效果了。

带来的副作用也就相当明显,任何一个进程卡了 UI,其他进程的 UI 将完全无响应。当然,不依赖消息循环的代码不会受此影响,比如 WPF 应用程序的动画和渲染。

如何解决

对于 SetParent 造成的这些问题,实际上没有官方的解决方案,你需要针对你不同的业务采用不同的解决办法。

正如 Raymond Chen 所说:

(It’s one of those “if you don’t already know what the consequences are, then you are not smart enough to do it correctly” things. You must first become the master of the rules before you can start breaking them.)
正如有些人说的“如果你不知道后果,那么你也不足以正确地完成某件事情”。在开始破坏规则之前,您必须先成为规则的主人。

你必须清楚跨进程设置父子窗口带来的各种副作用,然后针对性地给出解决方案:

  1. 比如所有窗口会强制串联成一个队列,那么可以考虑将暂时不显示的窗口断开父子关系;
  2. 比如设置窗口的位置大小等操作,必须考虑此窗口不是顶层窗口的问题,需要跨越进程到顶层窗口来操作;

参考资料

  • windows - Good or evil - SetParent() win32 API between different processes - Stack Overflow
  • Hosting WPF UI cross-thread and cross-process – Diaries of a Software Plumber
  • Is it legal to have a cross-process parent/child or owner/owned window relationship? | The Old New Thing
  • winapi - Why are “TranslateMessage” and “DispatchMessage” separate calls? - Stack Overflow

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

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

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

使用 SetParent 跨进程设置父子窗口时的一些问题(小心卡死)相关推荐

  1. Iframe中跨域进行父子窗口进行通信的四种方法

    一.跨域简介 1. 首先简单介绍一下什么是跨域 当我们在浏览器的地址栏中输入一个地址的时候,这个地址通常包含四部分信息内容.这四部分信息包含:①协议.②域名.③端口.④资源位置. 其中前三部分将会决定 ...

  2. VirtualAllocEx 跨进程读写数据 代码注入

    VirtualAllocEx 函数的作用是在指定进程的虚拟空间保留或提交内存区域,除非指定MEM_RESET参数,否则将该内存区域置0. LPVOID VirtualAllocEx(  HANDLE  ...

  3. Android组件化跨进程通信框架Andromeda解析

    关于组件化 随着项目结构越来越庞大,模块与模块间的边界逐渐变得不清晰,代码维护越来越困难,甚至编译速度都成为影响开发效率的瓶颈. 组件化拆分是比较常见的解决方案,一方面解决模块间的耦合关系.将通用模块 ...

  4. 爱奇艺开源的组件化跨进程通信解决方案

    /   今日科技快讯   / 近日,特斯拉首席执行官埃隆·马斯克来到中国上海,亲自向客户交付中国制造的Model 3,并透露了有关Model Y的更多信息,特斯拉股价继续保持着近三个月来的飙涨势头,目 ...

  5. 再谈Android Binder跨进程通信原理

    在谈Android的跨进程通信问题上时,总会问到Android的IPC机制,是指两个进程之间进行数据交换的过程.按操作系统的中的描述,线程是CPU调度最小的单元,同时线程是一种有限的系统资源,而进程是 ...

  6. Android之使用AIDL时的跨进程回调—Server回调Client

    首先建立在server端建立两个aidl文件 ITaskCallback.aidl 用于存放要回调client端的方法 package com.cmcc.demo.server; interface ...

  7. vue 什么是渐进式 响应式 意思。Vue常用的指令。VUE:跨域设置。vue router 新窗口。$router.push。

    Vue  是 轻量的 模型视图视图模型 框架.就是数据的双向开发. 数据驱动+组件化开发. 渐进式框架. 官网:cn.vuejs.org 在读 Vue2.0 文档的时候,介绍"Vue.js( ...

  8. 设置idea打开时显示选择项目窗口

    设置idea打开时显示选择项目窗口 效果图: 详细设置如下 找到File->Settings->Appearance & Behavioer->System Settings ...

  9. 使用AIDL+动态代理+运行时注解+反射 反手撸一套Android跨进程通信框架

    IPC 前言 跨进程通信方式 跨进程通信框架 涉及到的技术 使用Request-Response思想 IPCRequest IPCResponse RemoteService 服务端 客户端 附带 项 ...

最新文章

  1. JMF天昏地暗之路(一)-----jmf无法检测到摄像头
  2. VMware上的ubuntu14.04与win7共享文件夹
  3. 异常数据4种剔除方法_数据分析系列 22/32 | 9种常用的数据分析方法
  4. Java命令行界面(第23部分):Rop
  5. 在美国本科 计算机排名2015,(word)2015年美国大学专业排名汇总-以计算机专业排名为例.doc...
  6. python2.7升级到python3.6注意事项
  7. 前端基础:JavaScript 代码风格指南
  8. 将MfgTool工具改造为自己的烧写工具
  9. 单片机波形发生c语言,51单片机波形发生器程序设计
  10. 微信游戏,微信小说系统域名防封是如何做到的
  11. Android Local Manifests机制
  12. 七大顶级Linux桌面比较
  13. 倍投技巧 - 凯利公式教你如何用正确的方法投资
  14. 使用PowerShell替代WinDbg在高分辨率笔记本下调试、排错
  15. linux之mmc子系统
  16. LCD12864液晶显示屏与12位AD模块程序
  17. C/C++ CGI处理文件上传
  18. 夜空中最靓的二狗子是如何让 HTTPS 快上加快的?
  19. 学计算机需要什么基础?
  20. 使用Halo建立自己的网站

热门文章

  1. 2021年R2移动式压力容器充装考试内容及R2移动式压力容器充装模拟考试
  2. ad 卡尔曼_理解卡尔曼五个方程
  3. Linux系统常用命令查看进程的用法
  4. 2019年广东工业大学腾讯杯新生程序设计竞赛(同步赛)E-缺席的神官
  5. 如何查看Linux磁盘类型
  6. WK2124 linux 驱动移植
  7. 马毅与来自高维度的恩赐
  8. 几何向量:空间三角形外心和法向量
  9. ORA-02019:未找到远程数据库的连接说明(数据库链接创建)
  10. flinkSql中自定义时间窗口开启时间