C#中的Process.MainWindowHandle总是返回IntPtr Zero

16

这是我的代码:

            using (Process game = Process.Start(new ProcessStartInfo() { 
        FileName="DatabaseCheck.exe",
        RedirectStandardOutput = true,
        CreateNoWindow = true,
        UseShellExecute = false }))
        {
            lblLoad.Text = "Loading";
            int Switch = 0;

            while (game.MainWindowHandle == IntPtr.Zero)
            {
                Switch++;
                if (Switch % 1000 == 0)
                {
                    lblLoad.Text += ".";
                    if (lblLoad.Text.Contains("...."))
                        lblLoad.Text = "Loading.";

                    lblLoad.Update();
                    game.Refresh();
                }
            }

问题是游戏的 game.MainWindowHandle 总是 IntPtr.Zero。我需要找到运行进程的 IntPtr 以确认游戏是否由启动器启动,因此我让游戏发送它的 IntPtr,然后启动器响应是否可行。但为此,我必须特别知道运行进程的 IntPtr。

提前致谢!

3个回答

16

主窗口是当前具有焦点(即顶级表单)的进程打开的窗口。必须使用Refresh方法刷新进程对象,以获取当前的主窗口句柄(如果已更改)。

只能为在本地计算机上运行的进程获取MainWindowHandle属性。MainWindowHandle属性是唯一标识与进程关联的窗口的值。

仅当进程拥有图形界面时,它才有一个与之关联的主窗口。如果相关的进程没有主窗口,则MainWindowHandle值为零。对于已隐藏的进程,即在任务栏中不可见的进程,该值也为零。这可能是出现在任务栏最右边的通知区域图标的进程的情况。

如果您刚刚启动一个进程并想要使用其主窗口句柄,请考虑使用WaitForInputIdle方法,以允许进程完成启动,确保已创建主窗口句柄。否则,将引发异常。


回家后我会尝试一下。谢谢。 - Kfir Eichenblat
请注意,在4.5版本中不再需要这样做(个人经验 - 我的代码在4.5上运行正常,但当我降级到3.5时失败了,直到我添加了“.Refresh()”)。 - Basic

8
一个解决方法是枚举所有顶级窗口并检查它们的进程ID,直到找到匹配项...

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindowEx(IntPtr parentWindow, IntPtr previousChildWindow, string windowClass, string windowTitle);

    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowThreadProcessId(IntPtr window, out int process);

    private IntPtr[] GetProcessWindows(int process) {
        IntPtr[] apRet = (new IntPtr[256]);
        int iCount = 0;
        IntPtr pLast = IntPtr.Zero;
        do {
            pLast = FindWindowEx(IntPtr.Zero, pLast, null, null);
            int iProcess_;
            GetWindowThreadProcessId(pLast, out iProcess_);
            if(iProcess_ == process) apRet[iCount++] = pLast;
        } while(pLast != IntPtr.Zero);
        System.Array.Resize(ref apRet, iCount);
        return apRet;
    }

1
只是想提一下,在查找其他进程的窗口时,这种解决方法在Unity上非常有效(而使用_Refresh_ + _MainWindowHandle_总是给我零指针)。 - dkrprasetya

6
while (!proc.HasExited)
{
    proc.Refresh();
    if (proc.MainWindowHandle.ToInt32() != 0)
    {
        return proc.MainWindowHandle;
    }
}

4
您好,您的帖子被标记为“低质量”,可能是因为它只包含代码。您可以提供一份解释,清楚地说明为什么这个答案能够回答问题,这样会极大地改善您的回答质量。 - Ben
2
对于阅读这篇旧帖子的任何人...我记得在某个地方读到过,使用类似这样的东西不是一个好主意,因为x64与x86。最好使用IntPtr.Zero != proc.MainWindowHandle - David Bentley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接