『片段』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. 分布式编码的时间浪费: 但是,无一例外的,开发分布式程序的开发遵循 ...
随机推荐
- mysql 存储引擎简介
几个常用存储引擎的特点 下面我们重点介绍几种常用的存储引擎并对比各个存储引擎之间的区别和推荐使用方式. 特点 Myisam BDB Memory InnoDB Archive 存储限制 没有 没有 有 ...
- cocos2d-x学习之路之工作吐槽
经过大半年的cocos2d-x的学习,目前已在一个游戏创业公司实习,负责客户端的代码编写和维护.公司做了一款网游.比较给力,马上就要发布了.希望能够大卖.比较坑的是,居然电脑不给联网.查资料都不好查, ...
- Python的logging日志
日志级别:critical > error > warning > info > debug,notset级别越高打印的日志越少,反之亦然,即debug : 打印全部的日志(n ...
- 填坑!!!virtualenv 中 nginx + uwsgi 部署 django
一.为什么会有这篇文章 第一次接触 uwsgi 和 nginx ,这个环境搭建,踩了太多坑,现在记录下来,让后来者少走弯路. 本来在 Ubuntu14.04 上 搭建好了环境,然后到 centos7. ...
- python之Flask实现登录功能
网站少不了要和数据库打交道,归根到底都是一些增删改查操作,这里做一个简单的用户登录功能来学习一下Flask如何操作MySQL. 用到的一些知识点:Flask-SQLAlchemy.Flask-Logi ...
- opencv利用hough概率变换拟合得到直线后,利用DDA算法得到直线上的像素点坐标
图片霍夫变换拟合得到直线后,怎样获得直线上的像素点坐标? 这是我今天在图像处理学习中遇到的问题,霍夫变换采用的概率霍夫变换,所以拟合得到的直线信息其实是直线的两个端点的坐标,这样一个比较直接的思路就是 ...
- Spring cloud整体框架
研究了一段时间spring boot了准备向spirng cloud进发,公司架构和项目也全面拥抱了Spring Cloud.在使用了一段时间后发现Spring Cloud从技术架构上降低了对大型系统 ...
- log4j的配置与使用
配置log4j的步骤如下: 1.导入jar包 如log4j-1.2.15.jar 2.在src下添加log4j.properties 使用时把下面内容中的注释去掉: //日志级别及位置 log4j.r ...
- 修改LINUX的时区。
新装的机器(redhat7)有几台时区不对: 百度了之后找到了以下解决方法输入 tz 依次选择Asia China east China Yes 1 然后 export TZ 新开对话发现 ...
- 理解主从设备模式(Master-Slave)
前言 在给定上下文的软件体系结构中,为了解决某些经常出现的问题而形成的通用且可重用的解决方案称之为架构模式,而常见的体系架构模式主要有以下十种 分层模式 客户端-服务器模式 主从设备模式 管道-过滤器 ...