首页 技术 正文
技术 2022年11月15日
0 收藏 387 点赞 2,285 浏览 1917 个字

需求背景

近来,有个需求: 和一个外部程序对接。

具体是,我这边 主程序用 Process 启动外部程序。外部程序启动后,我这边调用的窗体不允许再进行任何操作。

当外部程序关闭时,外部程序会向我这边的主程序 返回结果。

传统做法

 Process process = Process.Start("外部程序.exe", "-外部程序的参数");
process.Exited += (sender, e)=> { MessageBox.Show("外部程序关闭"); }
process.WaitForExit(); //主程序等待 外部程序执行结束

以往,三行代码 就能搞定。 但是有个问题: process.WaitForExit(); 这段代码,将会导致 UI线程 假死。

这时,你在UI线程上,多点几次鼠标,系统就会弹窗提示: 有个程序未响应,是否将其关闭。 (优化过的Ghost系统 甚至会直接将你的 主程序关闭)

—— 这种用户体验 自然是 非常不好的。

问题来了

点击主窗体,如何让外部程序弹出模式窗体(非常难表达)

—— 就是说:启动外部程序后,如果我点击 主程序,这时候 外部程序 主动弹出,盖过 主程序,就像 模式窗体 一样。

传统的模式窗体

如下图,Form1 以 模式窗体 打开 Form2, 这时候再点击 Form1 —— Form2 会自动弹5次。

『片段』Win32 模式窗体 消息路由

直接给出实现后的效果

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

『片段』Win32 模式窗体 消息路由

代码实现解释

效果图 已经在上面了 —— 一种很小众的需求。

实现原理: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?

答:

  1. 闪动5次,Spy++ 拦截到的消息有 60多个,用代码模拟消息 —— 至少就是 100多行代码,还不一定正确。

  2. Form2 确实可以删除,也确实可以用 代码来模拟消息 —— 这个设想是可行的,就是代码量大,麻烦而已。

问题3:

问: 多出来的 Form2 影响用户体验

答:

  1. 你可以把 Form2 调整为 1×1 像素 —— 然后把这个 Form2 藏起来。

  2. 或者,你可以把 Form2 做成一个 半透明的 提示窗体,其实也挺美观的。

『片段』Win32 模式窗体 消息路由

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,082
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,556
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,406
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,179
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,815
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,898