需求背景

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

具体是,我这边 主程序用 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?

答:

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

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

问题3:

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

答:

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

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

『片段』Win32 模式窗体 消息路由的更多相关文章

  1. 『片段』OracleHelper (支持 多条SQL语句)

    C# 调用 Oracle 是如此尴尬 >System.Data.OracleClient.dll —— .Net 自带的 已经 过时作废. >要链接 Oracle 服务器,必须在 本机安装 ...

  2. 『片段』C# DateTime 时间相减 和 时区的关系

    本文只是基础代码片段,直接先写 结论: C# DateTime 时间相减 —— 和 时区无关,只和时间值有关. 运行结果: 测试代码: using System; using System.Colle ...

  3. 『片段』ShellHelper 控制台程序 的 程序调用(支持输入命令得到返回字符串输出)

    背景: > 之前做 OGG 时,被 OGG的配置 恶心到了.(OGG是啥,这里就不解释了) > 总之就是一个 控制台程序,总是得手动执行一堆命令,每次都得输入 —— 实在是打字打累了. & ...

  4. 『TensorFlow』分布式训练_其二_单机多GPU并行&GPU模式设定

    建议比对『MXNet』第七弹_多GPU并行程序设计 一.tensorflow GPU设置 GPU指定占用 gpu_options = tf.GPUOptions(per_process_gpu_mem ...

  5. 『设计』Laura.Compute 设计思路

    前言: 前一篇文章 <『开源』也顺手写一个 科学计算器:重磅开源> ,继 Laura.Compute 算法开源之后,有 博客园 园友 希望公开一下 Laura.Compute算法 的 设计 ...

  6. iOS 多线程:『RunLoop』详尽总结

    1. RunLoop 简介 1.1 什么是 RunLoop? 可以理解为字面意思:Run 表示运行,Loop 表示循环.结合在一起就是运行的循环的意思.哈哈,我更愿意翻译为『跑圈』.直观理解就像是不停 ...

  7. 『AngularJS』$location 服务

    项目中关于 $location的用法 简介 $location服务解析在浏览器地址栏中的URL(基于window.location)并且让URL在你的应用中可用.改变在地址栏中的URL会作用到$loc ...

  8. 『开源』Slithice 2013 服务器集群 设计和源码

    相关介绍文章: <『设计』Slithice 分布式架构设计-支持一体式开发,分布式发布> <『集群』001 Slithice 服务器集群 概述> <『集群』002 Sli ...

  9. 『设计』Slithice 分布式架构设计-支持一体式开发,分布式发布

    项目原因: 参与过各种 分布式项目,有 Socket,Remoting,WCF,当然还有最常用的可以跨平台的 WebService. 分布式编码的时间浪费: 但是,无一例外的,开发分布式程序的开发遵循 ...

随机推荐

  1. php中的session_id详解

    php中session_id()函数原型及说明session_id()函数说明:stringsession_id([string$id])session_id() 可以用来获取/设置 当前会话 ID. ...

  2. 面向对象的WebAPI框架XXL-HEX

    <面向对象的WebAPI框架XXL-HEX>    一.简介 1.1 概述 XXL-HEX 是一个简单易用的WebAPI框架, 拥有 "面向对象.数据加密.跨语言" 的 ...

  3. Flask入门之flask-wtf表单处理

    参考文章 1. 使用 WTForms 进行表单验证  第11集 #Sample.py # coding:utf-8 from flask import Flask,render_template,re ...

  4. 【转】搭建自己的 sentry 服务

    1. 安装 docker 首先要确认你的 Ubuntu 版本是否符合安装 Docker 的前提条件.如果没有问题,你可以通过下边的方式来安装 Docker : 使用具有 sudo 权限的用户来登录你的 ...

  5. PAT1065: A+B and C (64bit)

    1065. A+B and C (64bit) (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 HOU, Qiming G ...

  6. jquery遍历table为每一个单元格取值及赋值

    表格代码 <tr> <td> <input type="text" style="border: none; text-align: cen ...

  7. Whitelabel Error Page 专题

    Spring boot为错误视图提供了如下错误属性:timestamp:错误发生的时间status:HTTP状态码error:错误原因exception:异常的类名message:异常消息(如果这个错 ...

  8. OAuth 2 Developers Guide

    Introduction This is the user guide for the support for OAuth 2.0. For OAuth 1.0, everything is diff ...

  9. day14_DBUtils学习笔记

    一.DBUtils介绍 Apache公司开发的框架. 什么是dbutils?它的作用?   DBUtils是java编程中的数据库操作实用工具,小巧简单实用.   DBUtils封装了对JDBC的操作 ...

  10. ECMAScript简介以及es6新增语法

    ECMAScript简介 ECMAScript与JavaScript的关系 ECMAScript是JavaScript语言的国际化标准,JavaScript是ECMAScript的实现.(前者是后者的 ...