Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
298 views
in Technique[技术] by (71.8m points)

c++ - Simulating key press with PostMessage only works in some applications?

My approach to this problem turned out to be correct only in several programs. Why it isn't universal?

Works fine on:

Firefox
Visual Studio Text Editor

Unfortunately, in some cases nothing happens(even if I click into a textbox area before execution of my program):

Google Chrome Notepad

GetLastError returns always 0, even using SendMessage instead of PostMessage.Could you point out my mistake?

#include <Windows.h>
#include <iostream>

int main()
{
    HWND hCurrentWindow;

    Sleep(5000);

    hCurrentWindow = GetForegroundWindow();

    std::cout<<"GO!!!
";

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

UPDATE after Maximus sugestion

#include <Windows.h>
#include <iostream>

int main()
{
    HWND hCurrentWindow;

    Sleep(5000);

    hCurrentWindow = GetForegroundWindow();

    if(!hCurrentWindow)
        std::cout<<"Failed get set the window handle
";

    std::cout<<"GO!!!
";

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

There is no difference in effect.

UPDATE after Rob Kennedy's comment and Hans Passant's answer

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

    GetWindowThreadProcessId(hCurrentWindow,&procID); 
    GetGUIThreadInfo(procID,&currentWindowGuiThreadInfo);               
    hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;

    if(!hCurrentWindow)
        std::cout<<"Failed get the child window handle
";

    std::cout<<"GO!!!
";

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

Now, "transparent" messages are sent every time. GetLastError() says:

ERROR_INVALID_WINDOW_HANDLE

1400 (0x578)

Invalid window handle.

GetLastError() "fixed"

int main()
{
    HWND hCurrentWindow;
    DWORD procID;
    GUITHREADINFO currentWindowGuiThreadInfo;

    Sleep(5000);

    hCurrentWindow = GetForegroundWindow();

    if(!hCurrentWindow)
        std::cout<<"Failed get main the window handle
";

    GetWindowThreadProcessId(hCurrentWindow,&procID); 
    GetGUIThreadInfo(procID,&currentWindowGuiThreadInfo);               
    hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;

    if(!hCurrentWindow)
        std::cout<<"Failed get the child window handle
";

    std::cout<<"GO!!!
";

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

...outputs 1400 thousand times. Except this, nothing has changed.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This will of course happen when you post the message to the wrong window. Which is certainly the case for Notepad. It doesn't have just one window, something you can see with Spy++. GetForegroundWindow() returns you a top-level window, the frame window for Notepad. Inside of that frame window it has a child window, an EDIT control. That window needs to get the messages.

You'll need to jump through a few hoops to get that window, the GetFocus() function returns the window with the focus but that only works if you call it from the process that owns the window. When you do this out-of-process then you must first call GetWindowThreadProcessId() to get the ID of the thread that owns the foreground window. Then you must call GetGUIThreadInfo(), the GUITHREADINFO.hwndFocus it returns is the window handle you need.

This is still not without trouble, you cannot control the keyboard state of the process. In other words, the state of the Shift, Ctrl and Alt keys as well as any dead keys (like Alt+Gr on certain keyboard layouts). Favor sending WM_CHAR for typing keys.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...