『片段』Win32 模式窗体 消息路由
需求背景
近来,有个需求: 和一个外部程序对接。
具体是,我这边 主程序用 Process 启动外部程序。外部程序启动后,我这边调用的窗体不允许再进行任何操作。
当外部程序关闭时,外部程序会向我这边的主程序 返回结果。
传统做法
Process process = Process.Start("外部程序.exe", "-外部程序的参数");
process.Exited += (sender, e)=> { MessageBox.Show("外部程序关闭"); }
process.WaitForExit(); //主程序等待 外部程序执行结束
以往,三行代码 就能搞定。 但是有个问题: process.WaitForExit(); 这段代码,将会导致 UI线程 假死。
这时,你在UI线程上,多点几次鼠标,系统就会弹窗提示: 有个程序未响应,是否将其关闭。 (优化过的Ghost系统 甚至会直接将你的 主程序关闭)
—— 这种用户体验 自然是 非常不好的。
问题来了
点击主窗体,如何让外部程序弹出模式窗体(非常难表达)
—— 就是说:启动外部程序后,如果我点击 主程序,这时候 外部程序 主动弹出,盖过 主程序,就像 模式窗体 一样。
传统的模式窗体
如下图,Form1 以 模式窗体 打开 Form2, 这时候再点击 Form1 —— Form2 会自动弹5次。

直接给出实现后的效果
我们假设,这个外部程序是 Visual Studio —— 我们点击 Form1,结果 Visual Studio 弹出来 闪了5下 (就像模式窗体一样)。

代码实现解释
效果图 已经在上面了 —— 一种很小众的需求。
实现原理:Form1 以模式窗体 打开 Form2
当 点击 Form1 时,理论上 Form2 应该 闪动5下。
但是,我们改写了 Form2 的消息机制,我们将 闪动5下 的 消息,路由给了 Visual Studio。
于是,最终的效果就是,我点击 Form1,结果 外部程序 Visual Studio 却很像模式窗体 一样的 闪了5下。
关键代码就在 Form2
private DateTime m_DialogTime = DateTime.Now;
protected override void WndProc(ref Message m)
{
//base.WndProc(ref m);
//return; if (m.Msg == Win32Msg.WM_WINDOWPOSCHANGING)
{
//WM_WINDOWPOSCHANGING 消息之后, 1秒以内的 WM_NCACTIVATE 的消息, 才会进行消息路由
//为什么要控制在 1秒 内:
//你可以尝试一下, 去掉 m_DialogTime 相关代码, 然后将 消息路由的窗体 最小化
//—— 这时候, m_DialogTime 参数导致的区别就显现了
m_DialogTime = DateTime.Now;
base.WndProc(ref m);
return;
} if (m.Msg == Win32Msg.WM_NCACTIVATE)
{
if ((DateTime.Now - m_DialogTime).TotalMilliseconds > ) return;
//IntPtr intPtr = FindForm3Handle();
IntPtr intPtr = FindOuterFormHandle(); //查找外部程序的 句柄
if (intPtr != IntPtr.Zero)
{
if (!Win32API.IsZoomed(intPtr)) Win32API.ShowWindow(intPtr, );
Win32API.SendMessage(intPtr, (uint)m.Msg, (int)m.WParam, (int)m.LParam);
Win32API.SetWindowPos(intPtr, IntPtr.Zero, , , , , (uint)(SWPFlags.SWP_NOMOVE | SWPFlags.SWP_NOSIZE));
return;
}
}
base.WndProc(ref m);
}
有人质疑了
以上效果,想必有人质疑了:
问题1:
问: 主程序是 Form1, 用户点击的也是 Form1 —— 请问:Form2 有什么用?
答: Form2 就是 用来路由消息的,把 原本 Form2 的消息 路由给 外部程序。
问题2:
问: Form2 只是提供消息的?那为什么不直接模拟 闪动5次的 消息? 为什么不删掉 Form2?
答:
闪动5次,Spy++ 拦截到的消息有 60多个,用代码模拟消息 —— 至少就是 100多行代码,还不一定正确。
Form2 确实可以删除,也确实可以用 代码来模拟消息 —— 这个设想是可行的,就是代码量大,麻烦而已。
问题3:
问: 多出来的 Form2 影响用户体验
答:
你可以把 Form2 调整为 1x1 像素 —— 然后把这个 Form2 藏起来。
或者,你可以把 Form2 做成一个 半透明的 提示窗体,其实也挺美观的。

