"SendMessage" to 3 different processes in C++

Laurence picture Laurence · Mar 25, 2012 · Viewed 11.2k times · Source

I want to send keystrokes to multiple processes. For example, if I press “1”, then I want to send the “1” to 3 "Notepad windows". Frist I want to try to send a keystroke to notepad, but it fails on the HWND:

    //HANDLE hWin; 
    HWND windowHandle = FindWindowA(NULL, "Notepad");   //Can’t find a proccess

    //Send a key
    if( windowHandle ) //This one fails
    {
        while(true)
        {
            if( GetAsyncKeyState(VK_F12) != 0 )
            {
                SendMessageA(windowHandle, WM_KEYDOWN, VK_NUMPAD1, 0); 
                Sleep(1000); 
                SendMessageA(windowHandle, WM_KEYUP, VK_NUMPAD1, 0);
            }
                    Sleep(100);
        }
    }

But the "FindWindow" method is not good enough for my program. There is also no way to get 3 different processes with the same name. So how can I make 3 handles to 3 different processes with the same name? And how can I send key’s to the processes?

Answer

Mike Kwan picture Mike Kwan · Mar 25, 2012

You can use EnumWindows for enumerating all the top level windows on the system. You then need to filter through these windows to get the ones you are interested in. Class name is probably a better choice for filtering rather than the window name though. Here is some example code (not tested) of what I have in mind:

BOOL CALLBACK BroadcastToNotepad(HWND hwnd, LPARAM lParam)
{
    wchar_t lpClassName[16];

    /*
     * More reliable to filter by class name. We could additionally filter
     * by caption name too if necessary.
     */
    if(GetClassName(hwnd, lpClassName, _countof(lpClassName))) {
        if(wcscmp(lpClassName, L"Notepad") == 0) {
            SendMessage(hwnd, WM_KEYDOWN, (WPARAM)lParam, 0);
            Sleep(1000);
            SendMessage(hwnd, WM_KEYUP, (WPARAM)lParam, 0);
        }
    }

    return TRUE;
}

// Some handler which gets invoked when your hotkey is hit.
void handlerKey1(...)
{
    EnumWindows(BroadcastToNotepad, (lParam)VK_NUMPAD1)
}

Note the usage of BroadcastToNotepad and how you can have different handlers pass in a different lParam.

One final thing to note is that PostMessage/SendMessage is not a reliable way to simulate keyboard input. This is noted by Raymond Chen here. SendInput is the preferred way for injecting input. However, to use that you will need to ensure the window you want to send to has the keyboard focus.

I recall vaguely having played with something similar to what you are doing in the past. If I remember correctly, you need to send to Notepad's child window (class name = Edit). So the code above needs to be modified as so:

if(wcscmp(lpClassName, L"Notepad") == 0) {
    HWND hwndChild = FindWindowEx(hwnd, NULL, L"Edit", NULL);

    SendMessage(hwndChild, WM_KEYDOWN, (WPARAM)lParam, 0);
    Sleep(1000);
    SendMessage(hwndChild, WM_KEYUP, (WPARAM)lParam, 0);
}