sendmessage发送模拟点击按钮没有反应

spxyoung 2015-09-21 05:37:00
使用
SendMessage(hwnd, 0x10, 0, 0)可以关闭按钮 //VM_CLOSE
但是使用,sendmessage(hwnd, 0xF5, 0, 0)却点击不了按钮。 //BM_CLICK
求助!!!
...全文
3025 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
spxyoung 2015-09-24
  • 打赏
  • 举报
回复
貌似解决了。谢谢各位的提醒! 解决方法:在sendmessage发送点击消息之前,要先调用SetFrontgroundWindow函数把按钮设置为最顶层, 然后还要sleep 2秒,最后发送sendmessage消息才能成功。 不过还是不明白为什么要sleep2秒才可以。。
spxyoung 2015-09-23
  • 打赏
  • 举报
回复
引用 20 楼 spxyoung 的回复:
[quote=引用 19 楼 qbilbo 的回复:] 如果你确定hwnd是对的,而且用鼠标点那个按钮也有响应的话,那么你可以尝试发送其它消息,比如:WM_LBUTTONDOWN之类的。 就比如你自己写了个程序,用的不是按钮的Click事件,而是用的MouseDown事件,那么给按钮送发BN_CLICK消息,肯定是没反应的。
也尝试过了, SendMessage(hwnd, 0x0201, 0, 0); SendMessage(hwnd, 0x0202, 0, 0); 也是不行的。[/quote] 而且,之前在没有创建子线程之前,使用sendmessage发送BM_CLICK消息是可以点击的。
spxyoung 2015-09-23
  • 打赏
  • 举报
回复
在主UI线程中创建子线程A。 子线程A创建system.threading.timer T1定时器,然后sleep等待。 定时器线程T1,获取主UI线程弹出的对话框的保存按钮,并sendmessage模拟点击。 所以接收sendmessage点击消息的应该是主UI线程。 那么应该与子线程A的sleep没有关系的。 然后在定时器线程T1中使用sendmessage VM_CLOSE消息是让按钮消失的,那么应该是消息可以被接收到, sendmessage 发送点击同步消息是有返回值的,为0,那么应该是消息有被处理过的。 可以为什么却没有点击的效果呢?还是不明白。。。
spxyoung 2015-09-23
  • 打赏
  • 举报
回复
引用 19 楼 qbilbo 的回复:
如果你确定hwnd是对的,而且用鼠标点那个按钮也有响应的话,那么你可以尝试发送其它消息,比如:WM_LBUTTONDOWN之类的。 就比如你自己写了个程序,用的不是按钮的Click事件,而是用的MouseDown事件,那么给按钮送发BN_CLICK消息,肯定是没反应的。
也尝试过了, SendMessage(hwnd, 0x0201, 0, 0); SendMessage(hwnd, 0x0202, 0, 0); 也是不行的。
qbilbo 2015-09-23
  • 打赏
  • 举报
回复
引用 21 楼 spxyoung 的回复:
在主UI线程中创建子线程A。 子线程A创建system.threading.timer T1定时器,然后sleep等待。 定时器线程T1,获取主UI线程弹出的对话框的保存按钮,并sendmessage模拟点击。 所以接收sendmessage点击消息的应该是主UI线程。 那么应该与子线程A的sleep没有关系的。 然后在定时器线程T1中使用sendmessage VM_CLOSE消息是让按钮消失的,那么应该是消息可以被接收到, sendmessage 发送点击同步消息是有返回值的,为0,那么应该是消息有被处理过的。 可以为什么却没有点击的效果呢?还是不明白。。。
好奇怪的设计....,既然是你是自己的程序,为什么要弄得这么复杂,还要SendMessage?直接调用xxx_Click不行? 不想要对话框不弹出不就好了,为什么还要弹出来了再自动关闭? 如果想要达到定时关闭或执行的效果,弄个Timer就行了,为什么要起线程,在新线程里再起个Timer,然后让线程阻塞,而不是直接在Ui线程起定时器? 定时器用System.Windows.Forms.Timer一样可以,对话框不会阻塞线程的,只是"阻塞"当前消息处理函数,Forms.Timer一样可以起到定时关闭或执行的效果。程序里弄那么多线程没必要。 就算按你这样设计,我试了一下,一样也可以,如果没达到点击的效果,还是在hwnd上找找原因吧... 主窗体代码:
public partial class frmMain : Form
    {
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hwnd, int msg, int p1, int p2);

        IntPtr buttonHwnd = IntPtr.Zero;
        frmDialog dialog;

        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(createTimer);
            thread.IsBackground = true;
            thread.Start();
        }

        private void btnDialog_Click(object sender, EventArgs e)
        {
            frmDialog f = new frmDialog();
            f.NewFormCreated += new EventHandler<NewFormCreatedEventArgs>(f_NewFormCreated);
            f.ShowDialog();
            buttonHwnd = IntPtr.Zero;
            f.NewFormCreated -= new EventHandler<NewFormCreatedEventArgs>(f_NewFormCreated);
        }

        private void f_NewFormCreated(object sender, NewFormCreatedEventArgs e)
        {
            buttonHwnd = e.ButtonHwnd;
        }

        private void createTimer()
        {
            System.Threading.Timer timer = new System.Threading.Timer(timerCallback, null, 0, 5000);
            
            Thread.Sleep(int.MaxValue);
        }

        private void timerCallback(object p)
        {
            if (buttonHwnd != IntPtr.Zero)
            {
                int r = SendMessage(buttonHwnd, 0xf5, 0, 0);

                MessageBox.Show(string.Format("发送消息成功,返回:{0}", r));
            }
        }

        //建议方案
        //仅提供思路及证明对话框不会阻塞线程,未考虑多个frmDialog实例及定时器回收等问题。
        private void btnShowDialog2_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
            timer.Interval = 5000;
            timer.Tick += new EventHandler(timer_Tick);
            timer.Enabled = true;
            dialog = new frmDialog();
            dialog.ShowDialog();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (dialog != null && !dialog.IsDisposed)
            {
                dialog.btnClose_Click(this, new EventArgs());
            }
        }
    }
