Как получить доступ к окну?

Я пытаюсь получить доступ к определенному окну, используя его дескриптор (это значение 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.

Если я не могу, есть ли другой способ получить доступ к окну (то есть вместо использования дескрипторов)?

=================== ИЗМЕНИТЬ

Я хочу иметь дело со всем объектом окна и его собственными элементами управления.


person Community    schedule 22.05.2012    source источник
comment
Не могли бы вы использовать user32.dll и вызвать FindWindow(null, Window Title)?   -  person Dan Armstrong    schedule 22.05.2012
comment
это другое приложение Windowsforms для .NET?   -  person Tigran    schedule 22.05.2012
comment
Я предполагаю, что первый пример вызывает один form'ui из другого потока, а второй пример из того же потока. Попробуйте использовать BeginInvoke   -  person Val Bakhtin    schedule 22.05.2012
comment
Почему бы не использовать пространство имен System.Windows.Automation? Его целью является манипулирование элементами управления других приложений!   -  person Raymond Chen    schedule 23.05.2012


Ответы (4)


Тогда, как предложил Рэймонд, почему бы вам не попробовать автоматизацию? Добавьте консольный проект со ссылками на 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();
        }
    }
}

ссылка

person danielQ    schedule 23.05.2012
comment
Это не совсем то, что я хочу, но это не проблема - person ; 29.05.2012

В документации для NativeWindow.FromHandle объясняется, почему эта функция всегда возвращает вам null:

Дескриптор уже должен принадлежать другому NativeWindow в текущем процессе; в противном случае возвращается ноль.

Но окно, на которое вы нацеливаетесь, находится в другом процессе. Таким образом, вы просто не можете использовать NativeWindow здесь. Вам придется обойтись дескриптором окна как IntPtr.

В своем редактировании вы указываете:

Я хочу иметь дело со всем объектом окна и его собственными элементами управления.

Это ничего не меняет. Вы не можете использовать NativeWindow. Вам придется иметь дело с необработанным Win32 API.

person David Heffernan    schedule 22.05.2012

К чему вы хотите получить доступ? Вы можете получить заголовок и текст окон в 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 и перехватчики окон, как показано в моем примере здесь.

person Motes    schedule 22.05.2012

Не понял, что вы действительно пытаетесь сделать, но, может быть, если вы попытаетесь...

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

Если не извиняюсь, не очень понял вопрос.

person danielQ    schedule 22.05.2012
comment
-1 Если вопрос не понял, а он действительно так выглядит, то лучше искать разъяснения через комментарии. Этот ответ действительно бесполезен. Кстати, я пытаюсь помочь вам понять, как давать лучшие ответы, а не унижать вас. - person David Heffernan; 22.05.2012
comment
Спасибо, Дэвид, сначала я попрошу разъяснений;) - person danielQ; 22.05.2012