user586399
user586399

Reputation:

How to access a window?

I'm trying to access a specific window using its handle (that is System.IntPtr value):

        // 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!!");

I have tried also to access another demo .net winforms application's main window, that I have made for this purpose, (i.e. I run the demo application, and attempted to access its main window by this application), and failed, too, although both the demo and this application are .NET applications. However, this successes:

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

I think this works because it is invoked from the same application. So, how can I access some another program's window object by its handle? I thought it can work using C\C++ by using header file <windows.h> and then using a P\invoke.

If I can't, is there another way to access a window (i.e. rather than using handles)?

=================== EDIT

I want to deal with the entire window object and its own controls

Upvotes: 4

Views: 6458

Answers (4)

Motomotes
Motomotes

Reputation: 4237

What do you want to access? You can get the title and text of windows in Windows. But you cant get a NativeWindow object of another application. You need to use the windows API to interact with other applications. I once hijacked an object in another app, but did so by knowing its class and discovering a hack to find its Idispatch pointer, you can look into it here. Below is how to get the title of the foreground window, hope this helps.

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

Thought I might add, if you're trying to subclass a window of another application, you should take a look at my link above. I believe the only way to do it is using DLL injection and windows hooks, exemplified in my example here.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 613003

The documentation for NativeWindow.FromHandle explains why that function always returns null for you:

The handle must already be owned by another NativeWindow in the current process; otherwise, null is returned.

But the window that you are targeting is in a different process. So you simply cannot use NativeWindow here. You will have to make do with the window handle as an IntPtr.

In your edit you state:

I want to deal with the entire window object and its own controls

That changes nothing. You can't use NativeWindow. You will have to deal with the raw Win32 API.

Upvotes: 3

danielQ
danielQ

Reputation: 2086

Then, as Raymond suggested, why don't you try with Automation? Add a console project with references to UIAutomationClient and 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();
        }
    }
}

reference

Upvotes: 3

danielQ
danielQ

Reputation: 2086

Didn't get what you're really trying to do but maybe if you try...

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


}

now calling it...

Process p = Process.Start(new ProcessStartInfo() { FileName = "someApp.exe"});

ApiUtils.ShowWindow(p.MainWindowHandle, WindowShowStyle.ShowNormal);

If not sorry, didn't get the question really well.

Upvotes: 0

Related Questions