zoukankan      html  css  js  c++  java
  • C# MainWindowHandle为0的解决方法(2)

    一般需要程序单例运行时,在第二次运行程序时,可以激活正在运行的程序。那么需要找到该程序的窗体句柄。

    但如果运行程序已经最小化,或者没显示在任务栏,则Process.MainWindowHandle属性可能为0,则需要其他思路来找到正确的句柄。

    方法1: https://www.cnblogs.com/xyz0835/p/3351424.html

    方法1的有一个缺陷,就是如果程序的主标题随时在变化,或者标题有可能会重复,则不太方便找到已最小化的窗体句柄。

    方法2改善后的思路如下:

    1. 用Process.GetProcessesByName()查找在运行的进程,找出进程id与当前不同的进程. 

    2. 如果进程MainWindowHandle为0,则利用FindWindowEx函数查找所有顶级窗体句柄

    3. 利用GetWindowThreadProcessId函数,判断找出的句柄是否属于该进程

    4. 步骤3中可能会找出不少属于该窗体的顶级句柄,那需要用IsWindowVisible函数判断其是否可见(最小化的窗体可见性是true,只是窗体位置移到了坐标负值,桌面上看不到)。

    5.一般经过步骤4,就能找出正确的窗体句柄。如果还不对,则用GetWindowRect函数查找窗体的大小是否需要查找的句柄

    6. 找到正确句柄后,使用ShowWindowAsync和SetForegroundWindow函数,就可以正确激活该进程的已最小化的窗体。

    相关函数:

            [DllImport("user32.dll")]
            static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
    
            [DllImport("user32.dll")]
            static extern IntPtr GetWindowThreadProcessId(IntPtr window, out int process);
    
            [DllImport("user32.dll")]
            static extern IntPtr FindWindowEx(IntPtr parentWindow, IntPtr previousChildWindow, string windowClass, string windowTitle);
    
            [DllImport("user32.dll")]
            public static extern bool SetForegroundWindow(IntPtr hWnd);
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
    
            [DllImport("user32.dll")]
            static extern bool IsWindowVisible(IntPtr hWnd);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
    
            public int Width => Right - Left;
    
            public int Height => Bottom - Top;
    
            public override string ToString()
            {
                return $"{Left} {Top} {Width} {Height}";
            }
        }

    具体代码

            private static IntPtr GetProcessWindows(int process)
            {
                IntPtr pLast = IntPtr.Zero;
                do
                {
                    pLast = FindWindowEx(IntPtr.Zero, pLast, null, null);
                    int iProcess_;
                    GetWindowThreadProcessId(pLast, out iProcess_);
                    if (iProcess_ == process)
                    {
                        if (IsWindowVisible(pLast))
                            return pLast;
                    }
                } while (pLast != IntPtr.Zero);
    
                return pLast;
            }

    1. 需要循环调用FindWindowEx找出所有桌面顶级句柄

    2. 找出的句柄要判断是否可见,用IsWindowVisible判断

    3. 找到正确句柄后,如不能正确激活,ShowWindowAsync函数可调用两次,传如9和5

    ShowWindowAsync(hwnd, (int)ShowWindowFlag.SW_RESTORE); //9
    ShowWindowAsync(hwnd, (int)ShowWindowFlag.SW_SHOW); //5
    SetForegroundWindow(hwnd);
  • 相关阅读:
    Navicat for MySQL远程连接的时候报错mysql 1130的解决方法
    阿里云主机 CentOS6.5 安装Mysql php Apache
    MAC下使用feddler进行抓包
    javascript钩子之Backbone里的实现
    SASS编译
    动态代理模式和AOP探究
    二分查找算法
    MyBatis在非Spring环境下第三方DataSource设置-Druid篇
    写字节流转换String 代码示例
    SpringAOP代理报错问题
  • 原文地址:https://www.cnblogs.com/xyz0835/p/13237387.html
Copyright © 2011-2022 走看看