10

オープンソースのパスワード マネージャーであるKeepassのプラグインに興味があります。現在、Keepassは現在、ウィンドウのタイトルに基づいて、コピー/貼り付けするパスワードを検出しています。これにより、Keepass は、現在のサイト (Chrome など) に基づいてウィンドウ タイトルを積極的に更新しないアプリに必要な現在のパスワードを検出できなくなります。

Spy++ の動作と同様に、別のプロセス ウィンドウ要素 (ボタン、ラベル、テキスト ボックス) をどのように操作できますか? Spy++ を実行すると、他のプログラム ウィンドウにカーソルを合わせると、さまざまなコントロール (ラベル、テキスト ボックスなど) に関するさまざまなプロパティに関するあらゆる種類の情報を取得できます。理想的には、パスワードをコピー/貼り付けする一致するアカウントを見つけるために、アクティブなウィンドウの要素をウォークスルーすることで、Keepass プラグインが現在のウィンドウの検出を強化するようにしたいと考えています。

C# を使用して、他のプロセス ウィンドウ要素をウォークし、ラベルとテキスト ボックスの値を取得するにはどうすればよいですか?

4

5 に答える 5

25

私はここでこのような同様の質問に答えています:スレッドにウィンドウハンドルがあるかどうかをどのように検出できますか?それが述べているように、主なアイデアは、ウィンドウハンドルを取得するためにEnumWindowsおよびEnumChildWindows API呼び出しを使用してプロセスウィンドウとその子ウィンドウを列挙し、次にWM_GETTEXTを指定してGetWindowTextまたはSendDlgItemMessageを呼び出してウィンドウテキストを取得することです。私はあなたが必要なことをしているはずの例を作るためにコードを修正しました(すみません、それは少し長いです:)。プロセスとそのウィンドウを反復処理し、ウィンドウテキストをコンソールにダンプします。

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

これがお役に立てば幸いです

于 2009-12-28T02:07:37.517 に答える
3

マネージドスパイに関する情報と、作成者がツールを作成した理由が記載されているこの記事をご覧ください。

于 2009-12-28T01:42:52.777 に答える
3

EnumWindowsを使用してすべての最上位の Chrome ウィンドウを検索し、EnumChildWindowsを 再帰的に呼び出して (Jeroen Wiert Pluimers のコメントを参照)、メイン ウィンドウのすべての子を取得できます。または、Chrome のメイン ウィンドウが表示されたら、GetWindowを使用して手動でツリーをナビゲートできます。探しているもの (3 番目の子の子コレクションなど) はおそらくわかっているからです。

ウィンドウが見つかったら、SendMessageを WM_GETTEXT パラメータと共に使用して、ウィンドウのラベルを読み取ることができます。

于 2009-12-28T01:07:02.033 に答える
2

HWndSpy を使用できます。ソースコードはこちら.

ここに画像の説明を入力

于 2016-01-12T06:20:26.473 に答える
1

ウィンドウを指す機能用。SetCapture()ウィンドウの外にあるマウス メッセージを取得する必要があります。次にWindowFromPoint()、マウスの位置をウィンドウに変換するために使用します。最初にマウス位置をクライアント座標からウィンドウ座標に変換する必要があります。

マウス クリック メッセージ以外の場所で呼び出しを試みると、SetCapture()おそらく無視されます。これが、Spy++ がアイコンをクリックして、ポイントしたいウィンドウにドラッグ アンド ドロップする理由です。

于 2009-12-28T01:28:53.617 に答える