使用PostMessage模拟按键仅在某些应用程序中有效吗?

0x6*_*C74 3 c++ winapi keypress

我对这个问题的解决方法仅在几个程序中才是正确的。为什么它不是通用的?

适用于:

  • 火狐浏览器

  • Visual Studio文字编辑器
  • 不幸的是,在某些情况下什么也没发生(即使我在执行程序之前单击了文本框区域):

  • 谷歌浏览器
  • 记事本
  • 即使使用SendMessage而不是PostMessage,GetLastError始终返回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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    效果没有差别。

    Rob Kennedy的评论和Hans Passant的回答后的更新

    #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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    现在,每次都发送“透明”消息。GetLastError()说:

    ERROR_INVALID_WINDOW_HANDLE

    1400 (0x578)
    
    Invalid window handle.
    
    Run Code Online (Sandbox Code Playgroud)

    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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    ...输出1400数千次 除此之外,没有任何改变。

    Han*_*ant 5

    当您将消息发布到错误的窗口时,这当然会发生。记事本肯定是这种情况。它不只有一个窗口,您可以在Spy ++中看到。GetForegroundWindow()返回一个顶级窗口,即记事本的框架窗口。在该框架窗口内部有一个窗口,一个EDIT控件。该窗口需要获取消息。

    您需要跳过几个步骤才能获得该窗口,GetFocus()函数返回具有焦点的窗口,但是仅当您从拥有该窗口的进程中调用该窗口时,该函数才起作用。当您在进程外执行此操作时,必须首先调用GetWindowThreadProcessId()以获取拥有前台窗口的线程的ID。然后,您必须调用GetGUIThreadInfo(),它返回的GUITHREADINFO.hwndFocus是您需要的窗口句柄。

    这仍然不是没有问题,您无法控制进程的键盘状态。换句话说,Shift,Ctrl和Alt键以及任何死键(例如某些键盘布局上的Alt + Gr)的状态。支持发送WM_CHAR以键入密钥。