Fake keystrokes to another process

This is a discussion on Fake keystrokes to another process within the Windows Programming forums, part of the Platform Specific Boards category; Originally Posted by BobS0327 Unfortunately, I could not get PostThreadMessage to work. This problem was really stumping me. Originally Posted ...

  1. #16
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    612
    Quote Originally Posted by BobS0327 View Post
    Unfortunately, I could not get PostThreadMessage to work. This problem was really stumping me.
    Quote Originally Posted by PostThreadMessage
    Messages sent by PostThreadMessage are not associated with a window. As a general rule, messages that are not associated with a window cannot be dispatched by the DispatchMessage function
    While that suggests there are exceptions, WM_KEYDOWN doesn't seem to be one. Without a window handle, who is it going to dispatch the (apparent) keystroke to? On XP SP3, the answer is no one, so nothing happens. It is removed from the message queue with no visible effect that it ever made it to its destination. WM_QUIT works because it causes GetMessage to return 0 which stops the message loop.

    How about posting a complete working example of using EnumChildWindows as needed in the context of this thread? I'm sure we'll all benefit from it . Especially, the OP.
    This is an extended version of yours
    Code:
    #undef UNICODE
    #undef _UNICODE
    #define WIN32_LEAN_AND_MEAN
    #define _WIN32_WINNT 0x0500
    
    #include <windows.h>
    #include <iostream>
    #include <shlwapi.h>
    #include <sstream>
    #include <iostream>
    
    #pragma comment(lib, "shlwapi.lib")
    
    // our enumerators
    BOOL WINAPI ChildEnumerator(HWND hwnd, LPARAM lParam);
    BOOL WINAPI ParentEnumerator(HWND hwnd, LPARAM lParam);
    
    // Struct masquerading as a text sink
    struct Buffer
    {
        // constructor sets up where to dump the final buffer, defaults to cout
        inline Buffer(std::ostream& out = std::cout) : out(out){}
    
        // destructor dumps it
        inline ~Buffer()
        {
            Dump();
        }
    
        // this allows nicer syntax for print operations, similar to printf.
        // Less typing required both here and invocation than operator()
        // with no real loss IMHO
        template<class T>
        Buffer& operator,(const T& data)
        {
            buf << data;
            return *this;
        }
    
        // this is retained from cout syntax, so we can see where the 
        // data is being streamed to just by looking at the first output
        // it's usage is not necessary
        template<class T>
        Buffer& operator<<(const T& data)
        {
            buf << data;
            return *this;
        }
    
        // dumps the text to the output stream specified in the constructor
        inline void Dump()
        {
            out << buf.str();
            out << std::endl;
        }
    
        // the ultimate output stream, and our buffer
    private:
        std::ostream& out;
        std::ostringstream buf;
    };
    
    void OutputWindowProperties(HWND hwnd, Buffer& printer)
    {
        char winText[512] = {0};
         // Get the text it's displaying
        if(SendMessage(hwnd, WM_GETTEXT, 512, reinterpret_cast<LPARAM>(winText)))
        {
            printer << "\tText: ", winText, '\n';
        }
        // Find out which file created it
        if(GetWindowModuleFileName(hwnd, winText, 512))
        {
            printer << "\tCreated by: ", PathFindFileName(winText), '\n';
        }
    
        // see what thread/process it came from
        DWORD procID = 0;
        DWORD threadID = GetWindowThreadProcessId(hwnd, &procID);
        printer << "\tOwning Process ID: ", procID, " Thread ID: ", threadID, '\n';
    
        // get some misc info
        WINDOWINFO wInfo = {sizeof(wInfo), 0};
        GetWindowInfo(hwnd, &wInfo);
    
        // se if we can get the class it belongs to
        WNDCLASSEX wcl = {sizeof(wcl), 0};
        if(GetClassInfoEx(reinterpret_cast<HINSTANCE>(GetWindowLongPtr(hwnd, GWLP_HINSTANCE)), 
           reinterpret_cast<LPCSTR>(wInfo.atomWindowType), &wcl))
        {
            printer << "\tClassInfo:\n\t\tName: ";
            // try and get the name of the class
            if(GetAtomName(wInfo.atomWindowType, winText, 512))
            {
                printer << winText, '\n';
            }
            // if we can't, see if the class belongs to the current process
            // if it does, we can dereference the string
            else if(GetCurrentProcessId() == procID)
            {
                printer << wcl.lpszClassName, '\n';
            }
            // otherwise, just print the class id
            else
            {
                printer << wInfo.atomWindowType, '\n';
            }
            // output the wndproc address in hex
            printer << "\t\tWndProc at address: ", std::hex, wcl.lpfnWndProc, std::dec, '\n';
        }
        // finally the window X/Y location
        printer << "\tX Location: ", wInfo.rcWindow.left, ", Y Location: ", wInfo.rcWindow.top, '\n';
    }
    
    // called for each top level window
    BOOL WINAPI ParentEnumerator(HWND hwnd, LPARAM lParam)
    {
        // our dumping ground
        Buffer printer;
        // output window handles in hex, then change the number format back to decimal
        printer << "Top-Level Window - ", std::hex, hwnd, std::dec, '\n';
        // Get its' properties
        OutputWindowProperties(hwnd, printer);
        // go through any children and do the same, passing in the text buffer
        // so we can have a roughly hierachichal structure to the output
        EnumChildWindows(hwnd, ChildEnumerator, reinterpret_cast<LPARAM>(&printer));
        // keep calling us for windows we haven't encountered yet
        return TRUE;
    }
    
    // called for each child window
    BOOL WINAPI ChildEnumerator(HWND hwnd, LPARAM lParam)
    {
        // get the text buffer we passed in
        Buffer& printer = *(reinterpret_cast<Buffer*>(lParam));
        // everything else is the same as the one above
        printer << "\n  Child Window ", std::hex, hwnd, std::dec, '\n';
        OutputWindowProperties(hwnd, printer);
        return TRUE;
    }
    
    int main(int argc, char *argv[])
    {
        // start the chain of window enumeration
        // warning, will spew out lots of data
        EnumWindows(ParentEnumerator, 0);
    }

  2. #17
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    Messages sent by PostThreadMessage are not associated with a window. As a general rule, messages that are not associated with a window cannot be dispatched by the DispatchMessage function
    They are associated to the thread assigned to window since my previous example illustrated how to send a WM_QUIT message to a window via a thread. This also can be demonstrated by executing the WinId util I previously referenced and finding the Notepad - Untitled window. You'll see a thread ID attached to that window. Thus, you can send a PostThreadMessage to that thread without any issues whatsover. The problem lies with trying to send a PostThreadMessage to a child window with a local message loop. This, also can be demontrated by opening up a text document in Notepad,and then executing WinId, finding the thread id of the child edit window and sending a PostThreadMessage to that thread. Using Ollydbg shows that the message gets "lost". I have a couple of theories as to why it gets lost. But I can't post post my theories until I can find some authoritatative references to substantiate my posts.
    Last edited by BobS0327; 01-26-2009 at 06:50 AM. Reason: Update

  3. #18
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    This is an extended version of yours
    No. it's not even close since it doesn't provide the required info that the original poster needs to complete his task. Execute my snippet and you'll see the information that he needs.

  4. #19
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    612
    You don't need any authorative sources, a simple program will suffice.

    Code:
    #define _UNICODE
    #define UNICODE
    #include <windows.h>
    #include <iostream>
    
    LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
    {
        switch( msg )
        {
            case WM_DESTROY:
            {
                DestroyWindow(hWnd);
                PostQuitMessage( 0 );
                return 0;
            }
            case WM_KEYDOWN:
            {
                std::cout << "WM_KEYDOWN received with key: " << static_cast<char>(wParam) << '\n';
            }
            break;
            case WM_CHAR: // TranslateMessage will produce one for a WM_KEYDOWN
            {
                std::wcout << L"WM_CHAR received with key: " << static_cast<WCHAR>(wParam) << L'\n';
            }
            break;
        }
        return DefWindowProc( hWnd, msg, wParam, lParam );
    }
    
    struct ThreadParams
    {
        DWORD threadId;
        HANDLE hEvent;
    };
    
    DWORD WINAPI ThreadFunc(LPVOID lpParam)
    {
        ThreadParams* tp = static_cast<ThreadParams*>(lpParam);
        while(WaitForSingleObject(tp->hEvent, 500) != WAIT_OBJECT_0)
        {
            PostThreadMessage(tp->threadId, WM_KEYDOWN, 'L', 0);
        }
        return 0;
    }
    
    INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
    {
        // Register the window class
        WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                          GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                          L"D3D Tutorial", NULL };
        if(RegisterClassEx( &wc ))
        {
            // Create the application's window
            HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 03: Matrices",
                                      WS_OVERLAPPEDWINDOW, 100, 100, 256, 256,
                                      NULL, NULL, wc.hInstance, NULL );
            if(hWnd)
            {
                HANDLE hThreadExitEvent = CreateEvent(NULL, TRUE, FALSE, L"ExitEvent");
                if(hThreadExitEvent)
                {
                    ShowWindow( hWnd, SW_SHOWDEFAULT );
                    UpdateWindow( hWnd );
    
                    ThreadParams tp = {GetCurrentThreadId(), hThreadExitEvent};
    
                    HANDLE hThread = CreateThread(NULL, 0, &ThreadFunc, &tp, 0, NULL);
                    if(hThread)
                    {
                        MSG msg = {0};
                        while( GetMessage( &msg, NULL, 0U, 0U) )
                        {
                            std::cout << "GetMessage retrieved message 0x" << std::hex << msg.message << '\n';
                            if(TranslateMessage( &msg ))
                            {
                                std::cout << "TranslateMessage success ";
                            }
                            DispatchMessage( &msg );
                        }
                        SetEvent(hThreadExitEvent);
                        WaitForSingleObject(hThread, INFINITE);
                        CloseHandle(hThread);
                    }
                    else DestroyWindow(hWnd);
                    CloseHandle(hThreadExitEvent);
                }
            }
        }
        return 0;
    }
    
    int wmain()
    {
        return wWinMain(GetModuleHandle(NULL), NULL, NULL, SW_SHOW);
    }
    The WM_KEYDOWN's (0x100) are received with GetMessage but never sent on to the WndProc because there is no HWND set in the message struct. Attach a debugger and step through DispatchMessage. On my XP SP3, without a window its worker func checks if the message is WM_USER, WM_DEVICECHANGE, WM_TIMER, or the undocumented message 0x0118 before ultimately returning without calling anybody. Close the window shows that WM_QUIT never makes it into the loop because it causes GetMessage to return 0 which ends the loop, as the docs for GetMessage state.

    In the case of notepad, all 3 of its windows belong to the same thread. It doesn't matter which windows' thread id you post to as they're all identical (if they're not then that app has a bug or you're using some funky version of notepad) and processed by the same loop, which shows identical behaviour to the program above.
    Last edited by adeyblue; 01-26-2009 at 03:17 PM.

  5. #20
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    The issue with PostThreadMessage is that it will work in the main "root" window because a message queue is available. That has been demonstrated in the code above using WM_QUIT message. In a child window, there isn't necesarily a message queue. But the bottom line is if a message queue is available, PostThreadMessage will work. Otherwise, it will fail. Also, the OP was referring to remote processes such as Notepad. Heck, with a app where the source code is available such as the above listing, the sky's the limit. Anything is possible. I'm basing my stuff on remote apps such as Notepad, MSWord etc.

    The reason why I wish to have an authoritative source or at least proof of concept code is because the above statements may just be pure BULL. Just because I can post "star wars" statements" doesn't necessarily make them true statements. How do you know that I really know what I'm talking about or whether it's just BULL? Case in point CloakDll which is a worthless piece of excrement.

    EDIT. There are actually 5 windows opened when notepad starts.
    Last edited by BobS0327; 01-26-2009 at 06:24 PM.

  6. #21
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    612
    Quote Originally Posted by BobS0327 View Post
    How do you know that I really know what I'm talking about or whether it's just BULL?
    That's the thing, there's a blockage somewhere and you don't know in anyway I interpret it. I'm not sure whether it's just a fundemental misunderstanding or I'm not explaining things clearly but whatever. It takes about 5 minutes to attach to notepad and seen for yourself that it does exactly the same as the app above. PostMessage and PostThreadMessage are one and the same except one fills in the HWND member of the message struct retrieved by Get\PeekMessage, one doesn't. That's the entirety of the difference as to why one will "type" in notepad while the other doesn't. There's a mapping between HWNDs and WndProcs, not between threads and WndProcs.

    In a child window, there isn't necesarily a message queue.
    Of course not since both queues and windows belong to threads. A thread creates a window, a thread pumps messages for that window; that's how it is and knowing MS that's how it will always be. Notepad has one thread and creates 3 windows -> the single thread pumps messages for all 3 windows. If you really wanted to you could spawn a thread to create an edit control for the app above, if that thread doesn't go into its own message loop the edit window will do nothing, the Get/PeekMessage docs spell this out.

    I'm basing my stuff on remote apps such as Notepad, MSWord etc.
    The above paragraph contains the rules for everybody, it's not one rule for them and one for us. Again, 5 minutes in a disassembler and debugger shows you haven't quite got the concept right in some shape or form.

    Case in point CloakDll which is a worthless piece of excrement.
    EDIT. There are actually 5 windows opened when notepad starts.
    Oh the irony here is delicious, I welcome attempts to show me where I've gone wrong but that's just laughable.

Page 2 of 2 FirstFirst 12
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. init adopts zombie process?
    By password636 in forum Linux Programming
    Replies: 4
    Last Post: 07-01-2009, 11:05 AM
  2. Replies: 3
    Last Post: 10-15-2008, 10:24 AM
  3. Problem with forking a process
    By Unitedroad in forum C Programming
    Replies: 10
    Last Post: 10-04-2007, 02:43 AM
  4. process programming
    By St0rM-MaN in forum Linux Programming
    Replies: 2
    Last Post: 09-15-2007, 08:53 AM
  5. Pass Fake Keystrokes to 3'rd Party Application
    By Jattie in forum Windows Programming
    Replies: 11
    Last Post: 10-31-2002, 06:53 PM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21