为什么无法获取启动进程的主窗口句柄?

我有一种情况,我在我的代码中启动一个进程,以便建立一个IPC通道。 我正在开始的过程是一个没有CLR支持的MFC应用程序。 我开始这个过程的应用程序是WPF应用程序中的C#模块(我认为这不是我的问题的结果)。 这适用于支持CLR的应用程序版本,它适用于除部署目标之外的每台计算机,Windows 7的触摸屏计算机。但出于某种原因,当我尝试使用此确切方案时,Process对象永远不会解析主窗口句柄( Process.MainWindowHandle )。 这样做还有另一种(甚至是pinvoke)方法吗? 这是安全的事吗? 我是那个盯着这个过程的人。 进程的主窗口句柄确实存在。 我看不出有什么不对。

如果有帮助,这是我的代码。

  _applicationProcess = new Process(); _applicationProcess.StartInfo.FileName = _strProcessPath; _applicationProcess.StartInfo.Arguments = _strProcessArguments; _applicationProcess.Start(); long nTicks = Environment.TickCount; if (_applicationProcess.WaitForInputIdle(1 /*minute(s)*/ * 60000)) { try { do { // Don't let total processing take more than 1 minute(s). if (Environment.TickCount > nTicks + 1 /*minute(s)*/ * 60000) throw new ApplicationException("MFCApplication.Startup failed! The main window handle is zero!"); _applicationProcess.Refresh(); } while (_applicationProcess.MainWindowHandle.ToInt32() == 0); _applicationHandle = new IntPtr(_applicationProcess.MainWindowHandle.ToInt32()); } catch (Exception ex) { //Do some stuff... throw; } } else { // Do exception handling. } 

在尝试获取除零之外的主窗口句柄一分钟后,将触发ApplicationException

不幸的是,您从Process.MainWindowHandle获得的值是一个猜测。 程序没有可用的API函数,它可以告诉Windows“这是我的主窗口”。 它使用的规则是记录的,它是进程启动时创建的第一个窗口。 如果第一个窗口是登录窗口或启动画面,则会导致问题。

你无能为力,你必须更多地了解程序如何找到真正的主窗口。 只要在与主窗口相同的线程上创建第一个窗口,使用EnumThreadWindows()枚举窗口就可以帮助您找到它。 如果不是这样的话,将需要更精细的EnumWindows()。

我的习惯是在一个循环中调用EnumWindows并结合GetWindowThreadProcessId来查找窗口句柄。

 C Code, adapt to your language DWORD TargetHWND; //... while (EnumWindows(EnumWndProc, (LPARAM)(DWORD)pid)) { Sleep(100); } //... BOOL EnumWndProc(HWND hWnd, LPARAM lParam) { DWORD pid = (DWORD)-1; GetWindowThreadProcessId(hWnd, &pid); if (pid == (DWORD)lParam) { TargetHWND = hWnd; return FALSE; } return TRUE; } 

为了通过您的进程获取MainWindowHandle ,请确保您的WPF应用程序显示在任务栏上,即ShowInTaskbar="True" ,并将Application.Current.MainWindow属性设置为您要设置为主窗口的窗口。

如果我在WPF主窗口中执行下面的代码而没有设置ShowInTaskbar="True"我总是得到0作为MainWindowHandle因为我的WPF窗口是全屏的而没有显示在任务栏上。

  Application.Current.MainWindow = this; var Query = System.Diagnostics.Process.GetProcessesByName("ProcessName"); if (Query.Any()) { Query.FirstOrDefault().Refresh(); MessageBox.Show(Query.FirstOrDefault().MainWindowHandle.ToInt32().ToString()); } 

我不知道为什么会有所不同,但是在创建过程之后,请尝试:

 Process[] allProcesses = Process.GetProcessesByName("YourWindowTitle"); 

并查看返回的任何进程是否具有MainWindowHandle。