通过钩子程序跨程序关闭Window
需求:
在实际场景中会有自身程序在调用第三方的动态库过程中,因为第三方的动态库弹框导致线程阻塞,必须手动将弹窗关闭后才能回到自身程序的主线程中。
最简单的场景就是很多自助设备,本身是没有固定操作员的,如果用户在看到弹框后没有手动点击关闭则弹框会一直会存在。
解决方案:
1、通过Windows提供的API,FindWindow(通过Window的Title)获取到第三方弹框句柄,通过SendMessage向Winwos发起关闭该句柄的命令;
2、如果该弹框有“关闭“按钮,则通过FindWindow获取到句柄后,再通过FindwWindowEx找到“关闭”按钮子句柄,然后通过SendMessage发起鼠标左击事件;
Code:
方案1:
/// <summary>
/// 寻找系统的全部窗口
/// </summary>
/// <returns></returns>
public WindowInfo[] GetAllDesktopWindows()
{
List<WindowInfo> wndList = new List<WindowInfo>();
EnumWindows(delegate (IntPtr hWnd, int lParam)
{
WindowInfo wnd = new WindowInfo();
StringBuilder sb = new StringBuilder(256);
//get hwnd
wnd.hWnd = hWnd;
//get window name
GetWindowTextW(hWnd, sb, sb.Capacity);
wnd.szWindowName = sb.ToString();
//get window class
GetClassNameW(hWnd, sb, sb.Capacity);
wnd.szClassName = sb.ToString();
//add it into list
wndList.Add(wnd);
return true;
}, 0);
return wndList.ToArray();
} /// <summary>
/// 根据指定窗口标题暴力干掉这个窗口
/// </summary>
/// <param name="windowTitle">window的标题</param>
/// <param name="second">指定多少秒后关闭window</param>
/// <returns></returns>
public async Task KillWindow(string windowTitle, int second = 3)
{
try
{
await Task.Delay(TimeSpan.FromSeconds(second));
#region 通过获取所有窗口方式关闭 WindowInfo[] a = GetAllDesktopWindows();
int i = 0;
int index = 0;
for (i = 0; i < a.Length; i++)
{
if (a[i].szWindowName.ToString().Contains(windowTitle))
{
index = i;
IntPtr myIntPtr = a[index].hWnd;
//先置顶!!!不置顶发送windows消息没卵用
SetWindowPos(myIntPtr, -1, 0, 0, 0, 0, 1 | 2);
if (myIntPtr != null)
{
IntPtr childHwnd = FindWindowEx(myIntPtr, IntPtr.Zero, null, "否(&N)");
SendMessage(childHwnd, BM_CLICK, 0, 0); //发送点击按钮的消息
}
break;
}
}
#endregion
}
catch (Exception)
{
}
}
方案二:
/// <summary>
/// 根据指定窗口标题暴力干掉这个窗口
/// </summary>
/// <param name="windowTitle">window的标题</param>
/// <param name="second">指定多少秒后关闭window</param>
/// <returns></returns>
public async Task KillWindowAndBtn(string windowTitle, int second = 3, string btnTxt = "否(&N)")
{
try
{
await Task.Delay(TimeSpan.FromSeconds(second));
#region 通过获取所有窗口方式关闭 WindowInfo[] a = GetAllDesktopWindows();
int i = 0;
int index = 0;
for (i = 0; i < a.Length; i++)
{
if (a[i].szWindowName.ToString().Contains(windowTitle))
{
index = i;
IntPtr myIntPtr = a[index].hWnd;
//先置顶!!!不置顶发送windows消息没卵用
SetWindowPos(myIntPtr, -1, 0, 0, 0, 0, 1 | 2);
if (myIntPtr != null)
{
IntPtr childHwnd = FindWindowEx(myIntPtr, IntPtr.Zero, null, btnTxt);
SendMessage(childHwnd, BM_CLICK, 0, 0); //发送点击按钮的消息
}
break;
}
}
#endregion
}
catch (Exception)
{
}
}
调用方式(第一种方案):
private async void KillCardErrorWindow()
{
WinUtils utils = new WinUtils();
//通过获取全部窗口方式进行模糊查询
await utils.KillWindow("卡");
}
调用第二种方案:
/// <summary>
/// 杀掉医保读卡dll生成的window
/// </summary>
private async void KillPassWordWindow()
{
WinUtils utils = new WinUtils();
//通过获取全部窗口方式进行模糊查询
await utils.KillWindow("输入密码"); //"读市民卡错误提示:"
}
PS: 无论使用哪一种方案,都必须在调用第三方API之前先发起杀掉window的方法,留意代码即可知道,都是通过异步执行的。
所以结合实际场景需要,请先设定Task.Delay的时间值。
通过钩子程序跨程序关闭Window的更多相关文章
- MemoryMappedFile 在IIS与程序跨程序交互数据的权限问题
使用IIS 与程序交互时,发布到IIS上获取不到数据提供方的数据(VSF5运行可以获取到数据),MemoryMappefFile基本使用不做介绍 数据方 static void Main(string ...
- Android入门(十四)内容提供器-实现跨程序共享实例
原文链接:http://www.orlion.ga/661/ 打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的 ...
- android: 实现跨程序数据共享
简单起见,我们还是在上一章中 DatabaseTest 项目的基础上继续开发,通过内容提供器 来给它加入外部访问接口. 打开 DatabaseTest 项目,首先将 MyDatabaseHelper ...
- CreateWindowEx failed (当前程序已使用了 Window 管理器对象的系统允许的所有句柄。)
我在QT图形场景视图中通过QGraphicsProxyWidget添加代理Widget(实现添加基本的QT Widget,如按钮.复选框.日期时间控件等),当数量超过3500左右的时候,QT应用程序直 ...
- Android学习--跨程序共享数据之内容提供其探究
什么是内容提供器? 跨程序共享数据之内容提供器,这是个什么功能?看到这个名称的时候最能给我们提供信息的应该是“跨程序”这个词了,是的重点就是这个词,这个内容提供器的作用主要是用于在不同的引用程序之间实 ...
- C# 最基本的涉及模式(单例模式) C#种死锁:事务(进程 ID 112)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务,解决方案: C#关闭应用程序时如何关闭子线程 C#中 ThreadStart和ParameterizedThreadStart区别
C# 最基本的涉及模式(单例模式) //密封,保证不能继承 public sealed class Xiaohouye { //私有的构造函数,保证外部不能实例化 private ...
- Java基础-输入输出-2.编写IoDemo.java的Java应用程序,程序完成的功能是:首先读取text.txt文件内容,再通过键盘输入文件的名称为iodemo.txt,把text.txt的内容存入iodemo.txt
2.编写IoDemo.java的Java应用程序,程序完成的功能是:首先读取text.txt文件内容,再通过键盘输入文件的名称为iodemo.txt,把text.txt的内容存入iodemo.txt ...
- JAVA基础-输入输出:1.编写TextRw.java的Java应用程序,程序完成的功能是:首先向TextRw.txt中写入自己的学号和姓名,读取TextRw.txt中信息并将其显示在屏幕上。
1.编写TextRw.java的Java应用程序,程序完成的功能是:首先向TextRw.txt中写入自己的学号和姓名,读取TextRw.txt中信息并将其显示在屏幕上. package Test03; ...
- C#:手把手教你用C#打包应用程序(安装程序卸载程序)
摘要:本文介绍在C#中手把手教你用C#打包应用程序(安装程序卸载程序) 1:新建安装部署项目 打开VS,点击新建项目,选择:其他项目类型->安装与部署->安装向导(安装项目也一样),然后点 ...
随机推荐
- android studio gradle 打jar 包 (混淆+第三方库包)
将依赖的第三方库打包进自己的jar包 1.先将第三方的库包拿到,然后添加jar包到项目的libs. 2.项目的build.gradle脚本添加下面的task: task buildJar(depend ...
- URI is not registered ( Setting | Project Settings | Schemas and DTDs )
URI is not registered ( Setting | Project Settings | Schemas and DTDs ) 在idea中,当初手动第一次写spring配置文件的时候 ...
- VS2017 生成事件去除未修改项目
1.右键“解决方案”→“配置管理器” 2.列“生成”,反勾选无需编译的项目 3.点击“确定”,重新编译即可跳过未勾选的项目.
- SpringSecurity实现权限管理和页面导航栏动态实现
用户模块. 3 1.1 需求:获取用户名. 3 1.1.1 分析. 3 1.1.2 服务端获取用户信息. 4 1.1.3 页面获取用户信息. 5 1.2 给用户分配角色. ...
- 关于Http协议,你必须要知道的
转自:https://segmentfault.com/a/1190000016751071 引言 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用 ...
- 十八、泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器基础加强
l 泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器 泛型 1 回顾泛型类 泛型类:具有一个或多个泛型变量的类被称之为泛型类. public class A<T> { ...
- unittest各个组件之间的关系
各个组件的含义: TestCase:测试用例,测试用例里面会有很多测试方法,是单元测试中最小维度的测试行为. TestSuite:测试套件,是测试用例的集合. TestFixure:测试固件,测试准备 ...
- Reactjs组件中的方法为什么绑定this?
前言:Reactjs中的定义的方法其实是基于实例的原型方法:es6默认严格模式 问题:在Reactjs组件中写入以下代码,那么执行结果会是什么呢? ··· 结果是这样的: 对的,你没看错,不是do ...
- Java面试题:Hibernate的二级缓存与Hibernate多表查询
我们来看两个有关Java框架之Hibernate的面试题,这是关于Hibernate的常考知识点. 1.请介绍一下Hibernate的二级缓存 解题按照以下思路来回答: (1)首先说清楚什么是缓存: ...
- vue中实现动态切换不同的值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...