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);
  • 相关阅读:
    【编程基础】const与#define的区别
    【Unity3D】模仿制作“神庙逃亡”吃金币后金币飞出屏幕效果
    【基础数学】素数判定、素数打表
    【NYOJ-187】快速查找素数—— 枚举法、筛选法、打表法
    【基础数学】质数,约数,分解质因数,GCD,LCM
    【NYOJ-35】表达式求值——简单栈练习
    【UVa-679】小球下落——二叉树的编号
    【UVa-442】矩阵链乘——简单栈练习
    【UVa-514】铁轨——栈的学习
    gitignore git提交忽略文件
  • 原文地址:https://www.cnblogs.com/xyz0835/p/13237387.html
Copyright © 2011-2022 走看看