对话框窗体代码:
public partial class frmDialog : Form
    {
        public frmDialog()
        {
            InitializeComponent();
        }

        public event EventHandler<NewFormCreatedEventArgs> NewFormCreated;
        
        public void btnClose_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
        }

        private void frmDialog_Load(object sender, EventArgs e)
        {
            if (NewFormCreated != null)
            {
                NewFormCreated(this, new NewFormCreatedEventArgs(btnClose.Handle));
            }
        }
    }
事件参数类(为了传递按句柄)代码:
public class NewFormCreatedEventArgs : EventArgs
    {
        public IntPtr ButtonHwnd
        {
            get;
            private set;
        }

        public NewFormCreatedEventArgs(IntPtr buttonHwnd)
        {
            ButtonHwnd = buttonHwnd;
        }
    }
qbilbo 2015-09-22
  • 打赏
  • 举报
回复
引用 3 楼 spxyoung 的回复:
不好意思,写的不清楚。 我的意思是:hwnd肯定是正确的,因为调用SendMessage(hwnd, VM_CLOSE, 0, 0)是可以关闭按钮。 但是sendmessage(hwnd, BM_CLICK, 0, 0)却点击不了按钮。 我是在新建的线程中,调用sendmessage的,和这个有关吗?
从这里看出,你的hwnd明显不对。具体看我一楼的回复。 在窗体程序里,不仅窗体有句柄,几乎每一个控件都有自己的句柄,它们都是Windows系统中所谓的Window,都有自己的消息处理函数。你能发送关闭消息关闭窗体,只能说明你的窗体句柄找对了,但这和关闭按钮的句柄对不对完全没关系。 PS1:关于对话框会线程阻塞的说法也是错误的,弹出对话框只是"阻塞"了对该消息处理的"子函数",另外会对键盘,鼠标消息做一些"额外"的处理。最简单的例子:Form1中弹出对话框Form2,在Form2中你是可以对Form1中的控件进行操作的,比如:改变TextBox中的Text属性,而不用Invoke。 PS2:SendMessage是同步的。它会等"对方"将消息处理完毕才返回。可以做一个实验,比如:A程序中的button1点击后会一个复杂的运算,需要10秒,那你用SendMessage向这个按钮发送点击消息,要10秒后才会返回。PostMessage才是异步的。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
引用 11 楼 spxyoung 的回复:
[quote=引用 10 楼 wawd74520 的回复:] [quote=引用 9 楼 spxyoung 的回复:] 想要sendmessage接收点击的窗体,是子线程A弹出的对话框,这个子线程A正在sleep,和这个有关吗? 因为线程A sleep了,所以没法处理消息?那有没有可以处理消息的线程挂起方法? 另外,子线程A弹出的对话框是在子线程A中?还是在子线程A创建的子线程中处理?
如果是弹窗 你的sendmessage 可能会卡在这。不往下执行。 你需要异步 或者开线程去操作。 还有 SendMessage(hwnd_bt, 0x0201, 0, 0); SendMessage(hwnd_bt, 0x0202, 0, 0); 是发送给按钮的句柄。 不是窗体。 [/quote] sendmessage为什么会卡住呢?是因为子线程A sleep了吗?还是其他原因?还是不懂要怎么处理。[/quote] 子线程A创建线程定时器T1处理,自己处在sleep状态等待。 线程定时器T1进行业务处理,弹出了对话框,创建线程定时器T2处理弹出的对话框。 线程定时器T2根据FindWindow、FindWindowEx等函数,找到要点击的按钮,然后sendmessage。 sendmessage是异步的,也没有卡住,有返回值为0。但是就没有没有点击操作(应该再弹出个对话框的)。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
另外应该是和线程相关的,因为之前在没有开子线程前,sendmessage发送点击消息是有反应的。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
引用 10 楼 wawd74520 的回复:
[quote=引用 9 楼 spxyoung 的回复:] 想要sendmessage接收点击的窗体,是子线程A弹出的对话框,这个子线程A正在sleep,和这个有关吗? 因为线程A sleep了,所以没法处理消息?那有没有可以处理消息的线程挂起方法? 另外,子线程A弹出的对话框是在子线程A中?还是在子线程A创建的子线程中处理?
如果是弹窗 你的sendmessage 可能会卡在这。不往下执行。 你需要异步 或者开线程去操作。 还有 SendMessage(hwnd_bt, 0x0201, 0, 0); SendMessage(hwnd_bt, 0x0202, 0, 0); 是发送给按钮的句柄。 不是窗体。 [/quote] sendmessage为什么会卡住呢?是因为子线程A sleep了吗?还是其他原因?还是不懂要怎么处理。
失落的神庙 2015-09-22
  • 打赏
  • 举报
