如何访问窗口
本文关键字:窗口 访问 何访问 | 更新日期: 2023-09-27 18:34:54
我正在尝试使用其句柄(即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");
我认为这是有效的,因为它是从同一个应用程序调用的。那么,如何通过其句柄访问另一个程序的窗口对象?我认为它可以通过使用头文件<windows.h>
然后使用 P''invoke 来使用 C'C++
。
如果我不能,有没有另一种方法可以访问窗口(即而不是使用句柄(?
===================编辑
我想处理整个窗口对象及其自己的控件
然后,正如 Raymond 所建议的那样,您为什么不尝试使用自动化呢?添加引用UIAutomationClient
和UIAutomationTypes
的控制台项目
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
:
该句柄必须已由 当前流程;否则,返回 null。
但是,您定位的窗口处于不同的过程中。所以你根本不能在这里使用NativeWindow
。您将不得不将窗口手柄用作IntPtr
。
在编辑中,您需要声明:
我想处理整个窗口对象及其自己的控件
这不会改变什么。你不能使用NativeWindow
.您将不得不处理原始的Win32 API。
你想访问什么?您可以在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 注入和窗口钩子,我在这里的例子中举例说明。
没有得到你真正想做的事情,但也许如果你尝试......
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);
如果不对不起,没有很好地理解这个问题。