7

次のいずれかを実行しようとしています 1.目的のプログラムを開き、プログラムでキーを押します 2.プログラムの開いているウィンドウを見つけて、プログラムでキーを押します(どちらでも構いません)

SendKeys.SendWait()、PostMessage()、および SendMessage() の多数の実装を試みましたが、失敗しました。以下は私のコードスニペットです

    //included all these for attempts 
    [DllImport("User32.dll")] 
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);  

    [DllImport("User32.dll")] 
    static extern int SetForegroundWindow(IntPtr hWnd);

    [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
    static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    [DllImport("user32.dll")]
    static extern byte VkKeyScan(char ch);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

ウィンドウのハンドル、sendmessage/postmessage/sendkeys で使用される変数を取得する

IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly
//IntPtr ptrOBS = FindWindow(null, "Open Broadcaster Software v0.472b");
SetForegroundWindow(ptrOBS);
const UInt32 WM_CHAR = 0x0102;
const uint WM_KEYDOWN = 0x100;
const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
const int VK_S = 0x53;

SendMessage 試行:

SendMessage(ptrOBS, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);//tried both WM_CHAR and WM_KEYDOWN

PostMessage 試行:

string message = "rs";
bool sent = PostMessage(ptrOBS, WM_KEYDOWN, VkKeyScan(message[0]), 0);

SendKeys 試行:

SendKeys.SendWait("{r}");

親ウィンドウ(アプリケーション)と子ウィンドウ(送信しようとしているキープレスによってトリガーされるボタン)で SetFocus を試しました:

static void SetFocus(IntPtr hwndTarget, string childClassName)
    {
        // hwndTarget is the other app's main window 
        // ...
        IntPtr targetThreadID = GetWindowThreadProcessId(hwndTarget, IntPtr.Zero); //target thread id
        IntPtr myThreadID = GetCurrentThread(); // calling thread id, our thread id
        try
        {
            bool lRet = AttachThreadInput(myThreadID, targetThreadID, -1); // attach current thread id to target window

            // if it's not already in the foreground...
            lRet = BringWindowToTop(hwndTarget);
            SetForegroundWindow(hwndTarget);

            // if you know the child win class name do something like this (enumerate windows using Win API again)...
            IntPtr hwndChild = (IntPtr)1183492;//(IntPtr)EnumAllWindows(hwndTarget, childClassName).FirstOrDefault();

            if (hwndChild == IntPtr.Zero)
            {
                // or use keyboard etc. to focus, i.e. send keys/input...
                // SendInput (...);
                return;
            }

            // you can use also the edit control's hwnd or some child window (of target) here
            SetFocus(hwndChild); // hwndTarget);
            SendKeys.SendWait("{r}");
        }
        finally
        {
            SendKeys.SendWait("{r}");
            bool lRet = AttachThreadInput(myThreadID, targetThreadID, 0); //detach from foreground window
            SendKeys.SendWait("{r}");
        }
    }

NSGaga の場合:

    string windowName = "Open Broadcaster Software v0.472b";
IntPtr outerPtr = FindWindow(null, windowName);
IntPtr ptrOBS = (IntPtr)527814;//button that im trying to trigger keypress on
SetForegroundWindow(outerPtr);
SetForegroundWindow(ptrOBS);
SetFocus(outerPtr, "OBSWindowClass");//SetFocus(ptrOBS, "Button");
const UInt32 WM_CHAR = 0x0102;
const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
const int VK_S = 0x53;

//SetForegroundWindow(ptrOBS);
System.Threading.Thread.Sleep(3000);
SendKeys.SendWait("{r}");
SendMessage(outerPtr, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);
PostMessage(outerPtr, WM_KEYDOWN, VkKeyScan('r'), 0);
4

2 に答える 2

6

SendMessagePostMessageをキーボード入力の合成に確実に使用することはできません。それらはこのために設計されていません。これらのメッセージ ( WM_CHARWM_KEYDOWNなど) は、キーボード入力が受信、処理され、適切な受信者に転送されたときに、下位レベルのサブシステムによって生成される通知です。これらのメッセージを自分で送信または投稿することは、誰かにいたずら電話をかけるようなものです。

SendKeys(キーボード入力を合成するために明示的に設計された関数を含む、他のすべての入力シンセサイザー メソッドと同様SendInputに、少なくとも一部の実装ではSendKeys、内部で実際に使用されるものです) は、キーボード入力を受け取りたいウィンドウにフォーカスがある場合にのみ機能します。Windows では、フォーカスされた (アクティブな) ウィンドウのみが入力イベントを受け取ります。

これSendKeysを機能させるつもりなら (それまたは P/Invoking とそれに関連するすべての構造体のいずれか)、おそらくこれが進むべき道ですが、受信者ウィンドウにフォーカスがなければならないSendInputという警告を尊重する必要があります。そうでなければ、何も得られません。

SetForegroundWindowサンプルコードから、この前提条件を満たすために関数を使用しようとしているように見えます。残念ながら、無効な値を渡しており、この間違いを警告するエラー チェックを行っていません。具体的には、次のコードは間違っています。

IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly
SetForegroundWindow(ptrOBS); // WRONG, ptrOBS is not a window handle

ptrOBS正しく初期化されていると信じていても、それはprocessの有効なハンドルになります。これは、 windowの有効なハンドルとは大きく異なります。明らかな名目上の違いは別として、プロセスは複数のウィンドウを持つことができ、1 つのウィンドウだけがフォーカスを持つことができます (つまり、「フォアグラウンド」になります)。

を呼び出す前に、特定のウィンドウへのハンドルを取得する必要がありますSetForegroundWindow。プロセスが複数のウィンドウを持つ可能性があることがわかっている場合、これは注意が必要です。必要なウィンドウを決定するための信頼できる方法が必要です。多くの人は、ウィンドウの名前を文字列としてハードコーディングすることでこれを実現しています。これは、ターゲット アプリが再コンパイルされ、この実装の詳細が変更されるまでうまく機能します。私が考えることができる唯一の防弾方法は、ユーザーにターゲット ウィンドウとコードをクリックして、現在マウス ポインターの下にあるウィンドウのハンドルを取得させることです。

SetForegroundWindowそしてもちろん、これはすべて、リンクされた SDK ドキュメントの「備考」セクションに列挙されている の使用に関する制限を順守していることを前提としています。

于 2013-03-21T00:02:40.797 に答える
3

それを機能させるには、多くの試行錯誤があります。これは
、以前に投稿したコードの一部です。試してみたいと思うかもしれません(さらに情報が添付されています)...

SetFocus を特定のコントロールにピンボークする

最初に (前述のメカニズムを使用して) フォーカスを設定してから、SendKeysまたはを使用してみてくださいSendInput

ここにいくつかの詳細なコードがありSendInputます...

Microsoft Word を含む他のアプリケーションに文字列を送信する方法

于 2013-03-21T00:44:38.773 に答える