SendMessage模拟点击按钮的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SendMessage模拟点击按钮的问题相关的知识,希望对你有一定的参考价值。

SendMessage(Btn_Handle,WM_LBUTTONDOWN,1,0);
Sleep(10);
SendMessage(Btn_Handle,WM_LBUTTONUP,0,0);

上面的代码是可以正常执行的,但是有一个问题,当系统比较繁忙时,可能会出现点击,而按钮没有反应的情况。

怎么判断按钮有没有响应,通过sendmessage的返回值行不行

全球::查找窗口GET HWND CWnd类的cwnd,通过GetSafeHwnd()的HWND。
我觉得你的问题是由于PostMessage的消息后,仍队列,标题为“提示”对话框中的另一条消息,你说的应该是鼠标点击的消息,点击鼠标消息的处理将被处理后一个按钮,点击该消息。所以,在这里你需要模拟鼠标点击的消息就可以了。
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP,0,0,0,0);
没有SetCursorPos,移动鼠标会显示,你不应该需要移动的按钮。
参考技术A 可以判断返回值 参考技术B 用BM_CLICK

这个是直接模拟按键的。另外如果没有获得焦点,建议发送两次这个消息。

参数两个0追问

那能否解决系统繁忙时,可能按钮没有响应的问题?
SendMessage(Btn_Handle,BM_CLICK,0,0);
这样就能达到按下松开的效果了吗?

追答

你是模拟按下再放开。需要两个消息,其实BM_CLICK就相当于模拟你那个东西,只不过这个消息是连贯的。不是和你那样间断的发送的。所以不用担心系统忙。

参考技术C 不会,提高回答,拿分

Net实现钩子函数(Hook)以及通过SendMessage实现自动点击按钮和给文本框赋值

原文:Net实现钩子函数(Hook)以及通过SendMessage实现自动点击按钮和给文本框赋值

1.实现钩子函数

钩子(Hook)的实现需要三个主要的函数和一个委托

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);//设置系统钩子

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);//卸载系统钩子

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);//调用下一个钩子函数

public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);//用于处理Hook住的消息

当我们在执行一个操作的时候,首先不是由我们的窗体获得消息,而是系统获得,然后系统再把消息发送到对应的窗体,Hook就是在窗体获取到信息之前抓住信息,然后对信息进行处理,然后可以传递给船体继续执行,或者就不传递给窗体

当在HookProc处理消息的时候,如果return 1,那么消息就会被截断,不会再传递到目标窗口,如果return的是CallNextHookEx那么就会继续调用下一个钩子,如果下面没有钩子了,那么消息就会被传递到目标窗体进行处理

SetWindowsHookEx第一个参数是需要勾住的消息类型,总共14种消息类型,如下

public const int WH_JOURNALRECORD = 0;
public const int constWH_JOURNALPLAYBACK = 1;
public const int WH_KEYBOARD = 2;
public const int WH_GETMESSAGE = 3;
public const int WH_CALLWNDPROC = 4;
public const int WH_CBT = 5;
public const int WH_SYSMSGFILTER = 6;
public const int WH_MOUSE = 7;
public const int WH_HARDWARE = 8;
public const int WH_DEBUG = 9;
public const int WH_SHELL = 10;
public const int WH_FOREGROUNDIDLE = 11;
public const int WH_CALLWNDPROCRET = 12;
public const int WH_KEYBOARD_LL = 13;
public const int WH_MOUSE_LL = 14;

第二个参数就是HookProc委托,用于对钩住的消息进行处理,

第三个参数是需要钩住的实例的句柄,最后一个是钩住的线程,如果是0则是全局钩住

返回值为抓住的钩子的ID

UnhookWindowsHookEx卸载掉钩子,参数为上面返回的ID

 

辅助函数

[DllImport("kernel32.dll")]

public static extern IntPtr GetModuleHandle(string name);//根据模块名称获取到对应的句柄

[DllImport("user32.dll", EntryPoint = "FindWindow")]

private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);//查询一个窗体

[DllImport("User32.dll", EntryPoint = "FindWindowEx")]

private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);//获取窗体中的所有子窗体(文本框,按钮等,都属于窗体)

 

        [DllImport("user32.dll")]

        public static extern int EnumChildWindows(IntPtr hWndParent, CallBack lpfn, int lParam);//枚举窗体中的所有子窗体

public delegate bool CallBack(IntPtr hwnd, int lParam);

此委托是EnumChildWindows的回调函数,用于遍历的时候对窗口进行处理

 

根据Module的名字获取到对应的句柄SetWindowsHookEx的第三个参数可以使用这个函数来获得。