『片段』Win32 模式窗体 消息路由的更多相关文章
- 『片段』OracleHelper (支持 多条SQL语句)
C# 调用 Oracle 是如此尴尬 >System.Data.OracleClient.dll —— .Net 自带的 已经 过时作废. >要链接 Oracle 服务器,必须在 本机安装 ...
- 『片段』C# DateTime 时间相减 和 时区的关系
本文只是基础代码片段,直接先写 结论: C# DateTime 时间相减 —— 和 时区无关,只和时间值有关. 运行结果: 测试代码: using System; using System.Colle ...
- 『片段』ShellHelper 控制台程序 的 程序调用(支持输入命令得到返回字符串输出)
背景: > 之前做 OGG 时,被 OGG的配置 恶心到了.(OGG是啥,这里就不解释了) > 总之就是一个 控制台程序,总是得手动执行一堆命令,每次都得输入 —— 实在是打字打累了. & ...
- 『TensorFlow』分布式训练_其二_单机多GPU并行&GPU模式设定
建议比对『MXNet』第七弹_多GPU并行程序设计 一.tensorflow GPU设置 GPU指定占用 gpu_options = tf.GPUOptions(per_process_gpu_mem ...
- 『设计』Laura.Compute 设计思路
前言: 前一篇文章 <『开源』也顺手写一个 科学计算器:重磅开源> ,继 Laura.Compute 算法开源之后,有 博客园 园友 希望公开一下 Laura.Compute算法 的 设计 ...
- iOS 多线程:『RunLoop』详尽总结
1. RunLoop 简介 1.1 什么是 RunLoop? 可以理解为字面意思:Run 表示运行,Loop 表示循环.结合在一起就是运行的循环的意思.哈哈,我更愿意翻译为『跑圈』.直观理解就像是不停 ...
- 『AngularJS』$location 服务
项目中关于 $location的用法 简介 $location服务解析在浏览器地址栏中的URL(基于window.location)并且让URL在你的应用中可用.改变在地址栏中的URL会作用到$loc ...
- 『开源』Slithice 2013 服务器集群 设计和源码
相关介绍文章: <『设计』Slithice 分布式架构设计-支持一体式开发,分布式发布> <『集群』001 Slithice 服务器集群 概述> <『集群』002 Sli ...
- 『设计』Slithice 分布式架构设计-支持一体式开发,分布式发布
项目原因: 参与过各种 分布式项目,有 Socket,Remoting,WCF,当然还有最常用的可以跨平台的 WebService. 分布式编码的时间浪费: 但是,无一例外的,开发分布式程序的开发遵循 ...
随机推荐
- 时间复杂度O(n),空间复杂度O(1)解斐波那契数列
#include <stdio.h> #include <iostream> using namespace std; long long fibs1(int in_iN) { ...
- 2018山东省ACM省赛G题-Game
Alice and Bob are playing a stone game. There are n piles of stones. In each turn, a player can remo ...
- JDBC、DBUtils
JDBC(Java Data Base Connectivity) java数据连接 可以为多种数据库,提供统一访问,它由一组用java语言编写的类和接口组成,也是java访问数据库的规范. my ...
- Python(Django)项目与Apache的管理
(开开心心每一天~ ---虫瘾师) Python(Django)项目交给Apache的管理(一) 准备:Django的环境(Python).Apache.Wsgi(必须文件) 首先需要电脑有Pytho ...
- Tornado day1
Tornado 之路由配置 首先导入模块,使用Application方法中可配置多个路由,格式必须为列表中是元组 元组的第一个是配置的url,第二个参数时自定义的类(继承自RequestHandler ...
- ES的基本用法
ES的基本概念 1> 集群和节点 一个es集群是由一个或多和es节点组成的集合 每一个集群都有一个名字, 如之前的wali 每个节点都有自己的名字, 如之前的master, slave1, sl ...
- java内部类(转)
转自:http://www.cnblogs.com/nerxious/archive/2013/01/24/2875649.html 内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类 ...
- 一个能够在Asp.Net和Asp.NetCore之间能够互相通讯的Rpc
一.特性 1.跨平台 2.提供负载均衡算法 3.支持ZK服务协调 4.提供了JSON.BinarySerializer.还有自定义的序列化方式 5.客户端提供Socket连接池,以便于快速交互,防止类 ...
- JS中清空字符串前后空格
在JS 操作的时候 长期会有对字符串的操作, 但是在JS 中不像在C#中 有字符串的方法 Trim() 来对字符串进行处理 . 所以自己写一个对字符串前后清楚空格的方法还是有必要的 以免以后忘记了 ...
- 2017年Kali Linux更新源
终端输入: leafpad /etc/apt/sources.list 打开更新源配置文件,将下面的更新源复制到原内容的前面: #163网易 Kali源 deb http://mirrors.163. ...