views:

3016

answers:

6

Hi guys,

I need to simulate a keypress in a third party application. Let's say I have a C# application that needs to send an "8" to the Calculator application. I can't use the SendKeys of .Net or the keybd_event of win32 api because they both require the window to be the top active one, which is not case in my situation.

So that leaves me with the calls sendMessage and postMessage. I've been trying in the last three hours trying to get some results but right now I'm completely hopeless.

I have the following:

        [DllImport("user32.dll")]
    public static extern int FindWindow(string lpClassName,string lpWindowName);
    [DllImport("user32.dll")]
    public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);

    private void button1_Click(object sender, EventArgs e)
    {
        const int WM_KEYDOWN = 0x100;
        const int WM_SYSCOMMAND = 0x018;
        const int SC_CLOSE = 0x053;

        int WindowToFind = FindWindow(null,"Calculator");

        int result = SendMessage(WindowToFind, WM_SYSCOMMAND, SC_CLOSE, 0);
        Boolean result2 = PostMessage(WindowToFind, WM_SYSCOMMAND, SC_CLOSE, 0);

        int result3 = SendMessage(WindowToFind, WM_KEYDOWN,((int)Keys.NumPad7), 0);
        Boolean result4 = PostMessage(WindowToFind, WM_KEYDOWN, ((int)Keys.NumPad7), 0);
    }

As you can see, I make four attempts to communicate with the Calculator. Using both sendMessage and PostMessage to close the window and also to send the key 7. Nothing works. The FindWindow Method works cause I get the handler of the app (I've even tryed launching the process myself and accessing it with process.MainWindowHandler, but no luck). There are no errors or exceptions, but it just doesn't do nothing in Calculator.

I've also tried the exact same things with notepad and nothing changed too..

Please help, going mad over here =(

Thanks!

+3  A: 

Any chance you're running this on a 64bit machine? If so, I believe all those 'int' values that are actually hWnds (first argument to Send/Post, return value from FindWindow) need to be IntPtr.


After a bit more checking, it looks like for both SendMessage and PostMessage, the 1st, 3rd, and 4th parameters should be IntPtr instead of int (as well as the return values for all of these)

So, the right signatures would be:

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
Jonathan
I love U :DThanks =)
Joao Oliveira
Wow. That worked? Talk about a lucky guess. I've never even used those two particular win32 methods.
Jonathan
Im actually on 32bits, but it worked nevertheless :)
Joao Oliveira
Hey, whatever works :)
Jonathan
Could you check my last answer? :)
Joao Oliveira
+1  A: 

There is a good article about this on CodeProject: http://www.codeproject.com/KB/cs/SendKeys.aspx

SendKeys is actually the correct idea, but you need to get the HWND (window handle) of the target window. This MSDN sample shows how to use SendKeys effectively, but not how to discover the HWND of anything other than the top-most window.

Combine the two techniques, using the CodeProject example to locate the HWND of the application you want to target, then use the MSDN article to use SendKeys to send the key strokes (or mouse events) to the target application.

Simon Gillbee
+1  A: 

Not directly your question, but the difference between SendMessage and PostMessage is that Send is a blocking call, Post returns immediately (before the receiving application has processed it).

MSDN explains the difference: http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx

Also if you are on vista but not on .NET 3.0 that could also be a problem:

The SendKeys class has been updated for the .NET Framework 3.0 to enable its use in applications that run on Windows Vista. The enhanced security of Windows Vista (known as User Account Control or UAC) prevents the previous implementation from working as expected.

Andrew Burns
A: 

It works for calculator but not for notepad :(

The following code opens the windows calculator, and then presses "7". Works fine.

            Process x = Process.Start(@"CALC");
        Thread.Sleep(5000);
        PostMessage(x.MainWindowHandle, WM_KEYDOWN, ((IntPtr)Keys.NumPad7), IntPtr.Zero);

However, the same thing for Notepad, opens it but doesn't press any key:

            Process x = Process.Start(@"NOTEPAD");
        Thread.Sleep(5000);
        PostMessage(x.MainWindowHandle, WM_KEYDOWN, ((IntPtr)Keys.NumPad7), IntPtr.Zero);

Any ideia why?

Joao Oliveira
The text edit box is probably a child windows of the main notepad window. You may need to get the child's handle. In C it would be something like: GetWindow(hwndNotepad, GW_CHILD);
Slapout
Worked like charm slapout! Thanks :)
Joao Oliveira
A: 

The sound always play when PostMessage() is called. How can i fix this problem?

tuan
A: 

Because it is a Edit Chuld window inside thr notepad window. You shold send mrssages to the right child window. It is a working example on C

   #include <windows.h>
#include <stdio.h>

void main(void) {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    HWND mainwnd,editwnd;
    char c;
    si.cb=sizeof(si);
    si.lpReserved=NULL;
    si.lpDesktop=NULL;
    si.lpTitle=NULL;
    si.dwFlags=0;
    si.cbReserved2=0;
    si.lpReserved2=NULL;
    if(!CreateProcess("c:\\windows\\notepad.exe",NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) {
        printf("Failed to run app");
        return;
    }
    WaitForInputIdle(pi.hProcess,INFINITE);
    mainwnd=FindWindow(NULL,"Untitled - Notepad");
    if(!mainwnd) {
        printf("Main window not found");
        return;
    }
    editwnd=FindWindowEx(mainwnd,NULL,"Edit","");
    if(!editwnd) {
        printf("Edit window not found");
        return;
    }
    for(c='1';c<='9';c++) {
        PostMessage(editwnd,WM_CHAR,c,1);
        Sleep(100);
    }
}
Olgar