Thread: Fake keystrokes to another process

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    5

    Fake keystrokes to another process

    Hi all!

    I've been dealing with the task of sending fake keystrokes from my process to windows of other processes. I can send messages such like minimize or close. But when i try to send WM_KEYDOWN or WM_CHAR messages to microsoft programs (notepad is the one i've been working with), nothing happens!!!!

    Found a thread in this forum (2002) which tries to solve it, but no solution appears.

    So, I've done a little program to show messages so that i can send exactly the same messages, with the same wParam and lParam than Windows do when a key is pressed.

    And think i found the following problem (hope sbdy could confirm):

    When i send a message, it's sent directly to windowproc, while when a key is really pressed, it's sent to the messages loop (GetMessage(..) function) where it's translated, dispatched and whatever..

    So, if, as i suspect, microsoft programs translate WM_KEYDOWN and/or WM_CHAR messages to another WM_USER+n message which is unknown for external users, i find myself with no more ideas to go on.... :S

    Does anybody have some info about this?? Do i have to send keystrokes at a lower level??

    Thanks in advance!!

  2. #2

  3. #3
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Found a thread in this forum (2002) which tries to solve it, but no solution appears.
    One possible solution.....
    Code:
    #include <windows.h> 
    #include <stdio.h>
    
    #define VK_A 0x41
    #define VK_B 0x42
    #define VK_E 0x45
    #define VK_H 0x48
    #define VK_O 0x4F
    #define VK_R 0x52
    #define VK_S 0x53
    #define VK_W 0x57
    
    int main(void)
    {
        HWND hWnd=NULL; 
        HWND hWndEdit=NULL; 
    
        hWnd=FindWindow("Notepad",NULL); 
        if(hWnd==NULL) 
        {
            printf("Error: Can't find Notepad, aborting\n");
            return 0;
        } 
        hWndEdit=FindWindowEx(hWnd,NULL,"Edit",NULL);
        if(hWndEdit==NULL) 
        {
            printf("Error: Can't find Notepad Edit, aborting\n");
            return 0;
        }
        PostMessage(hWndEdit,WM_KEYDOWN,VK_B,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_O,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_B,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_SPACE,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_W,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_A,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_S,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_SPACE,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_H,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_E,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_R,1);
        PostMessage(hWndEdit,WM_KEYDOWN,VK_E,1);
        return 0;
    }

  4. #4
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Assuming of course that DXInput or some other method isn't used...

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    137
    Quote Originally Posted by BobS0327 View Post
    One possible solution.....
    No, wrong method (Win32 FAQ)

  6. #6
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by Alex31 View Post
    No, wrong method (Win32 FAQ)
    There are a gazillion Win32 FAQ's all over the 'net. How about posting a specific link so that we may debate the issue?

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Assuming of course that DXInput or some other method isn't used...
    DirectInput is not suited nor designed for this type of task.

  8. #8
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    and yet my posted solution works perfectly at producing the keystroke...

  9. #9
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Quote Originally Posted by Bubba View Post
    DirectInput is not suited nor designed for this type of task.
    Yes I'm aware of that... I meant provided the process doesn't use DirectInput or some other method to catch key strokes.

  10. #10
    Registered User
    Join Date
    Jan 2009
    Posts
    5
    Thank u all for your help! Specially to abachler and BobS0327

    abachler, keyb_event works fine, thank you a lot!, but i find that, before calling the function, i must set focus on the application I want it to write in.
    It's ok to use WM_SETFOCUS, which i tried with non-microsoft programs (e.g. matlab, openoffice.org writer), but i get no result with microsoft programs. With these, y use WM_MAXIMIZE, which works fine, but is quite annoying.
    Anyway, is it possible to use keybd_event with a program A and let the user work with other program B without being bothered with focus issues??


    BobS0327, thank you very much for your help, it worked fine too, and i avoid focus problems. However, when i use it with other programs, do you know how can i get the name of the child window classes in it, in case they're not predefined like "Edit"? And what if there are several controls of the same class?
    By the way, (in case you're still with forces to help me!), why, as it is in your code, does PostMessage(hWndEdit, ...) works, and not (as i tried too) PostMessage(hWnd, ...)? PostMessage sends the message to the owner thread, and the thread seems to be the same for hWnd and hWndEdit, doesn't it?

    Thank you again

  11. #11
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    However, when i use it with other programs, do you know how can i get the name of the child window classes in it, in case they're not predefined like "Edit"? And what if there are several controls of the same class?
    Code:
    #include <stdio.h>
    #include <windows.h>
    
    void ListChildWindows(HWND hWnd, DWORD dwPIDCheck)
    {
        DWORD dwPID;    
        char szBuffer[1000] = {0};
        GetWindowThreadProcessId(hWnd, &dwPID);
        GetWindowText(hWnd, szBuffer, 1000);
        if(dwPID == dwPIDCheck)
            printf("%-8X %-40s %-8d\n", hWnd, szBuffer,dwPID);
        for(hWnd = GetWindow(hWnd, GW_CHILD); hWnd != NULL; hWnd = GetWindow(hWnd, GW_HWNDNEXT))
            ListChildWindows(hWnd, dwPIDCheck);
    }
    
    int main(int argc, char **argv)
    {
        HWND hDesktopWindow = NULL;
        if(argc == 1)
        {
            printf("Invalid  arguments\n");
            return 0;
        }
        hDesktopWindow = GetDesktopWindow();
        ListChildWindows(hDesktopWindow, atoi(argv[1]));
        return 0;
    }
    The process ID is the input for the above snippet. It will list all the windows for a particular process.

    By the way, (in case you're still with forces to help me!), why, as it is in your code, does PostMessage(hWndEdit, ...) works, and not (as i tried too) PostMessage(hWnd, ...)? PostMessage sends the message to the owner thread, and the thread seems to be the same for hWnd and hWndEdit, doesn't it?
    Because you want to send (post) a message to the actual EDIT window not the window that "contains" the EDIT window. We're not working with threads but rather working with windows. I hope that makes sense.

  12. #12
    Registered User
    Join Date
    Jan 2009
    Posts
    5
    Because you want to send (post) a message to the actual EDIT window not the window that "contains" the EDIT window. We're not working with threads but rather working with windows. I hope that makes sense.
    Yap, that's what i thought first too, but then i went into winapi documentation. http://msdn.microsoft.com/en-us/libr...44(VS.85).aspx It seems to work with threads, so... I'm lost.
    By the way, who is the owner thread of a window? The main thread in the process, or the one which calls CreateWindow()?Thx!!

    Thank you for the code!
    Last edited by Nota; 01-25-2009 at 09:09 AM.

  13. #13
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Quote Originally Posted by BobS0327 View Post
    Code:
        for(hWnd = GetWindow(hWnd, GW_CHILD); hWnd != NULL; hWnd = GetWindow(hWnd, GW_HWNDNEXT))
            ListChildWindows(hWnd, dwPIDCheck);
    Quote Originally Posted by http://msdn.microsoft.com/en-us/library/ms633515(VS.85).aspx GetWindow Function
    The EnumChildWindows function is more reliable than calling GetWindow in a loop. An application that calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle to a window that has been destroyed.
    Quote Originally Posted by Nota View Post
    It seems to work with threads, so... I'm lost.
    Windows are created by threads, which then run in the Get/PeekMessage loop to retrieve and process the messages directed towards these windows. PostMessage puts the message in this queue for the thread to deal with as and when it is retrieved from the queue. This is in direct contrast to SendMessage, which bypasses the message queue completely and calls the window procedure directly. The owner thread is the one which called CreateWindow(Ex). This happens to be the main thread in the majority of applications but that's just a convention, not a hard and fast rule.

  14. #14
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    The EnumChildWindows function is more reliable than calling GetWindow in a loop. An application that calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle to a window that has been destroyed.
    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.

  15. #15
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by Nota View Post
    Yap, that's what i thought first too, but then i went into winapi documentation. http://msdn.microsoft.com/en-us/libr...44(VS.85).aspx It seems to work with threads, so... I'm lost.
    By the way, who is the owner thread of a window? The main thread in the process, or the one which calls CreateWindow()?Thx!!

    Thank you for the code!
    I decided to approach this from the thread point of view with the following code:

    Code:
    #include <windows.h>
    #include <stdio.h>
    
    #define VK_B 0x42
    #define VK_O 0x4F
    
    int main(int argc, char *argv[])
    {
        HWND hWnd, hWndEdit;
        unsigned long ulProc;
        HANDLE hThread, hThreadEdit;
    
        hWnd=FindWindow("Notepad",NULL); 
        if(hWnd==NULL) 
        {
            printf("Error: Can't find Notepad, aborting\n");
            return 0;
        } 
        hWndEdit=FindWindowEx(hWnd,NULL,"Edit",NULL);
        if(hWndEdit==NULL) 
        {
            printf("Error: Can't find Notepad Edit, aborting\n");
            return 0;
        }
        printf("Found Notepad Window At...0x%xh\n",hWnd);
        printf("Found Notepad Edit Window At...0x%xh\n",hWndEdit);
        hThreadEdit = (void *)GetWindowThreadProcessId(hWndEdit,&ulProc);
        if(hThreadEdit  == NULL)
        {
            printf("Search for Edit thread failed\n");
            return 0;
        }
        else
        {
            printf("PostThreadMessage to EDIT window: TID 0x%xh  PID 0x%xh\n",hThreadEdit,ulProc);
            PostThreadMessage((DWORD) hThreadEdit,(UINT) WM_KEYDOWN,VK_B,1);
            PostThreadMessage((DWORD) hThreadEdit,(UINT) WM_KEYDOWN,VK_O,1);
            PostThreadMessage((DWORD) hThreadEdit,(UINT) WM_KEYDOWN,VK_B,1);
        }
    #ifdef SHUTNOTEPAD
        hThread = (void *)GetWindowThreadProcessId(hWnd,&ulProc);
        if(hThread  == NULL)
        {
            printf("Search for Notepad main thread failed\n");
            return 0;
        }
        else
        {
            PostThreadMessage((DWORD) hThread,(UINT) WM_QUIT,0,0);
        }
    #endif  
        return 0;
    }
    Unfortunately, I could not get PostThreadMessage to work. I used WinId to verify that my handle and thread ID's were correct. And they were. This problem was really stumping me. So, I searched Safari and all I found were statements indicating that PostThreadMessage would not work under the above circumstances and that PostMessage should be used. But no one indicated WHY it wouldn't work. Now I googled and only found this link. Well, we all know that there's a lot of misinformation on the net. Thus, I wasn't going to take this link on face value and started OllyDbg to verify the statemenst on the link. Lo and behold, the PostThreadMessage message was not getting to the local loop.

    Also, it's interesteing to note that PostThreadMessage does make it to the main loop. This is illustrated by the commented out code. If you uncomment the code, you can terminate notepad.

    Finally, if you aren't already using Ollydbg, I would strongly suggest that you start. IMHO, it's the greatest thing since sliced bread.

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, 10:05 AM
  2. Replies: 3
    Last Post: 10-15-2008, 09:24 AM
  3. Problem with forking a process
    By Unitedroad in forum C Programming
    Replies: 10
    Last Post: 10-04-2007, 01:43 AM
  4. process programming
    By St0rM-MaN in forum Linux Programming
    Replies: 2
    Last Post: 09-15-2007, 07: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