如何访问一个窗口?

我试图访问一个特定的窗口使用它的句柄(即System.IntPtr值):

  // Getting the process of Visual Studio program var process = Process.GetProcessesByName("devenv")[0]; // Showing the handle we've got, we've no problem MessageBox.Show(this, process.MainWindowHandle.ToString()); // Attempting to get the main window object by its handle var wnd = NativeWindow.FromHandle(process.MainWindowHandle); // always fails if (wnd == null) MessageBox.Show("Failed"); else MessageBox.Show(wnd.ToString(), "Yeeeeees!!"); 

我也尝试访问另一个演示.net winforms应用程序的主窗口,我已经做了这个目的,(即我运行演示应用程序,并尝试访问它的主窗口通过此应用程序),也失败了,虽然两者演示和这个应用程序是.NET应用程序。 但是,这个成功:

  var process2 = Process.GetCurrentProcess(); MessageBox.Show(this, process2.MainWindowHandle.ToString()); var wnd2 = NativeWindow.FromHandle(process2.MainWindowHandle); if (wnd2 == null) MessageBox.Show("Failed"); else MessageBox.Show(wnd2.ToString(), "Yes"); 

我认为这是有效的,因为它是从同一个应用程序调用的。 那么,如何通过句柄访问另一个程序的窗口对象呢? 我认为它可以使用C\C++通过使用头文件<windows.h> ,然后使用P \ invoke。

如果我不能,是否有另一种方式来访问一个窗口(即而不是使用手柄)?

=================== 编辑

我想处理整个窗口对象和自己的控件

Solutions Collecting From Web of "如何访问一个窗口?"

然后,正如雷蒙德所说,你为什么不尝试使用自动化? 添加一个引用到UIAutomationClientUIAutomationTypes的控制台项目

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Automation; using System.Diagnostics; using System.Threading; namespace ConsoleApplication { class Program { static void Main(string[] args) { var pInfo = new ProcessStartInfo("notepad"); var p = Process.Start(pInfo); p.WaitForInputIdle(); AutomationElement installerEditorForm = AutomationElement.FromHandle(p.MainWindowHandle); // menus AutomationElementCollection menuBars = installerEditorForm.FindAll(TreeScope.Children, new PropertyCondition( AutomationElement.ControlTypeProperty, ControlType.MenuBar)); var mainMenuItem = menuBars[0]; AutomationElementCollection menus = mainMenuItem.FindAll(TreeScope.Children, new PropertyCondition( AutomationElement.ControlTypeProperty, ControlType.MenuItem)); var fileMenuItem = menus[0]; ExpandCollapsePattern fileMenuItemOpenPattern = (ExpandCollapsePattern)fileMenuItem.GetCurrentPattern( ExpandCollapsePattern.Pattern); fileMenuItemOpenPattern.Expand(); AutomationElement fileMenuItemNew = fileMenuItem.FindFirst(TreeScope.Children, new AndCondition( new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuItem), new PropertyCondition(AutomationElement.NameProperty, "New"))); Console.Read(); } } } 

参考

NativeWindow.FromHandle的文档解释了为什么该函数总是为您返回null

句柄在当前进程中必须已经被另一个NativeWindow拥有; 否则返回null。

但是你所瞄准的窗口是在一个不同的过程。 所以你不能在这里使用NativeWindow 。 你将不得不作为一个IntPtr做窗口句柄。

在你的编辑中你声明:

我想处理整个窗口对象和自己的控件

这没有改变。 您不能使用NativeWindow 。 你将不得不处理原始的Win32 API。

你想要访问什么? 您可以在Windows中获得Windows的标题和文本。 但是你不能得到另一个应用程序的NativeWindow对象。 您需要使用Windows API与其他应用程序进行交互。 我曾经在另一个应用程序中劫持了一个对象,但是通过了解它的类并发现了一个黑客来找到它的Idispatch指针,你可以在这里查看它。 以下是如何获得前景窗口的标题,希望这有助于。

 using System.Runtime.InteropServices; using System.Text; [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); private string GetActiveWindowTitle() { const int nChars = 256; IntPtr handle = IntPtr.Zero; StringBuilder Buff = new StringBuilder(nChars); handle = GetForegroundWindow(); if (GetWindowText(handle, Buff, nChars) > 0) { return Buff.ToString(); } return null; } 

想想我可能会补充一点,如果你想要继承另一个应用程序的窗口,你应该看看我上面的链接。 我相信唯一的方法是使用DLL注入和Windows挂钩,在我的例子中例举。

没有得到你真正想做的事情,但也许如果你尝试…

 public class ApiUtils { [DllImport("user32")] public static extern int SetForegroundWindow(IntPtr hwnd); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow); [DllImport("user32.dll")] public static extern int GetForegroundWindow(); public static void ActiveWindow(IntPtr hwnd) { if ((IntPtr)GetForegroundWindow() != hwnd) { ShowWindow(hwnd, ShowWindowCommand.ShowMaximized); } } } 

现在叫它…

 Process p = Process.Start(new ProcessStartInfo() { FileName = "someApp.exe"}); ApiUtils.ShowWindow(p.MainWindowHandle, WindowShowStyle.ShowNormal); 

如果没有抱歉,没有得到很好的问题。