CodeDemen
CodeDemen

Reputation: 1971

SendMessageCallback crushes

I am trying to sent keystrokes to a window that sometimes in background. Most of time it works good, but sometimes it just crushes. As I've noticed it happens when user presses same key on keyboard at exactly same time as the message is sent... Can you please give me some advice how to avoid those crushes? Here is my code to call SendMessageCallback:

Native.SendAsyncProc del = new Native.SendAsyncProc(Helpers.Win32.Native.SendMessage_Callback);
Native.SendMessageCallback(MainWindowHandle, 256U, (int)System.Windows.Forms.Keys.D3, 0, del, UIntPtr.Zero);
        Thread.Sleep(5);
Native.SendMessageCallback(MainWindowHandle, 257U, (int)System.Windows.Forms.Keys.D3, 0, del, UIntPtr.Zero);

and in Native:

[DllImport("user32.dll")]
    public static extern bool SendMessageCallback(IntPtr hWnd, uint Msg, int
    wParam, int lParam, SendAsyncProc lpCallback, UIntPtr dwData);
    public delegate void SendAsyncProc(IntPtr hwnd, uint uMsg, UIntPtr dwData,
    IntPtr lResult);
    public static void SendMessage_Callback(IntPtr hwnd, uint uMsg, UIntPtr dwData, IntPtr lResult)
    {
        //LogManager.LogError("SM CB {0}",(DateTime.Now - td).TotalMilliseconds.ToString());
        return;
    }

Also Ive noticed it never raises SendMessage_Callback... But can not understand why till now...

Upvotes: 0

Views: 446

Answers (1)

Eric Brown
Eric Brown

Reputation: 13932

Your problem is that you're trying to simulate keyboard input using the moral equivalent of PostMessage. That doesn't work reliably. In particular, apps in the background have lost focus and activation, and many applications rely on focus and activation messages to properly handle input. Raymond Chen has more about how Windows handles input here.

Also, you're not getting your callback because you're not pumping messages while your sleeping. Use a WaitHandle to wait, as it will pump messages while waiting. You'll need to set the event in your callback, of course.

So, if your code looked like this:

[DllImport("user32.dll")]
public static extern bool SendMessageCallback(IntPtr hWnd, uint Msg, int
wParam, int lParam, SendAsyncProc lpCallback, UIntPtr dwData);
public delegate void SendAsyncProc(IntPtr hwnd, uint uMsg, UIntPtr dwData,
IntPtr lResult);

WaitHandle waiter = new EventWaitHandle (false, EventResetMode.ManualReset);

public static void SendMessage_Callback(IntPtr hwnd, uint uMsg, UIntPtr dwData, IntPtr lResult)
{
    waiter.Set();
    return;
}

Native.SendAsyncProc del = Helpers.Win32.Native.SendMessage_Callback;
Native.SendMessageCallback(MainWindowHandle, 256U, (int)System.Windows.Forms.Keys.D3, 0, del, UIntPtr.Zero);
waiter.WaitOne();
Native.SendMessageCallback(MainWindowHandle, 257U, (int)System.Windows.Forms.Keys.D3, 0, del);
waiter.WaitOne();

You should at least get your callbacks. You'll need to rethink your keyboard simulation from scratch, though. Consider UI Automation, at a bare minimum.

Upvotes: 1

Related Questions