ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 1135|回复: 0

[分享] EXCEL子窗体的HOOK方法(使用NativeWindow)

[复制链接]

TA的精华主题

TA的得分主题

发表于 2021-11-2 10:38 | 显示全部楼层 |阅读模式
写了个函数调试的中鼠标选取替代F9功能键的小插件,地址:https://club.excelhome.net/thread-1604722-1-1.html
要截取一些EXCEL子窗体的系统消息,发现NativeWindow在处理这些问题时挺方便,分享一下:

第一步,确定要截取消息的子窗口,获取其句柄,用原始的winapi函数FindWindowEx就行,这个编辑栏的类名是“EXCEL>”,可以通过spy++获取
image.png

第二步,句柄有了,但怎么截取这个窗口的鼠标和键盘消息呢?Winform下有个NativeWindow类:提供了窗口句柄和窗口过程的低级封装。利用NativeWindow不仅可以很方便的实现子窗体,同时可以捕获消息,重写窗口过程(默认处理函数WndProc),在捕获到消息后添加自己的代码就可以了。步骤大致如下:

1. 定义一个类Mywin继承NativeWindow,并在构造函数中使用AssignHandle方法将获取的句柄分配给此窗口。

2. 重载Wndproc方法,Wndproc有个引用类型的参数:ref Message m,通过m.Msg就可以得到所有刚刚指定的EditWinHwnd的窗体消息,截取对应的消息,加入自己的代码,在断点调试时可查看对应截取消息,如下图:

image.jpg


代码很少,如下(可忽略EXCELDNA部分,关键是下面红色字体的那个Mywin类):

using ExcelDna.Integration;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;

namespace ExcelFuncTool
{
    public class RF9
    {
        public static MyWin myWin;
        public static IntPtr ExcelAppHwnd = new IntPtr(((Excel.Application)ExcelDnaUtil.Application).Hwnd);

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [ExcelCommand(MenuName = "FuncTool", MenuText = "开启")]
        public static void StartHook()
        {
            myWin = new MyWin(FindWindowEx(ExcelAppHwnd, IntPtr.Zero, "EXCEL<", null));
        }

        [ExcelCommand(MenuName = "FuncTool", MenuText = "关闭")]
        public static void EndtHook()
        {
            myWin.ReleaseHandle();
        }
    }

    public class MyWin : NativeWindow
    {
        private IntPtr EditWinHwnd;
        private const int WM_LBUTTONUP = 0X202;
        private const int WM_LBUTTONDOWN = 513;
        public struct Point{public int x;public int y;}
        private Point mousePoint;

        public MyWin(IntPtr hwnd)
        {
            EditWinHwnd = hwnd;
            AssignHandle(EditWinHwnd);
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_LBUTTONDOWN:
                    mousePoint.x = (int)m.LParam & 0xffff;
                    mousePoint.y = (int)m.LParam >> 16;
                    break;

                case WM_LBUTTONUP:
                    mousePoint.x -= (int)m.LParam & 0xffff;
                    mousePoint.y -= (int)m.LParam >> 16;
                    if (Math.Abs(mousePoint.x) >= 10){SendKeys.Send("{F9}");}
                    break;
            }
            base.WndProc(ref m);
        }
    }
}


评分

2

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-21 19:30 , Processed in 0.029879 second(s), 14 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表