下面是一个示例程序,设置一个全局钩子,作用是,如果输入的字符是小写字母,则直接转换为大写字母。

1.1  HookProc的方法实现

  private int MessageHandle(int nCode, Int32 wParam, IntPtr lParam)

       

            if (0x100 == wParam || 0x101 == wParam)  //如果按键为按下状态,如果没有这句判断,则内部代码会执行两遍,一遍是KeyDown一遍是KeyUp

           

                KBDLLHOOKSTRUCT ks = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));

               //将所有的小写字母直接加1

                if (ks.vkCode >= 65 && ks.vkCode <= 90)

               

                    string cUpper = Convert.ToChar(ks.vkCode).ToString().ToUpper();

                    SendMessage(txtHandle, 0x0c, IntPtr.Zero, cUpper);

               

           

            return CallNextHookEx(result, nCode, 0, lParam);

 

       

1.2 KBDLLHOOKSTRUCT结构体(这个结构体因为不同的钩子内容会不一样)

public struct KBDLLHOOKSTRUCT

   

        public int vkCode;

        public int scanCode;

        public int flags;

        public int time;

        public IntPtr dwExtraInfo;

   

 

1.3设置钩子和卸载钩子(两个按钮的事件)

  private void btnInstallHook_Click(object sender, EventArgs e)

       

            HookProc hProc = new HookProc(MessageHandle);

            IntPtr cInstance = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

            result = SetWindowsHookEx(HookHelper.WH_KEYBOARD_LL, hProc, cInstance, 0);

       

 

        private void btnUnhook_Click(object sender, EventArgs e)

       

            UnhookWindowsHookEx(result);

       

辅助方法:为了获取到窗体中的文本框的句柄

//枚举窗体中的子窗体的回调函数

        private bool EnumWindow(IntPtr hwnd, int lParam)

       

            StringBuilder sb=new StringBuilder();

            GetWindowText(hwnd, sb, 10);

            if (sb.ToString() == "HookTest")

           

                txtHandle = hwnd;

           

            return true;

       

 

 

2.SendMessage的使用

可以使用SendMessage模拟给发送一条系统消息

[DllImport("user32.dll", EntryPoint = "SendMessage")]

        private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

 

        [DllImport("User32.dll", EntryPoint = "SendMessage")]

        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);//发送消息,此重载方法可以直接给文本框赋值

 

下面是一个自动点击按钮和自动给文本框赋值的示例

 

   private void btnTest_Click(object sender, EventArgs e)

       

            #region 自动点击按钮

            //IntPtr cProcess = FindWindow(null, "测试Hook");

            //winHandle = FindWindowEx(cProcess, IntPtr.Zero, null, "点击显示界面");

            ////SendMessage(winHandle, 0xf5, 0, 0);//0xf5 BM_CLICK 按钮单击对应的消息--经过测试,直接使用0xf5无法实现点击按钮的功能    

            ////测试结果发现,如果想要实现单击按钮的功能,必须先按下鼠标左键,再抬起鼠标左键

            //SendMessage(winHandle, 0x201, IntPtr.Zero, IntPtr.Zero);//0x201 WM_LBUTTONDOWN 按下鼠标左键对应的消息

            //SendMessage(winHandle, 0x202, IntPtr.Zero, IntPtr.Zero);//0x201 WM_LBUTTONUP 抬起鼠标左键对应的消息

            #endregion

 

            #region 自动输入文本

            //IntPtr cProcess = FindWindow(null, "Test.txt - 记事本");

            //winHandle = FindWindowEx(cProcess, IntPtr.Zero, null, "");

 

            //IntPtr cProcess = FindWindow(null, "测试Hook");

            //winHandle = FindWindowEx(cProcess, IntPtr.Zero, null, null);

            ////winHandle = new IntPtr(0xE10F2);//这种方式是先通过Spy++找到控件的句柄,然后再使用这个句柄进行数据交互(此方法每次重启窗体,对应的句柄都会发生变化)

            //SendMessage(txtHandle, 0x0c, IntPtr.Zero, "ABCDEFGHIJKLMN");//0x0c wm_settext 给窗体设置文本     

            #endregion

       

 源代码:https://files.cnblogs.com/files/ckym/HookTest.rar

以上是关于SendMessage模拟点击按钮的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何模拟后台鼠标点击功能? SendMessage 和PostMessage 都无效。

C#-使用Win32_API的SendMessage实现指定窗口的模拟点击操作

在后台窗口中模拟鼠标点击

模拟鼠标点击

SendMessage, postmessage模拟鼠标左键

delphi 后台模拟鼠标点击