Thread: Pass Fake Keystrokes to 3'rd Party Application

  1. #1
    Registered User
    Join Date
    Oct 2002
    Posts
    7

    Question Pass Fake Keystrokes to 3'rd Party Application

    I want to launch a third party application from my program, get the windows handle on that application and then pass fake keystrokes to that application to perform certain tasks that is not supported by command line parameters.

    I've been told that this is possible using windows SDK function calls using the windows messaging system. I've tried to get to the relevant sections on how to do this on the Microsoft website, but with no success. I just cant seem to find the appropriate sections covering the windows messaging system, cause I end up with results explaining either Outlook or Exchange features to me.

    Can anyone shed some light on this and point me in the right direction.

    Best regards

    Jattie

    This was moved from the C Forum by kermi3

  2. #2
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    Use the FindWindow API command to get the handle of the window you want. You will need to know the name on caption bar of the window. (Finding the window handle of process you have just spawned is much more difficult, and you will end having to examine all the windows on currently on the system to find which one has the spawned process id, but it can be done).

    Once you have the handle of the window, you can send it a message using SendMessage, which looks like:

    Code:
    LRESULT SendMessage(
      HWND hWnd,      // handle of destination window
      UINT Msg,       // message to send
      WPARAM wParam,  // first message parameter
      LPARAM lParam   // second message parameter
    );
    I suggest you send it a key down message. Info about key down as follows:


    WM_KEYDOWN
    nVirtKey = (int) wParam; // virtual-key code
    lKeyData = lParam; // key data

    Parameters
    nVirtKey
    Value of wParam. Specifies the virtual-key code of the nonsystem key.
    lKeyData
    Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table. Value Description
    0–15 Specifies the repeat count for the current message. The value is the number of times the keystroke is auto-repeated as a result of the user holding down the key. If the keystroke is held long enough, multiple messages are sent. However, the repeat count is not cumulative.
    16–23 Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
    24 Specifies whether the key is an extended key, such as the right-hand alt and ctrl keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
    25–28 Reserved; do not use.
    29 Specifies the context code. The value is always 0 for a WM_KEYDOWN message.
    30 Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
    31 Specifies the transition state. The value is always 0 for a WM_KEYDOWN message.

  3. #3
    Registered User
    Join Date
    Oct 2002
    Posts
    7

    Unhappy

    I'm still not getting the desired response that I expect to get. For instance I want to try and pass some menu commands to my application to upload a program to a serial controller and I need to access the __file menu and select __Download from there, so i theory I need to pass <ALT>F then D or <ALT>F <ALT>D to the application. I've tried to use the messaging system calls as set out in my code to try and open windows notepad menu but there is no response. I managed to get the handle successfull now but the messages passed has no response, can you please elaborate on the sequence to actually pass the keystrokes to the application now?

    Below the code of what I've done so far.
    Code:
    #include "windows.h"
    #include <ansi_c.h>
    #include <utility.h>
    #include <cvirte.h>
    
    
    int __stdcall WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
    					   LPSTR lpszCmdLine, int nCmdShow)
    {
    	int ExeHandle;
    	HWND WindowHandle;
    	LRESULT Result;
    	
    	if (InitCVIRTE (hInstance, 0, 0) == 0)
    		return -1;    /* out of memory */
    	//launch my application here
    	//system (Notepad.exe WinMSG.txt);
    	LaunchExecutableEx ("Notepad.exe WinMSG.txt", LE_SHOWNORMAL, &ExeHandle);
    	//get the handle to the application
    	WindowHandle = FindWindow(
    					  	"Notepad",			//LPCTSTR lpClassName - class name
    					  	"WinMSG.txt - Notepad"//LPCTSTR lpWindowName - window name
    						);
    	//and send a message to the application
    	Result = SendMessage(
    				  	WindowHandle,	// handle to destination window
    				  	WM_KEYDOWN,		// message
    				  	VK_MENU,	// first message parameter
    				  	1	// second message parameter
    					);
    	Result = SendMessage(
    				  	WindowHandle,	// handle to destination window
    				  	WM_CHAR,		// message
    				  	'a',	// first message parameter
    				  	1	// second message parameter
    					);
    	
    	TerminateExecutable (ExeHandle);
    	RetireExecutableHandle (ExeHandle);
    	return 0;
    }

    Code tags added by Hammer
    Last edited by Jattie; 10-30-2002 at 09:28 AM.

  4. #4
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    Here's what I suggest: Write a quick program which receives messages, and logs WM_KEYDOWN/WM_KETUP & WM_CHAR messages. Press the keys you want & see what comes through.


    I think a key press constitutes a WM_KEYDOWN followed by a WM_KEYUP. I think a WM_CHAR is generated automatically in this. So you could try two different approaches, one where you send it a WM_KEYDOWN(s) followed by WM_KEYUP. Also try sending a single WM_CHAR message.

    In the case of WM_CHAR, you will have to correctly specify that the alt key is down in lKeyData, which you don't appear to be doing. Alt key is specified by 29th bit. You seem to be simply setting lKeyData to 1, which is simply setting the 0th bit.

    try:

    SendMessage(hndl, WM_CHAR, 'A', 0x40000001);

    I.e. the 0x40000000 is the 29th bit, plus 1 for a repeat rate.
    Last edited by Davros; 10-30-2002 at 06:26 AM.

  5. #5
    Registered User
    Join Date
    Oct 2002
    Posts
    7

    Unhappy

    Still not working.

    How would you send a simple command to windows notepad menu, for instance <ctrl> S?
    Last edited by Jattie; 10-30-2002 at 09:51 AM.

  6. #6
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    The M$ documentation is hard work, but the necessary info regarding WM key messages is there.

    I have done this before, but it was sometime ago and took me a lot of effort to get it working. Unfortunately, I don't have the code with me, otherwise I would post it.

    As I suggested, write a quick application which logs WM_KEYDOWN, WM_KEYUP, WM_CHAR and any other message you suspect. Hit some keys and see what is logged. Use this information to decide what you need to send to Notepad. This is exactly what I had to do.
    OS: Windows XP
    Compilers: MinGW (Code::Blocks), BCB 5

    BigAngryDog.com

  7. #7
    Registered User
    Join Date
    Oct 2002
    Posts
    7
    Thanks, I'll give it a go. Like you said thou, M$ documentation is hard! If you do come across your code however please let me know.

    Thanks for your help and comments!

  8. #8
    Registered User
    Join Date
    Oct 2002
    Posts
    7
    This is what I've been able to learn so far with regard to sending keystrokes to a third part executable application that's launched by my application. In summary I basically get the handle to the application and simply send it a message using that handle and the message format is determined by the output captured using a handy application spy.exe found in the M$ SDK. This message is repeated by my code but nothing happens in the third party application(notepad in this case) when I send the messages from my code. For some reason unknown (and undocumented by M$) it simply does not respond. My guess is that it has to do with the handle of the message sender and I have to assume that it is a handle (00170448) that's in front of spy's output because it's also not described in the M$ documentation. The only difference I can see is the handle/ID being different and the keydown capture handle in the captured sequence is different.

    So if anyone can help me to make some progress beyond this point, please let me know, any suggestions or ideas are welcome!


    Code:
    /*
    Captured code capturing keystrokes in Notepad pushing <ctrl>S
    00170448	WM_KEYDOWN	00000011	001D0001 
    00170448	WM_KEYDOWN	00000053	001F0001 
    00170448	WM_CHAR		00000013	001F0001 
    00050514	WM_KEYUP	00000053	C01F0001 
    00050514	WM_KEYUP	00000011	C01D0001 
    
    result of my program code sending the same keystrokes with messages also captured in spy.
    0019044E	WM_KEYDOWN	00000011	001D0001 
    0019044E	WM_KEYDOWN	0000004F	00180001 
    0019044E	WM_CHAR		0000000F	00180001 
    0019044E	WM_KEYUP	0000004F	C0180001 
    0019044E	WM_KEYUP	00000011	C01D0001 
    */
    My Code
    Code:
    
    #include "windows.h"
    #include "toolbox.h"
    #include <ansi_c.h>
    #include <utility.h>
    #include <cvirte.h>
     
    
    int __stdcall WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
    					   LPSTR lpszCmdLine, int nCmdShow)
    {
    	int ExeHandle;
    	HWND WindowHandle;
    	LRESULT Result;
    	WPARAM WParam;
    	LPARAM LParam;
    	
    	//launch my application here
    
    	LaunchExecutableEx ("Notepad.exe WinMSG.txt", LE_SHOWNORMAL,&ExeHandle);
    	//wiat a while before getting the handle else it return NULL
    	Delay(1);
    	//get the handle to the application
    	WindowHandle = FindWindow(
    	                            "Notepad",			//LPCTSTR lpClassName - class name
    	                             "WinMSG.txt - Notepad"//LPCTSTR lpWindowName - window name
    						);
    	//Key sequence captured with Spy.exe - what happens when you hit <ctrl>S in
    	//a notepad window and you get the save dialogue
    	/*
    	00170448	WM_KEYDOWN	00000011	001D0001 
    	00170448	WM_KEYDOWN	00000053	001F0001 
    	00170448	WM_CHAR		00000013	001F0001 
    	00050514	WM_KEYUP	00000053	C01F0001 
    	00050514	WM_KEYUP	00000011	C01D0001 
    	*/
    
    	//This code produces the exact same results in spy, but no result in notepad
    	WParam=0x11;
    	LParam=0x1D0001;
    	Result = SendMessage(WindowHandle,WM_KEYDOWN,WParam,LParam);
    	
    	WParam=0x4F;
    	LParam=0x180001;
    	Result = SendMessage(WindowHandle,WM_KEYDOWN,WParam,LParam);
    	
    	WParam=0xF;
    	LParam=0X180001;
    	Result = SendMessage(WindowHandle,WM_CHAR,WParam,LParam);
    	
    	WParam=0x4F;
    	LParam=0xC0180001;
    	Result = SendMessage(WindowHandle,WM_KEYUP,WParam,LParam);
    	
    	WParam=0x11;
    	LParam=0xC01D0001;
    	Result = SendMessage(WindowHandle,WM_KEYUP,WParam,LParam);
    	
    	Delay(5);
    	TerminateExecutable (ExeHandle);
    	RetireExecutableHandle (ExeHandle);
    	
    	return 0;
    }
    Last edited by Jattie; 10-31-2002 at 04:38 AM.

  9. #9
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    Check your WindowHandle after FindWindow to see if it NULL. Make sure it is working.

    Also remember you are looking for the window caption, which in some applications can change depending upon the name of the document open at the time.

    Try calling:

    FindWindow(NULL, "Untitled - Notepad');
    OS: Windows XP
    Compilers: MinGW (Code::Blocks), BCB 5

    BigAngryDog.com

  10. #10
    Registered User
    Join Date
    Oct 2002
    Posts
    7
    I am positive that I'm adressing the right window and that the handle is not Null, in fact I used another utility TaskSpy from TaskWare to check the Notepad window information and the returned handle matches the handle that my code returned.

    There must be something else that I'm missing and that's not documented in the Microsoft SDK.

    In any case thanks for all your input so far, let me know if you can think of something else that I might be missing.

    Originally posted by Davros
    Check your WindowHandle after FindWindow to see if it NULL. Make sure it is working.

    Also remember you are looking for the window caption, which in some applications can change depending upon the name of the document open at the time.

    Try calling:

    FindWindow(NULL, "Untitled - Notepad');

  11. #11
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    Mmmm...

    I'm obviously stabbing in the dark here, but may be it's the edit control in NotePad you need to send the messages to. See if you can send a message to the parent window (which you have) to make it return it's child which currently has focus (i.e. the edit control). Then send the messages to that.

    If nothing seems to work, here are some desperate alternatives:

    1. Notepad is a trivial application. You could easily write you own clone (ClonePad) & build in your own method of communicating with it. Instead of launching NotePad, launch your clone & control that.

    2. Launch your file in M$ Word. I know that Word has built in methods of control. I believe it uses COM/automation objects, or something. However, I normally steer clear of this kind of stuff, and therefore don't know much about it.

    3. Send Notepad a mouse click over the File menu item (i.e. near top/left corner), followed by an 'S' key message. But this is real desperation stakes. Figuring out mouse messages is even harder than WM_KEY messages.

    If you get your key messages working, I'd be interested to know what the problem was.
    Last edited by Davros; 10-31-2002 at 02:57 PM.

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    When you send a program a keycode, along with that the information relating to the fact that you are an outside application is passed through the guard of the OS. Thus the solution is not going to be so simple. There are probably undocumented API's for this, as well some code out on the internet that achieves this. But I think you may have to do something like:
    -obtain the target windows handle as you have.
    -set the focus on that window.
    -invoke bios keyboard interrupts to bypass sendmessage.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Fake keystrokes to another process
    By Nota in forum Windows Programming
    Replies: 20
    Last Post: 01-26-2009, 11:56 PM
  2. Patching an exe to block 3rd party extractors
    By jmprox in forum Windows Programming
    Replies: 9
    Last Post: 09-24-2008, 11:54 AM
  3. Speed test result
    By audinue in forum C Programming
    Replies: 4
    Last Post: 07-07-2008, 05:18 AM
  4. Retrieving the result of a third party application
    By nvoigt in forum Windows Programming
    Replies: 2
    Last Post: 06-09-2004, 03:43 AM