Following example shows use of SendMessageTimeout and SendMessageCallback to click a button in a different application that invokes a modal dialog without causing the sending application to block.
Before using SendMessageTimeout or SendMessageCallback -
After -
Sample code -
private void OnClickTimeout(object sender, EventArgs e)
{
IntPtr hwnd = Win32.FindWindow("#32770", "Target");
if (hwnd != IntPtr.Zero)
{
IntPtr hBtn = Win32.FindWindowEx(hwnd, IntPtr.Zero, "BUTTON", "MsgBox");
if (hBtn != IntPtr.Zero)
{
UIntPtr uiResult;
Win32.SetForegroundWindow(hwnd);
// use 100 millisecond timeout
Win32.SendMessageTimeout(hBtn, Win32.BM_CLICK, UIntPtr.Zero, IntPtr.Zero,
Win32.SendMessageTimeoutFlags.SMTO_NORMAL, 100, out uiResult);
}
}
}
private void OnClickCallback(object sender, EventArgs e)
{
IntPtr hwnd = Win32.FindWindow("#32770", "Target");
if (hwnd != IntPtr.Zero)
{
IntPtr hBtn = Win32.FindWindowEx(hwnd, IntPtr.Zero, "BUTTON", "MsgBox");
if (hBtn != IntPtr.Zero)
{
Win32.SetForegroundWindow(hwnd);
Win32.SendMessageCallback(hBtn, Win32.BM_CLICK, UIntPtr.Zero, IntPtr.Zero, smcallback, UIntPtr.Zero);
}
}
}
private void smcallback(IntPtr hwnd, uint uMsg, UIntPtr dwData, IntPtr lResult)
{
Debug.Print("Callback received");
}
private void OnFreezer(object sender, EventArgs e)
{
IntPtr hwnd = Win32.FindWindow("#32770", "Target");
if (hwnd != IntPtr.Zero)
{
IntPtr hBtn = Win32.FindWindowEx(hwnd, IntPtr.Zero, "BUTTON", "MsgBox");
if (hBtn != IntPtr.Zero)
{
Win32.SetForegroundWindow(hwnd);
Win32.SendMessage(hBtn, Win32.BM_CLICK, UIntPtr.Zero, IntPtr.Zero);
}
}
}
}
internal class Win32
{
[Flags]
internal enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0,
SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x8,
SMTO_ERRORONEXIT = 0x20
}
internal const uint BM_CLICK = 0xF5;
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void SendMessageDelegate(IntPtr hWnd, uint uMsg, UIntPtr dwData, IntPtr lResult);
[DllImport("User32.dll", CallingConvention =CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr FindWindow(string strclass, string strname);
[DllImport("User32.dll", CallingConvention =CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr FindWindowEx(IntPtr hwnd, IntPtr hwndAfter, string strclass, string strname);
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool SetForegroundWindow(IntPtr hwnd);
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool SendMessage(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool SendMessageTimeout(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam,
SendMessageTimeoutFlags fuflags, uint uTimeout, out UIntPtr result);
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool SendMessageCallback(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam,
SendMessageDelegate lpCallBack, UIntPtr dwData);
}
}