一般需要程序单例运行时,在第二次运行程序时,可以激活正在运行的程序。那么需要找到该程序的窗体句柄。
但如果运行程序已经最小化,或者没显示在任务栏,则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}"; } }
具体代码就不贴出了,几个注意点:
1. 需要循环调用FindWindowEx找出所有桌面*句柄
2. 找出的句柄要判断是否可见,用IsWindowVisible判断
3. 找到正确句柄后,如不能正确激活,ShowWindowAsync函数可调用两次,传如9和5
ShowWindowAsync(hwnd, (int)ShowWindowFlag.SW_RESTORE); //9 ShowWindowAsync(hwnd, (int)ShowWindowFlag.SW_SHOW); //5
SetForegroundWindow(hwnd);