3

我正在尝试使用其句柄(即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 来工作。

如果我不能,是否有另一种访问窗口的方法(即,而不是使用句柄)?

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

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

4

4 回答 4

2

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

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

但是您所针对的窗口处于不同的进程中。所以你根本不能NativeWindow在这里使用。您将不得不将窗口句柄用作IntPtr.

在您的编辑中,您声明:

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

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

于 2012-05-22T15:54:54.463 回答
2

那么,正如雷蒙德建议的那样,您为什么不尝试使用自动化呢?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();
        }
    }
}

参考

于 2012-05-23T21:51:04.237 回答
1

你想访问什么?您可以在 Windows 中获取窗口的标题和文本。但是你不能得到另一个应用程序的 NativeWindow 对象。您需要使用 windows API 与其他应用程序进行交互。我曾经在另一个应用程序中劫持了一个对象,但是通过知道它的类并发现了一个 hack 来找到它的 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 挂钩,在我的示例中举例说明

于 2012-05-22T15:56:27.347 回答
0

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

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);

如果不是对不起,没有很好地回答这个问题。

于 2012-05-22T15:49:32.963 回答