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

时间:2011-01-18 17:22:54

标签: c# wpf mfc process ipc

我有一种情况,我在我的代码中启动一个进程,以便建立一个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被点击。

4 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:3)

我的习惯是在一个循环中调用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;
}

答案 2 :(得分:2)

为了通过您的流程获得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());
    }

答案 3 :(得分:1)

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

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

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