我正在尝试使用其句柄(即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++
然后使用P \ invoke使用<windows.h>
可以工作。
如果我不能,是否有其他方式来访问窗口(即不使用句柄)?
=================== 的修改
我想处理整个窗口对象及其自己的控件
答案 0 :(得分:2)
NativeWindow.FromHandle
的文档解释了为什么该函数始终为您返回null
:
句柄必须已经被另一个NativeWindow拥有 当前进程;否则,返回null。
但是您定位的窗口处于不同的过程中。所以你根本不能在这里使用NativeWindow
。您必须将窗口句柄作为IntPtr
。
在您的编辑中,您声明:
我想处理整个窗口对象及其自己的控件
没有改变。您无法使用NativeWindow
。您将不得不处理原始的Win32 API。
答案 1 :(得分: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();
}
}
}
答案 2 :(得分:1)
您想要访问什么?您可以在Windows中获取Windows的标题和文本。但是你无法获得另一个应用程序的NativeWindow对象。您需要使用Windows API与其他应用程序进行交互。我曾经在另一个应用程序中劫持了一个对象,但是通过了解它的类并发现了一个黑客来找到它的Idispatch指针,你可以查看它here。下面是如何获取前景窗口的标题,希望这有帮助。
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钩子,在我的示例here中举例说明。
答案 3 :(得分: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);
如果不对不起,那么问题就不会很好。