1

ここに画像の説明を入力

問題

これは、バックグラウンドでキーストロークを送信する私の機能です。

class SendMessage
{

[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

public static void sendKeystroke(string appName)
{
    const int WM_KEYDOWN = 0x100; 
    IntPtr hWnd = FindWindow(null, appName);
    IntPtr editx = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
    PostMessage(editx, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);  
}

}

このコードはnotepad、たとえば let appName = "notepad" の場合に正常に機能します。

でも、他のアプリではなんとかできるので、LINEアプリで練習中です。

写真でわかるようにlpszClass variable= "edit" (小さな赤い丸) はメモ帳用です。

LINEアプリで検索する必要があるので、WinSpy++それらのクラス名を取得するために使用します。

そのクラス名は「ATL:00B53BE8」(大きな赤い丸) で、メッセージを入力できることがわかりました。

WinSpy++ で入力すると、Line テキストボックス (青い丸) に表示されます。

結論は

キャプチャクラス名を「編集」に置き換えようとしましたが、希望はありません。

キャプチャ クラス名が使用できない理由がわかりません。ヘルプまたはヒントを教えてください。

システムアプリの階層が違うのかどうかはわかりません(ピンクのやつ)

FindWindowEx のどのパラメーターがそれほど意味があるのか​​ わかりません。

私の最終的な目標は、他のアプリケーションに集中することなく、キーストロークを他のアプリケーションに送信することです。

4

2 に答える 2

1

WM_KEYDOWNフォーカスを持たないアプリケーションに送信されたメッセージが期待どおりの効果を持つことは期待できません。単にサポートされていません。メッセージの受信はWM_KEYDOWN、Windows の規則により、アプリケーションがフォーカスを持っていることを意味します。フォーカスされたアプリケーションのみがキーボード入力を取得できます。

したがって、あなたが試みていることは特定のケースではうまくいくかもしれませんが、うまくいくとは限りません。アプリケーションは、キーボード入力を受信して​​いる場合、フォーカスがあると非常に合理的に想定する場合があります。

メモ帳で「機能する」場合、それはメモ帳が非常に単純なアプリケーションであるためです。これは、メニュー バーを備えた単なる編集コントロールです。メッセージの処理は、WM_KEYDOWNメッセージ パラメーターによって示されるキーによって表される文字をエディット コントロールに追加するだけの可能性があります。他のほとんどのアプリケーションはより複雑です。また、メモ帳でさえ、すべての場合に動作することが保証されているわけではありません。たとえば、そのウィンドウが最小化されている場合。このサイトや Interwebz の他の場所でも、このような問題が多数報告されています。

簡単に言うと、送信WM_KEYDOWNとその仲間は、Windows でキーボード入力をシミュレートする方法ではありません。それには2つの基本的な方法があります。SendInput1 つ目は、関数を使用することです。WH_JOURNALPLAYBACKもう1つはフックを取り付けることです。これらのタックは両方とも、SendKeys.NET のクラスの実装のさまざまなバージョンによってさまざまに採用されてきました。どちらも合成された入力をフォーカスされたウィンドウに送信します。これは、Windows では、それがすべての入力を受け取るウィンドウだからです。

これが機能する場合は、絶対に別の方法を見つける必要があります。コメントの中で、David は、この目的のために設計されたツールであるUI Automationを使用することを提案しています。.NET Framework によって便利にラップされます。なぜあなたがこのアドバイスに抵抗しているのかは不明です。UI オートメーションを使用すると、入れ子になったツリー構造を使用して、アプリケーション内のウィンドウの階層を簡単に移動できます。このツリーは、プロセス内のすべてのウィンドウ ハンドルから自動的に構築されます。これにより、操作したいコントロールを簡単に見つけることができます。次に、適切な制御パターンを取得し、必要なアクションを実行します。

于 2014-09-08T07:35:00.323 に答える
0

とのディスカッションからDavid Herffernan

「親子階層をたどるには複数の呼び出しが必要です」

これで、コードを機能させることができます..しかし、これは正しい方法ではないようです(ハッキング)

しかし、参考のためにこの質問に答えたいと思います

重要なのは、それを使用するFindWindowExことDavid Herffernanです。

これの代わりに..

public static void sendKeystroke(string appName)
{
    const int WM_KEYDOWN = 0x100; 
    IntPtr hWnd = FindWindow(null, appName);
    IntPtr editx = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
    PostMessage(editx, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);  
}

私はこれに編集します..

public static void sendKeystroke(string appName)
{
    const int WM_KEYDOWN = 0x100; 
    IntPtr hWnd = FindWindow(null, appName);
    IntPtr editx1 = FindWindowEx(hWnd, IntPtr.Zero, "SkinScrollWnd", null);
    IntPtr editx2 = FindWindowEx(editx1, IntPtr.Zero, "SkinScrollMidWnd", null);
    IntPtr editx3 = FindWindowEx(editx2, IntPtr.Zero, "ATL:00B53BE8", null);
    PostMessage(editx3, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);  
}
于 2014-09-08T07:48:38.473 に答える