2013-04-24 158 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