3

この問題に対する私のアプローチは、いくつかのプログラムでのみ正しいことが判明しました。なぜそれは普遍的ではないのですか?

正常に動作します:

  • Firefox

  • VisualStudioテキストエディター
  • 残念ながら、場合によっては何も起こりません(プログラムの実行前にテキストボックス領域をクリックしても):

  • グーグルクローム
  • メモ帳
  • GetLastErrorは、PostMessageの代わりにSendMessageを使用しても、常に0を返します。私の間違いを指摘していただけますか?

    #include <Windows.h>
    #include <iostream>
    
    int main()
    {
        HWND hCurrentWindow;
    
        Sleep(5000);
    
        hCurrentWindow = GetForegroundWindow();
    
        std::cout<<"GO!!!\n";
    
        for(int i=0; i<500; i++) //simulate 500 keystrokes of 'E'.
            {
                PostMessage(hCurrentWindow,WM_KEYDOWN,0x45,NULL);
                PostMessage(hCurrentWindow,WM_KEYUP,0x45,NULL);
            }
    
        std::cout<<GetLastError()<<std::endl;
    
        system("Pause");
        return 0;
    }
    

    Maximusの推測後の更新

    #include <Windows.h>
    #include <iostream>
    
    int main()
    {
        HWND hCurrentWindow;
    
        Sleep(5000);
    
        hCurrentWindow = GetForegroundWindow();
    
        if(!hCurrentWindow)
            std::cout<<"Failed get set the window handle\n";
    
        std::cout<<"GO!!!\n";
    
        for(int i=0; i<500; i++)
            {
                PostMessage(hCurrentWindow,WM_KEYDOWN,0x45,0x45);
                PostMessage(hCurrentWindow,WM_KEYUP,0x45,0x45);
            }
    
        std::cout<<GetLastError()<<std::endl;
    
        system("Pause");
        return 0;
    }
    

    効果に違いはありません。

    RobKennedyのコメントとHansPassantの回答の後の更新

    #include <Windows.h>
    #include <iostream>
    
    int main()
    {
        HWND hCurrentWindow;
        DWORD procID;
        GUITHREADINFO currentWindowGuiThreadInfo;
    
        Sleep(5000);
    
        hCurrentWindow = GetForegroundWindow();
    
        if(!hCurrentWindow)
            std::cout<<"Failed get main the window handle\n";
    
        GetWindowThreadProcessId(hCurrentWindow,&procID); 
        GetGUIThreadInfo(procID,&currentWindowGuiThreadInfo);               
        hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;
    
        if(!hCurrentWindow)
            std::cout<<"Failed get the child window handle\n";
    
        std::cout<<"GO!!!\n";
    
        for(int i=0; i<500; i++)
            {
                PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
                PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
            }
    
        std::cout<<GetLastError()<<std::endl;
    
        system("Pause");
        return 0;
    }
    

    これで、「透過的な」メッセージが毎回送信されます。GetLastError()は言う:

    ERROR_INVALID_WINDOW_HANDLE

    1400 (0x578)
    
    Invalid window handle.
    

    GetLastError()「修正済み」

    int main()
    {
        HWND hCurrentWindow;
        DWORD procID;
        GUITHREADINFO currentWindowGuiThreadInfo;
    
        Sleep(5000);
    
        hCurrentWindow = GetForegroundWindow();
    
        if(!hCurrentWindow)
            std::cout<<"Failed get main the window handle\n";
    
        GetWindowThreadProcessId(hCurrentWindow,&procID); 
        GetGUIThreadInfo(procID,&currentWindowGuiThreadInfo);               
        hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;
    
        if(!hCurrentWindow)
            std::cout<<"Failed get the child window handle\n";
    
        std::cout<<"GO!!!\n";
    
        for(int i=0; i<500; i++)
            {
    
                if(!PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC))) std::cout<<GetLastError()<<std::endl;
                if(!PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC)))   std::cout<<GetLastError()<<std::endl;
            }
    
    
    
        system("Pause");
        return 0;
    }
    

    ...1400千回出力します。これを除いて、何も変わっていません。

    4

    4 に答える 4

    6

    もちろん、これはメッセージを間違ったウィンドウに投稿したときに発生します。これは確かにメモ帳の場合です。Spy++で見ることができるウィンドウが1つだけではありません。GetForegroundWindow()は、メモ帳のフレームウィンドウであるトップレベルウィンドウを返します。そのフレームウィンドウ内には、ウィンドウであるEDITコントロールがあります。そのウィンドウはメッセージを取得する必要があります。

    そのウィンドウを取得するには、いくつかのフープをジャンプする必要があります。GetFocus()関数は、フォーカスのあるウィンドウを返しますが、ウィンドウを所有するプロセスから呼び出した場合にのみ機能します。これをアウトプロセスで行う場合は、最初にGetWindowThreadProcessId()を呼び出して、フォアグラウンドウィンドウを所有するスレッドのIDを取得する必要があります。次に、GetGUIThreadInfo()を呼び出す必要があります。返されるGUITHREADINFO.hwndFocusは、必要なウィンドウハンドルです。

    これはまだ問題がないわけではなく、プロセスのキーボード状態を制御することはできません。つまり、Shift、Ctrl、Altキー、およびデッドキー(特定のキーボードレイアウトのAlt + Grなど)の状態です。キーを入力するためにWM_CHARを送信することをお勧めします。

    于 2012-08-10T12:21:24.903 に答える
    2

    他に覚えておくべきことは、ターゲットアプリケーションがユーザー入力を同じように処理していると常に想定できるとは限らないということです。たとえば、代わりにGetAsyncKeyState()を使用している可能性があり、投稿されたメッセージはまったく効果がありません。

    于 2012-08-12T02:47:31.500 に答える
    1

    送信しますlParam==NULL。これには、現在機能していないアプリケーションが必要とする可能性のあるキーのスキャンコードが含まれています。

    また、コードはGetForegroundWindow()の戻り値をチェックしません。NULLの可能性があります。

    最後に、キーボードサイクルの重要な部分であるWM_CHARを省略します。

    于 2012-08-09T20:04:05.847 に答える
    1

    KeyDownとKeyUpを送信する間に、場合によっては遅延が必要になります。KeyDownの後に100msの一時停止を追加することで、同様の状況を解決しました

        {
            PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
            Sleep(100);
            PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
        }
    
    于 2014-03-18T17:20:53.360 に答える