回复
引用 9 楼 spxyoung 的回复:
想要sendmessage接收点击的窗体,是子线程A弹出的对话框,这个子线程A正在sleep,和这个有关吗? 因为线程A sleep了,所以没法处理消息?那有没有可以处理消息的线程挂起方法? 另外,子线程A弹出的对话框是在子线程A中?还是在子线程A创建的子线程中处理?
如果是弹窗 你的sendmessage 可能会卡在这。不往下执行。 你需要异步 或者开线程去操作。 还有 SendMessage(hwnd_bt, 0x0201, 0, 0); SendMessage(hwnd_bt, 0x0202, 0, 0); 是发送给按钮的句柄。 不是窗体。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
想要sendmessage接收点击的窗体,是子线程A弹出的对话框,这个子线程A正在sleep,和这个有关吗? 因为线程A sleep了,所以没法处理消息?那有没有可以处理消息的线程挂起方法? 另外,子线程A弹出的对话框是在子线程A中?还是在子线程A创建的子线程中处理?
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
使用 SendMessage(hwnd_bt, 0x0201, 0, 0); SendMessage(hwnd_bt, 0x0202, 0, 0); 还是不行。我在想是不是sendmessage其实已经把消息发出去了。 消息接收方没有处理?可是为什么VM_CLOSE消息就被处理了呢? 窗体就是弹出的对话框,有保存,取消按钮的。
失落的神庙 2015-09-22
  • 打赏
  • 举报
回复
 
            SendMessage(hwnd_bt, 0x0201, 0, 0);
            SendMessage(hwnd_bt, 0x0202, 0, 0);
这个是我的点击按钮消息
失落的神庙 2015-09-22
  • 打赏
  • 举报
回复
那也得看人家是什么窗体。腾讯的窗体就得点击窗体坐标。 而不是去找按钮。
mjp1234airen4385 2015-09-22
  • 打赏
  • 举报
回复
sendmessage(hwnd, BM_CLICK, 0, 0) 这个一般是发送鼠标按下,和鼠标弹起两个消息完成这个功能的。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
查了下,之前有人说或要sendmessage两次,或者在sendmessage之前先SendForegroundWindow,点击才会有效果。 两种方法都尝试了,还是不行。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
不好意思,写的不清楚。 我的意思是:hwnd肯定是正确的,因为调用SendMessage(hwnd, VM_CLOSE, 0, 0)是可以关闭按钮。 但是sendmessage(hwnd, BM_CLICK, 0, 0)却点击不了按钮。 我是在新建的线程中,调用sendmessage的,和这个有关吗?
qbilbo 2015-09-22
  • 打赏
  • 举报
回复
如果你确定hwnd是对的,而且用鼠标点那个按钮也有响应的话,那么你可以尝试发送其它消息,比如:WM_LBUTTONDOWN之类的。 就比如你自己写了个程序,用的不是按钮的Click事件,而是用的MouseDown事件,那么给按钮送发BN_CLICK消息,肯定是没反应的。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
对C#不是太懂。所以搞不明白sendmessage消息的处理与线程挂起有没有关系?还有弹出一个对话框是新建了一个线程吗?还有也不太懂的如何调试。
spxyoung 2015-09-22
  • 打赏
  • 举报
回复
引用 15 楼 Z65443344 的回复:
SendMessage(hwnd, 0x10, 0, 0)可以关闭按钮 关闭按钮? 按钮能够关闭? 关闭按钮是什么概念,你确定说的不是关闭窗体? 检查你的hwnd到底是什么玩意的句柄,是窗体的还是按钮的
我的hwnd是按钮的句柄,我只是为了测试,而试着把按钮这个“窗体”给关闭了。结果按钮真的不见了,从对话框中消失了。 所以应该不是按钮句柄的问题。
加载更多回复(4)

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