zoukankan      html  css  js  c++  java
  • 通过钩子程序跨程序关闭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的时间值。

    
    
    
  • 相关阅读:
    读取web.xml中设置的参数
    在服务端中,读取properties资源文件中的数据
    window下,nodejs安装http-server,并开启HTTP服务器
    跨域请求资源的方式
    IView 给Submenu增加click事件失效解决方案
    Vue -- mounted方法中调用methods的方法(并取出mounted方法中回调函数的值)
    IView 使用Table组件时实现给某一列添加click事件
    物联网协议CoAP协议学习
    电脑操作
    物联网协议
  • 原文地址:https://www.cnblogs.com/hunanzp/p/8976229.html
Copyright © 2011-2022 走看看