2009-12-28 29 views
9

Tôi muốn làm việc với một plugin cho Keepass, trình quản lý mật khẩu nguồn mở. Ngay bây giờ, Keepass hiện đang phát hiện mật khẩu để sao chép/dán cho bạn dựa trên tiêu đề cửa sổ. Điều này ngăn Keepass phát hiện mật khẩu hiện tại bạn cần cho các ứng dụng không chủ động cập nhật tiêu đề cửa sổ dựa trên trang web hiện tại (ví dụ: Chrome).Làm cách nào để nhận được chức năng tương tự như Spy ++ trong ứng dụng C# của tôi?

Làm cách nào tôi có thể xem qua các yếu tố cửa sổ quy trình khác (nút, nhãn, hộp văn bản) tương tự như cách hoạt động của Spy ++? Khi bạn chạy Spy ++, bạn có thể di chuột qua các cửa sổ chương trình khác và nhận tất cả các loại thông tin về các thuộc tính khác nhau liên quan đến các điều khiển khác nhau (nhãn, hộp văn bản, v.v.). Lý tưởng nhất, tôi muốn plugin Keepass của tôi để tăng cường phát hiện cửa sổ hiện tại bằng cách đi qua các phần tử của cửa sổ đang hoạt động trong một nỗ lực để tìm một tài khoản phù hợp để sao chép/dán mật khẩu.

Làm cách nào tôi có thể đi bộ các phần tử cửa sổ quy trình khác và có thể truy xuất giá trị nhãn và hộp văn bản bằng C#?

+1

Thú vị questin, tôi sẽ không ngạc nhiên mặc dù nếu nó bật ra rằng bạn sẽ phải PInvoke để WinAPI để đạt được điều đó. –

Trả lời

22

Tôi đang trả lời các câu hỏi tương tự như thế này tại đây: How can I detect if a thread has windows handles?. Giống như trạng thái, ý tưởng chính là liệt kê các cửa sổ quy trình và cửa sổ con của chúng bằng cách sử dụng các lệnh gọi EnumWindowsEnumChildWindows API để nhận xử lý cửa sổ và sau đó gọi GetWindowText hoặc SendDlgItemMessage bằng WM_GETTEXT để lấy văn bản cửa sổ. Tôi đã sửa đổi mã để làm một ví dụ mà nên được làm những gì bạn cần (xin lỗi nó là một chút dài :). Nó lặp đi lặp lại thông qua các quy trình và cửa sổ của chúng và đổ văn bản cửa sổ vào giao diện điều khiển.

static void Main(string[] args) 
{ 
    foreach (Process procesInfo in Process.GetProcesses()) 
    { 
     Console.WriteLine("process {0} {1:x}", procesInfo.ProcessName, procesInfo.Id); 
     foreach (ProcessThread threadInfo in procesInfo.Threads) 
     { 
      // uncomment to dump thread handles 
      //Console.WriteLine("\tthread {0:x}", threadInfo.Id); 
      IntPtr[] windows = GetWindowHandlesForThread(threadInfo.Id); 
      if (windows != null && windows.Length > 0) 
       foreach (IntPtr hWnd in windows) 
        Console.WriteLine("\twindow {0:x} text:{1} caption:{2}", 
         hWnd.ToInt32(), GetText(hWnd), GetEditText(hWnd)); 
     } 
    } 
    Console.ReadLine(); 
} 

private static IntPtr[] GetWindowHandlesForThread(int threadHandle) 
{ 
    _results.Clear(); 
    EnumWindows(WindowEnum, threadHandle); 
    return _results.ToArray(); 
} 

// enum windows 

private delegate int EnumWindowsProc(IntPtr hwnd, int lParam); 

[DllImport("user32.Dll")] 
private static extern int EnumWindows(EnumWindowsProc x, int y); 
[DllImport("user32")] 
private static extern bool EnumChildWindows(IntPtr window, EnumWindowsProc callback, int lParam); 
[DllImport("user32.dll")] 
public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId); 

private static List<IntPtr> _results = new List<IntPtr>(); 

private static int WindowEnum(IntPtr hWnd, int lParam) 
{ 
    int processID = 0; 
    int threadID = GetWindowThreadProcessId(hWnd, out processID); 
    if (threadID == lParam) 
    { 
     _results.Add(hWnd); 
     EnumChildWindows(hWnd, WindowEnum, threadID); 
    } 
    return 1; 
} 

// get window text 

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); 
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
static extern int GetWindowTextLength(IntPtr hWnd); 

private static string GetText(IntPtr hWnd) 
{ 
    int length = GetWindowTextLength(hWnd); 
    StringBuilder sb = new StringBuilder(length + 1); 
    GetWindowText(hWnd, sb, sb.Capacity); 
    return sb.ToString(); 
} 

// get richedit text 

public const int GWL_ID = -12; 
public const int WM_GETTEXT = 0x000D; 

