3

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

适用于:

  • 火狐

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

  • 谷歌浏览器
  • 记事本
  • GetLastError 总是返回 0,即使使用 SendMessage 而不是 PostMessage。你能指出我的错误吗?

    #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;
    }
    

    马克西姆斯建议后更新

    #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;
    }
    

    效果没有区别。

    在 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;
    }
    

    现在,每次都发送“透明”消息。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++ 看到。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 之后添加 100 毫秒的暂停解决了我的类似情况

        {
            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 回答