从窗口句柄获取窗口实例

16

我能够使用以下代码从运行的应用程序获取窗口句柄。

foreach (ProcessModule module in process.Modules)
{
  if (module.ModuleName.Contains("PresentationFramework.dll") || module.ModuleName.Contains("PresentationFramework.ni.dll"))
  {
    IntPtr window = process.MainWindowHandle;
  }
}

但我想从该处理程序中获取Window实例。 这可能吗?

请问是否有任何快速的想法?


你是指窗口句柄吗?(去掉'r')你是在寻找实际的.NET对象吗? - Emond
您无法从另一个进程的 HWND 获取 System.Windows.Window。尽管如此,您试图做什么?最终可能有某些方法可以实现您所尝试的操作。 - Simon Mourier
2个回答

12

请尝试以下方法:

IntPtr handle = process.MainWindowHandle;

HwndSource hwndSource = HwndSource.FromHwnd(handle);

Window = hwndSource.RootVisual as Window;

更新:

但是,这个方法只能在同一个应用程序域内使用,否则就意味着您可以在不同的应用程序域和进程之间共享对象,这显然是不可能的。


这个可以运行。但是只适用于当前应用程序。我可以获取当前 WPF 应用程序的窗口。其他的会抛出 NRE 异常。HwndSource 返回 null。还有其他帮助吗? - Jawahar
@Jawahar - 无法从当前AppDomain/进程之外访问对象(除非使用Remoting)。请查看我的更新。 - Pavlo Glazkov
有没有其他方法,比如使用非托管代码,例如使用user32.dll? - Jawahar
2
@Jawahar - 这是一个概念性问题,与.NET无关。您不能在进程之间共享相同的对象。假设您从不同的进程中获取了窗口实例。现在问问自己,如果更改此窗口的某些属性(例如位置),应该发生什么?如果可能的话,那么任何程序都可以操作任何其他程序的窗口... - Pavlo Glazkov
有人知道如何做相反的操作吗?我需要从现有的窗口对象获取IntPtr句柄。 - Dawid

9
在WPF应用程序(或WinForms)中,一个“窗口”有两个“对象”(即包含信息的内存块):
  1. 系统窗口对象。
  2. 管理对象,它“包装”了系统对象。
通过窗口句柄(在未经处理的代码中为HWND类型,在托管代码中为IntPtr),可以访问系统窗口对象。给定已获取的窗口句柄,可以使用{{link1:Window API方法}}操纵该窗口。可以使用p/invoke进行此操作。
禁止访问驻留在进程堆(或托管进程的AppDomain)中的托管对象。这段内存受到其他进程(1)的“保护”。
对象之间唯一可以在进程(或AppDomains)之间共享的方式是通过编组,这是两个进程的协作努力。即使是访问另一个进程中的窗口时,许多Win32 API方法也需要进行编组。没有自定义编组,不可能进行所有访问。
请注意,与WinForms不同,WPF通常不使用系统窗口来控制。如果您的目标是在另一个WPF进程/域中操作可视树,则除非该进程提供某种自动化接口,否则您将无法实现。
(1)虽然可以读取另一个进程的原始内存,但托管堆上的对象是移动目标。即使您能够以某种方式暂停该进程的垃圾收集线程,您也永远找不到它们。

+1 给那些“移动目标”,“甚至找不到”的人!(整个语言非常丰富多彩,但这一点让我印象深刻) - ivan_pozdeev

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