在CS程序中启动其他应用后,要获取进程的主窗体其实很简单:
Process p = Process.Start(exePath); //p.WaitForInputIdle(); p.Refresh(); IntPtr mainWnd = p.MainWindowHandle;
但是,总有很多特殊的情况,上面的方法根本无法用,所以,要用Windows API来搞定了
1、如果窗口信息很固定而且没有重名的话,可以用Findwindow搞定
[DllImport("User32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); IntPtr clientWnd = FindWindow(null,"FormClient");
2、根据标题枚举窗口句柄
//枚举窗体 [DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)] public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam); //获取窗体标题 [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount); //设置错误状态 [DllImport("kernel32.dll", EntryPoint = "SetLastError")] public static extern void SetLastError(uint dwErrCode); //线程主窗口句柄 private static IntPtr processMainWnd = IntPtr.Zero; //要查找的窗口名称 private static String winTitle = "__Web__Form__Main__"; //声明委托函数 public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam); //枚举进程句柄,非线程安全 [SecuritySafeCritical] public static IntPtr GetCurrentWindowHandle() { IntPtr ptrWnd = IntPtr.Zero; bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)0); if (!bResult && Marshal.GetLastWin32Error() == 0) { ptrWnd = processMainWnd; } return ptrWnd; } //枚举函数,获取主窗口句柄然后退出 [SecuritySafeCritical] private static bool EnumWindowsProc(IntPtr hwnd, uint lParam) { //根据标题获取窗体 var sb = new StringBuilder(50); GetWindowText(hwnd, sb, sb.Capacity); if (winTitle.Equals(sb.ToString())) { processMainWnd = hwnd; SetLastError(0); return false; } return true; }
3、跟进进程id枚举获取主窗体句柄
//枚举窗体 [DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)] //获取父窗体 [DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)] //根据窗口获取线程句柄 [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern int GetWindowThreadProcessId(IntPtr hwnd, out uint pid); //设置错误状态 [DllImport("kernel32.dll", EntryPoint = "SetLastError")] public static extern void SetLastError(uint dwErrCode); //线程主窗口句柄 private static IntPtr processMainWnd = IntPtr.Zero; //枚举进程句柄 [SecuritySafeCritical] public static IntPtr GetCurrentWindowHandle(int processId) { IntPtr ptrWnd = IntPtr.Zero; bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)processId); if (!bResult && Marshal.GetLastWin32Error() == 0) { ptrWnd = processMainWnd; } return ptrWnd; } //枚举函数,获取主窗口句柄然后退出 [SecuritySafeCritical] private static bool EnumWindowsProc(IntPtr hwnd, uint lParam) { uint uiPid = 0; //根据启动方式不同,这里要有相应修改 if (GetParent(hwnd) == IntPtr.Zero) { GetWindowThreadProcessId(hwnd, out uiPid); if (uiPid == lParam) { processMainWnd = hwnd; SetLastError(0); return false; } } }
4、跟进窗口WindowsClassName举获取主窗体句柄
//查找桌面 [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] public static extern IntPtr GetDesktopWindow(); //获取窗体句柄 [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] public static extern IntPtr GetWindow(IntPtr hwnd, int wFlag); //获取窗体类 [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); public const int GW_CHILD = 5; public const int GW_HWNDNEXT = 2; //枚举桌面窗口,根据WindowsClassName获取句柄 [SecuritySafeCritical] public static IntPtr GetWinHandleByClasName(String windowClassNmae) { //取得桌面窗口,再获取第一个子窗口 IntPtr hwnd = GetDesktopWindow(); hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_CHILD)); //通过循环来枚举所有的子窗口 while ((long)hwnd != 0) { System.Text.StringBuilder ClassName = new System.Text.StringBuilder(256); GetClassName((IntPtr)hwnd, ClassName, ClassName.Capacity); String tmpClassName= ClassName.ToString().Trim(); if (tmpClassName.Length > 0) { if (tmpClassName.Equals(windowClassNmae)) { break; } } hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_HWNDNEXT)); } return hwnd; }