您如何找到哪个窗口需要进程所有权?
这是一个误解,肯定是你被卡住的原因。窗口不拥有进程,反之亦然。更巧妙的是,一个线程拥有一个窗口。一个进程拥有一个线程。
当您使用 Process.GetProcesses() 时,您将枚举许多根本没有任何窗口的进程。像机器上运行的所有服务一样,拥有数十个服务并不罕见。您可以使用任务管理器在“进程”选项卡中查看它们,请务必单击显示所有用户拥有的进程的选项。SysInternals 的 Process Explorer 也是一个非常好的工具,可以查看正在运行的内容。
所以不要对 Process.MainWindowHandle 返回 IntPtr.Zero 感到惊讶。还要记住,这是一个猜测。一个进程可以轻松拥有多个顶级窗口。其中哪一个是“主”窗口并不总是很明显。Process 类使用一个简单的规则,它假定它找到的第一个没有所有者且可见的顶级窗口是主窗口。
要可靠地获取进程的顶级窗口,您必须首先枚举进程中的线程。使用 Process.Threads 很容易做到。然后对于每个线程,您通过调用EnumThreadWindows()来迭代它拥有的窗口。与 EnumWindows() 完全相同的想法,但仅限于特定线程并且没有 firehose 问题,并且由于在迭代时创建了一个新窗口而导致它崩溃的可能性更低。您将获得线程拥有的顶级窗口,您想要什么,枚举每个顶级窗口拥有的子窗口需要 EnumChildWindows()。
一些值得注意的坏消息:请注意,需要进行一些过滤才能获得不错的结果。一个线程通常拥有一个根本不可见的窗口。通常用于处理线程间通信,尤其是使用 COM 的代码。因此,您可能还想调用 IsWindowVisible()。并始终检查这些 pinvoked 函数的错误,当您的程序未以管理员权限运行和/或未提升 UAC 时,故障很常见。始终根据您从 Spy++ 实用程序中看到的内容仔细检查您的结果。