[DllImport("User32.dll")] 
public static extern int GetWindowLong(IntPtr hWnd, int index); 
[DllImport("User32.dll")] 
public static extern IntPtr SendDlgItemMessage(IntPtr hWnd, int IDDlgItem, int uMsg, int nMaxCount, StringBuilder lpString); 
[DllImport("User32.dll")] 
public static extern IntPtr GetParent(IntPtr hWnd); 

private static StringBuilder GetEditText(IntPtr hWnd) 
{ 
    Int32 dwID = GetWindowLong(hWnd, GWL_ID); 
    IntPtr hWndParent = GetParent(hWnd); 
    StringBuilder title = new StringBuilder(128); 
    SendDlgItemMessage(hWndParent, dwID, WM_GETTEXT, 128, title); 
    return title; 
} 

hy vọng điều này giúp, coi

+1

EnumChildWindows đã đệ quy, vì vậy bạn làm đệ quy kép ở đây; xem [Điều mới mẻ mới về EnumChildWindows] (http://blogs.msdn.com/b/oldnewthing/archive/2007/01/16/1478717.aspx) –

+1

Tôi nhận thấy rằng trên một vài câu trả lời, mọi người nói để gọi EnumChildWindows đệ quy . ĐỪNG LÀM. Đọc tài liệu MSDN cho nó - nó đã được đệ quy, nên đã được aptly đặt tên EnumDescendants. –

+0

Làm thế nào chúng ta có thể tránh một vòng lặp vô hạn ở đây xảy ra trên máy của tôi. Nó sẽ hợp lý tấn công sau khi khoan qua cửa sổ trẻ em. –

3

Bạn có thể sử dụng EnumWindows để tìm mọi cửa sổ Chrome cấp cao nhất và sau đó gọi EnumChildWindows đệ quy(xem bình luận Jeroen Wiert Pluimers') để có được mọi trẻ em của cửa sổ chính. Ngoài ra, khi bạn có cửa sổ Chrome chính, bạn có thể sử dụng GetWindow để điều hướng cây theo cách thủ công vì bạn có thể biết những gì bạn đang tìm kiếm (bộ sưu tập trẻ em của trẻ thứ 3 hoặc thứ gì đó tương tự).

Khi bạn tìm thấy cửa sổ của mình, bạn có thể sử dụng SendMessage với thông số WM_GETTEXT để đọc nhãn của cửa sổ.

+0

@Blindy, cảm ơn bạn đã thông tin! Tôi đang tìm cách thực hiện điều này với bất kỳ cửa sổ đang hoạt động nào, không chỉ Chrome.Một khi tôi có tay cầm vào cửa sổ/cửa sổ con, làm cách nào để điều hướng qua các phần tử cửa sổ đó? – mmcdole

+0

Đây là tất cả các cuộc gọi Windows API nguyên gốc và không được quản lý .NET Framework gọi để chúng yêu cầu P/Gọi từ CLR. –

+0

@DrJokepu, Aye. Tôi nghĩ rằng tôi phải làm một số phép thuật P/Invoke. – mmcdole

1

Đối với chức năng trỏ đến cửa sổ. Bạn cần phải SetCapture() để bạn nhận được thông báo bằng chuột nằm ngoài cửa sổ của mình. Sau đó sử dụng WindowFromPoint() để chuyển đổi vị trí chuột thành Cửa sổ. Bạn sẽ cần phải chuyển đổi vị trí moust từ tọa độ của khách hàng thành các tọa độ cửa sổ đầu tiên.

Nếu bạn thử gọi SetCapture() ở bất cứ nơi nào nhưng trên một thông báo nhấp chuột, có thể bạn sẽ bị bỏ qua. Đây là lý do mà Spy ++ làm cho bạn nhấp vào một biểu tượng và kéo và thả nó vào cửa sổ bạn muốn trỏ đến.

+0

Những gì tôi đang cố gắng chỉ đơn giản là lặp qua một cửa sổ các yếu tố không có tương tác chuột. Khi tôi gọi EnumChildWindows, làm thế nào tôi có thể nhận được văn bản của bất kỳ phần tử nào thuộc về cửa sổ con đó? – mmcdole

+0

Gửi tin nhắn cửa sổ. WM_GETTEXT, v.v. Nếu điều đó không đủ tốt, bạn cần xác định ý nghĩa của từ 'các yếu tố'? –

+0

@ John Knoeller, tất cả nhãn văn bản, hộp văn bản và nút. – mmcdole

3

Hãy xem bài viết này here chứa thông tin về Spy được quản lý và lý do tác giả viết công cụ này.

+0

Hãy nhớ rằng ứng dụng bạn đang đề cập đến chỉ hoạt động cho các ứng dụng * được quản lý *, không phải những ứng dụng không được quản lý giống như hầu hết các trình duyệt. – Blindy

0

Bạn có thể sử dụng HWndSpy. Mã nguồn là here.

enter image description here

Các vấn đề liên quan