3

この問題があります: 特定のアプリケーションの mainWindow へのハンドラーがあり、そのアプリケーションでキープレスをシミュレートしたい...

これを行うために sendMessage/postMessage API 呼び出しを使用しています。.Net SendKeys 関数または win32 API の keybd_event を使用しない理由は、それらがグローバル レベルでキープレスをシミュレートするためです。私の場合、ターゲット アプリケーションはトップ アクティブなアプリケーションではありません (他のアプリケーションがより高い z レベルで実行されている可能性があるため、ターゲット アプリをカバーしています)。

sendMessage と postMessage の問題は、キーを押したい正確な子ウィンドウのハンドラーを渡す必要があることです。たとえば、メモ帳では、mainWindow のハンドラーにキーを送信しても何も起こらず、基本的に書き込み可能な白いキャンバスで構成される子ウィンドウのハンドラーにキーを送信する必要があります。

アクティブな子ウィンドウへのハンドラーを取得することが問題です。最初は、最もアクティブな子ウィンドウを返す GetTopWindow または GetWindow(GW_CHILD) API 呼び出しを使用していました。私がやっていたことは、childWindows がなくなるまで、GetWindow(GW_CHILD) を呼び出し続けることでした。これは、メモ帳やペイントなどの一部のアプリケーションでは問題なく機能します。ただし、場合によっては (たとえば、firefox など)、動作しないことがあります。その理由は、親ウィンドウには Firefox 領域全体があり、その子ウィンドウには開かれた Web ページ (Google など) があるためです。そのため、mainWindow の最もアクティブな子ウィンドウを要求すると、Web ページ領域に対応する唯一の子ウィンドウが返されます。アクティブなウィンドウがそのウィンドウである場合にのみ機能します (ユーザーが特定のページのテキストボックスに何かを書いている場合など)。

次のコードを使用して、GetGUIThreadInfo API呼び出しを使用して、実際にこれを行う方法を見つけました。

    // get thread of the main window handle of the process
    var threadId = GetWindowThreadProcessId(firefox.MainWindowHandle, IntPtr.Zero);

    // get gui info
    var info = new GUITHREADINFO();
    info.cbSize = (uint)Marshal.SizeOf(info);
    if (!GetGUIThreadInfo(threadId, out info))
        throw new Win32Exception();

    // send the letter W to the active window
    PostMessage(info.hwndActive, WM_KEYDOWN, (IntPtr)Keys.W, IntPtr.Zero);

アドレスバーがアクティブな場合、「W」​​文字をアドレスバーに送信します。Google の検索テキスト ボックスがアクティブな場合、"W" の文字が送信されます... パーフェクト! ただし、このメソッドは単純な理由で使用できません。ターゲット アプリケーションがオペレーティング システムのアクティブ ウィンドウでない場合、ThreadInfo 構造体は空になります。たとえば、firefox をターゲットにしている場合、firefox がアクティブな場合 (最上位のアプリケーション、フォーカスされた/アクティブなアプリケーション) は機能しますが、たとえば、メモ帳が firefox の上にある場合は機能しません。アクティブなウィンドウ ハンドラを取得できません。

setForegroundWindow API 呼び出しを使用してターゲット アプリケーションをアクティブにし、アクティブな子ウィンドウのハンドラーをキャプチャすることでこれを解決できることはわかっていますが、ターゲット アプリをフォアグラウンドに移動する必要はありませんでした。

また、AttachThreadInput() や GetFocus() API 呼び出しなどの他の手法も試しましたが、これも機能しますが、同じ問題があります。ターゲット アプリケーションがアクティブな Windows アプリケーションでない場合、機能しません。

したがって、基本的には、アプリケーションが最上位のアクティブなアプリケーションでなくても、アプリケーションのアクティブな子ウィンドウにハンドラーを取得する方法を見つける必要があります。

何か案は?ありがとう

4

2 に答える 2

1

EnumChildWindows関数を確認することをお勧めします。

于 2009-05-11T14:09:32.903 に答える
0

他のすべてが失敗した場合は、別のアイデアがあります。WH_CBT または WH_CALLWNDPROC フックを使用して、ターゲット スレッドのどの子ウィンドウが最後にフォーカスされたかを監視することを検討してください。

CBT フック (WH_CBT) をインストールし、HCBT_SETFOCUS 通知をリッスンします。または、WH_CALLWNDPROC フックを使用して、WM_SETFOCUS メッセージをリッスンします。

フック プロシージャで多くのことをしないでください。そうしないと、システム リソースを浪費してしまいます。必要な情報を保存し、カスタム メッセージを投稿して後で処理するだけです。

于 2009-05-14T05:21:51.497 に答える