2013-04-24 229 views
2

我正在构建一个应用程序,它将获得所有控件都进入应用程序winform运行。首先,我可以注入DLL到应用程序winform运行并获取应用程序winform的句柄正在运行。在我把所有的孩子窗口都变成了应用之后。接下来,我想通过FindWindowEx将所有控件放到子窗口中。但我不能通过FindWindowEx获取所有控件

这里是代码:

static ArrayList GetAllChildrenWindowHandles(IntPtr hParent, int maxCount) 
    { 
     ArrayList result = new ArrayList(); 
     int ct = 0; 
     IntPtr prevChild = IntPtr.Zero; 
     IntPtr currChild = IntPtr.Zero; 
     while (true && ct < maxCount) 
     { 
      currChild = FindWindowEx(hParent, prevChild, null, null); 
      if (currChild == IntPtr.Zero) 
      { 
       int errorCode = Marshal.GetLastWin32Error(); 
       break; 
      } 
      result.Add(currChild); 
      prevChild = currChild; 
      ++ct; 
     } 
     return result; 
    } 

我得到的子窗口的句柄,并使用它的父。但是我无法通过FindWindowEx将所有控件都放到子窗口中。 对不起,我的英语

+1

如果您要查找某个特定窗口的所有子项,则需要['EnumChildWindows'](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633494.aspx) 。 – 2013-04-24 15:52:18

+0

逻辑结构是一棵树。最容易遍历一个递归函数。但是,这肯定也意味着ArrayList不是存储结果的适当数据结构。 – 2013-04-24 19:43:10

+0

“逻辑结构是一棵树,最容易遍历一个递归函数,但这肯定也意味着一个ArrayList不是存储结果的正确数据结构”我想也是,但我不知道这是怎么做到的?你知道吗?感谢:) – user2208401 2013-04-25 01:11:36

回答

4

您可以使用下面的代码。把它放到某个地方的助手类,例如使用这样的......

var hwndChild = EnumAllWindows(hwndTarget, childClassName).FirstOrDefault(); 

,如果你愿意,你可以“丢失” class检查 - 但是通常你在检查一个具体的目标。

你也可以想查这个职位,我发了一阵走了 - 这是使用 此方法设置焦点远程窗口(以及那些场景是 相当普遍,你会打的障碍越快或更晚)。
Pinvoke SetFocus to a particular control

public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam); 

[DllImport("user32.Dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam); 

[DllImport("user32.dll", CharSet = CharSet.Auto)] 
static public extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount); 

private static bool EnumWindow(IntPtr handle, IntPtr pointer) 
{ 
    GCHandle gch = GCHandle.FromIntPtr(pointer); 
    List<IntPtr> list = gch.Target as List<IntPtr>; 
    if (list == null) 
     throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>"); 
    list.Add(handle); 
    return true; 
} 

public static List<IntPtr> GetChildWindows(IntPtr parent) 
{ 
    List<IntPtr> result = new List<IntPtr>(); 
    GCHandle listHandle = GCHandle.Alloc(result); 
    try 
    { 
     Win32Callback childProc = new Win32Callback(EnumWindow); 
     EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle)); 
    } 
    finally 
    { 
     if (listHandle.IsAllocated) 
      listHandle.Free(); 
    } 
    return result; 
} 

public static string GetWinClass(IntPtr hwnd) 
{ 
    if (hwnd == IntPtr.Zero) 
     return null; 
    StringBuilder classname = new StringBuilder(100); 
    IntPtr result = GetClassName(hwnd, classname, classname.Capacity); 
    if (result != IntPtr.Zero) 
     return classname.ToString(); 
    return null; 
} 

public static IEnumerable<IntPtr> EnumAllWindows(IntPtr hwnd, string childClassName) 
{ 
    List<IntPtr> children = GetChildWindows(hwnd); 
    if (children == null) 
     yield break; 
    foreach (IntPtr child in children) 
    { 
     if (GetWinClass(child) == childClassName) 
      yield return child; 
     foreach (var childchild in EnumAllWindows(child, childClassName)) 
      yield return childchild; 
    } 
} 
+0

这不是工作,我可以将所有控件都放入应用程序winform运行的子窗口中。我只能得到子窗口,但不能将所有控件都放到子窗口中。 – user2208401 2013-04-25 01:13:21

+0

工作 - 试试Spy ++(或[这](http://mwinapi.sourceforge.net/))测试 - 看到这完全相同的代码[这里](http://stackoverflow.com/questions/7014190/why- is-enumchildwindows-skipping-children)(并确保你加载所有,给它时间)。并尝试从'SetFocus'链接的建议(附加到'线程')。如果你的控件是“非标准”(非窗口),它将不起作用。并删除'.FirstOrDefault()'当然:) – NSGaga 2013-04-25 01:50:42

+0

我得到错误“无法找到类型或命名空间名称'Win32Callback'(你是否缺少使用指令或程序集引用?)” – Ashish 2014-03-18 06:20:01

0

尝试间谍++,看你正试图枚举控件是Windows或没有。 如果它们不是Windows,则无法使用此API枚举它们。

+2

Spy ++显示的控件怎么可能不是一个窗口? – 2013-04-25 11:11:26

+0

@WernerHenze:这是使用Spy ++的一点。问题中的代码可能会失败,因为控件不是窗口,但在这种情况下,Spy ++会以相同的方式失败。即我们使用Spy ++来建立正确的行为。 – MSalters 2013-04-25 12:27:31

+0

@MSalters:所以你正在谈论一个父窗口,它在客户区绘制一些东西,看起来像一个控件,并处理鼠标点击,所以它就像一个控件,但事实上它不是一个真正的窗口,它只是从用户角度看起来像一个!? – 2013-04-25 12:57:58