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);

 

posted @ 2020-07-05 00:55  逍遥子k  阅读(1482)  评论(0编辑  收藏  举报