完善主體資料,免費贈送VIP會員!
    * 主體類型
    * 企業名稱
    * 信用代碼
    * 所在行業
    * 企業規模
    * 所在職位
    * 姓名
    * 所在行業
    * 學歷
    * 工作性質
    請先選擇行業
    您還可以選擇以下福利:
    行業福利,領完即止!

    下載app免費領取會員

    NULL

    ad.jpg

    Revit二次開發教程:Revit API Hook 之 攔截鼠標雙擊元素事件

    發布于:2019-06-22 17:55:56

    網友投稿

    更多

    HOOK(鉤子,掛鉤)是一種實現Windows平臺下類似于中斷的機制。HOOK機制允許應用程序攔截并處理Windows消息或指定事件,當指定的消息發出后,HOOK程序就可以在消息到達目標窗口之前將其捕獲,從而得到對消息的控制權,進而可以對該消息進行處理或修改,加入我們所需的功能。鉤子按使用范圍分,可分為線程鉤子和系統鉤子,其中,系統鉤子具有相當大的功能,幾乎可以實現對所有Windows消息的攔截、處理和監控。這項技術涉及到兩個重要的API,一個是SetWindowsHookEx,安裝鉤子;另一個是UnHookWindowsHookEx,卸載鉤子。


    本文使用的HOOK API技術,是指截獲系統或進程對某個API函數的調用,使得API的執行流程轉向我們指定的代碼段,從而實現我們所需的功能。Windows下的每個進程均擁有自己的地址空間,并且進程只能調用其地址空間內的函數,因此HOOK API尤為關鍵的一步是,設法將自己的代碼段注入到目標進程中,才能進一步實現對該進程調用的API進行攔截。然而微軟并沒有提供HOOK API的調用接口,這就需要開發者自己編程實現。

     一般來說,HOOK API由兩個組成部分,即實現HOOK API的DLL文件,和啟動注入的主調程序。本文采用HOOK API 技術對剪切板相關的API 函數進行攔截,從而實現對剪切板內容的監控功能,同樣使用該技術實現進程防終止功能。其中DLL文件支持HOOK API的實現,而主調客戶端程序將在初始化時把帶有HOOK API功能的DLL隨著鼠標鉤子的加載注入到目標進程中,這里的鼠標鉤子屬于系統鉤子。

    下面介紹在Revit中,如何應用Hook對鼠標雙擊元素事件進行攔截。


    第一步,先封裝HookBase抽象類,因所有Hook的都具有注冊、卸載邏輯,且注冊、卸載大同小易。如下

    public abstract class HookBase : IHook

        {

            private static Dictionary<int, IHook> m_Hooks;

            private IntPtr m_ProcessId;

            private int m_ThreadId;

            private HookType m_HookType;

            private HookProc m_HookProc; 

            protected internal int m_HookId; 

            static HookBase(){

                m_Hooks = new Dictionary<int, IHook>();

            } 

            private HookBase(HookType hookType){

                m_HookType = hookType;

                m_HookProc = HookProc;

            } 

            protected HookBase(IntPtr processId, HookType hookType):this(hookType){

                m_ProcessId = processId;

                if (m_ProcessId == IntPtr.Zero)

                {

                    m_ProcessId = HookHelper.GetCurrentProcessId();

                }

            } 

            protected HookBase(int threadId, HookType hookType):this(hookType){

                m_ThreadId = threadId;

                if (m_ThreadId == 0)

                {

                    m_ThreadId = HookHelper.GetCurrentThreadId();

                }

            } 

            public void Install(){

                if (m_ThreadId != 0)

                {

                    m_HookId = HookHelper.SetWindowsHookEx(m_HookType, m_HookProc, IntPtr.Zero, m_ThreadId);

                }

                else

                {

                    if (m_ProcessId == IntPtr.Zero)

                    {

                        return;

                    }

                    m_HookId = HookHelper.SetWindowsHookEx(m_HookType, m_HookProc, m_ProcessId,0);

                }


                if (m_HookId == 0)

                {

                    return;

                }


                if (!m_Hooks.ContainsKey(m_HookId))

                {

                    m_Hooks.Add(m_HookId, this);

                }

            } 

            public void Uninstall()

            {

                if (m_HookId == 0)

                {

                    return;

                }


                var flag = HookHelper.UnhookWindowsHookEx(m_HookId);

                if (flag)

                {

                    if (m_Hooks.Remove(m_HookId))

                    {

                        m_HookId = 0;

                    }

                }

            } 

            protected abstract int HookProc(int nCode, IntPtr wParam, IntPtr lParam);


    第二步 ,因鼠標Hook分為線程鼠標Hook以及全局鼠標Hook兩種,僅注冊方式有點區別。為使用方便,將其封裝為事件注冊方式。如下

    public abstract class MouseHookBase : HookBase

        {

            protected MouseHookBase(IntPtr processId)

                : base(processId, HookType.WH_MOUSE_LL)

            {


            }


            protected MouseHookBase(int threadId)

                : base(threadId, HookType.WH_MOUSE)

            {


            }

            public event HookHandler<MouseEventArgs> MouseDoubleClick;

            public event HookHandler<MouseEventArgs> MouseMove;

            public event HookHandler<MouseEventArgs> MouseDown;

            public event HookHandler<MouseEventArgs> MouseUp;


            protected override int HookProc(int nCode, IntPtr wParam, IntPtr lParam)

            {

                if (nCode < 0)

                {

                    return HookHelper.CallNextHookEx(m_HookId, nCode, wParam, lParam);

                }


                var mouseMsg = (MouseMessage)wParam.ToInt32();

                var mouseHookStruct = lParam.ToStruct<MOUSEHOOKSTRUCT>();


                var button = this.GetMouseButtons(mouseMsg);


                switch (mouseMsg)

                {

                    case MouseMessage.WM_LBUTTONDOWN:

                    case MouseMessage.WM_RBUTTONDOWN:

                    case MouseMessage.WM_MBUTTONDOWN:


                        return this.OnRaiseMouseDown(button, 1, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData);


                    case MouseMessage.WM_LBUTTONUP:

                    case MouseMessage.WM_MBUTTONUP:

                    case MouseMessage.WM_RBUTTONUP:


                        return this.OnRaiseMouseUp(button, 1, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData);


                    case MouseMessage.WM_LBUTTONDBLCLK:

                    case MouseMessage.WM_RBUTTONDBLCLK:

                    case MouseMessage.WM_MBUTTONDBLCLK:


                        return this.OnRaiseMouseDoubleClick(button, 2, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData);


                    case MouseMessage.WM_MOUSEMOVE:


                        return this.OnRaiseMouseMove(MouseButtons.None, 0, mouseHookStruct.pt.X, mouseHookStruct.pt.Y, mouseHookStruct.mouseData);

                    default:

                        return HookHelper.CallNextHookEx(m_HookId, nCode, wParam, lParam);

                }

            }


            private MouseButtons GetMouseButtons(MouseMessage mouseMsg)

            {

                MouseButtons result = MouseButtons.None;

                switch (mouseMsg)

                {

                    case MouseMessage.WM_LBUTTONDBLCLK:

                    case MouseMessage.WM_LBUTTONDOWN:

                    case MouseMessage.WM_LBUTTONUP:

                        result = MouseButtons.Left;

                        break;

                    case MouseMessage.WM_MBUTTONDBLCLK:

                    case MouseMessage.WM_MBUTTONDOWN:

                    case MouseMessage.WM_MBUTTONUP:

                        result = MouseButtons.Middle;

                        break;

                    case MouseMessage.WM_RBUTTONDBLCLK:

                    case MouseMessage.WM_RBUTTONDOWN:

                    case MouseMessage.WM_RBUTTONUP:

                        result = MouseButtons.Right;

                        break;

                }

                return result;

            }


            private int OnRaiseMouseDoubleClick(MouseButtons button, int clicks, int x, int y, intdelta)

            {

                if (this.MouseDoubleClick != null)

                {

                    return this.MouseDoubleClick(this, new MouseEventArgs(button, clicks, x, y, delta));

                }

                return 0;

            }


            private int OnRaiseMouseDown(MouseButtons button, int clicks, int x, int y, int delta)

            {

                if (this.MouseDown != null)

                {

                    return this.MouseDown(this, new MouseEventArgs(button, clicks, x, y, delta));

                }

                return 0;

            }


            private int OnRaiseMouseUp(MouseButtons button, int clicks, int x, int y, int delta)

            {

                if (this.MouseUp != null)

                {

                    return this.MouseUp(this, new MouseEventArgs(button, clicks, x, y, delta));

                }

                return 0;

            }


            private int OnRaiseMouseMove(MouseButtons button, int clicks, int x, int y, int delta)

            {

                if (this.MouseMove != null)

                {

                    return this.MouseMove(this, new MouseEventArgs(button, clicks, x, y, delta));

                }

                return 0;

            }

    }

    第三步,依次實現線程鼠標Hook以及全局鼠標Hook.

     public class MouseHook : MouseHookBase{

            public MouseHook(int threadId = 0)

                : base(threadId)

            { 

            }

        }

        public class GlobalMouseHook : MouseHookBase

        {

            public GlobalMouseHook(IntPtr processId)

                : base(processId)

            { 

            }

     }

    第四步,有了鼠標Hook,我們如果在Revit內使用并且攔截鼠標雙擊元素事件呢?我們繼續封裝一個元素監控類 ,如下:

    public class ElementMonitor

        {

            private static ElementMonitor m_Instance;

            private MouseHook m_MouseHook;

            private bool m_IsMonitor;

            private UIApplication m_UIApplication;


            private ElementMonitor(UIApplication uiApp)

            {

                m_Instance = this;

                m_UIApplication = uiApp;


                m_MouseHook = new MouseHook();

                m_MouseHook.Install();


                m_MouseHook.MouseDoubleClick += OnRaiseMouseDoubleClick;

            }


            /// <summary>

            /// 靜態實例,可在入口類判斷此實例是否為null,防止重復注冊.

            /// </summary>

            public static ElementMonitor Instance

            {

                get

                {

                    return m_Instance;

                }

            }


            /// <summary>

            /// 當鼠標雙擊元素時觸發此事件.

            /// </summary>

            public event HookHandler<DoubleClickElementEventArgs> DoubleClickElement;


            /// <summary>

            /// 注冊元素監控,并指定是否立即監控.

            /// </summary>

            public static void Register(UIApplication uiApp, bool immediatelyMonitor = true)

            {

                if (uiApp == null)

                {

                    throw new ArgumentNullException(nameof(uiApp));

                }


                new ElementMonitor(uiApp)

                {

                    m_IsMonitor = immediatelyMonitor

                };

            }


            /// <summary>

            /// 注冊元素監控,并指定是否立即監控.

            /// </summary>

            public static void Register(UIControlledApplication uiControllApp, bool immediatelyMonitor = true)

            {

                if (uiControllApp == null)

                {

                    throw new ArgumentNullException(nameof(uiControllApp));

                }


                var flag = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod;


                var uiApp = (UIApplication)uiControllApp.GetType().InvokeMember("getUIApplication", flag, Type.DefaultBinder, uiControllApp, null);


                Register(uiApp, immediatelyMonitor);

            }


            /// <summary>

            /// 返回1,則攔截鼠標消息,返回0則傳遞給真正消息接收者.

            /// </summary>

            private int OnRaiseMouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)

            {

                if (!m_IsMonitor || e.Button != MouseButtons.Left || e.Clicks != 2)

                {

                    return 0;

                }


                var uiDoc = m_UIApplication.ActiveUIDocument;


                if (uiDoc == null)

                {

                    return 0;

                }


                var elemIds = uiDoc.Selection.GetElementIds();


                if (elemIds.Count == 1)

                {

                    var elem = uiDoc.Document.GetElement(elemIds.First());


                    if (elem == null)

                    {

                        return 0;

                    } 

                    if (this.DoubleClickElement == null)

                    {

                        return 0;

                    } 

                    return this.DoubleClickElement(this, new DoubleClickElementEventArgs(elem));

                }


                return 0;

            }

        }

    第五步,調用測試,如下

    [Transaction(TransactionMode.Manual)]

        public class MouseHookTest : IExternalCommand

        {

            Result IExternalCommand.Execute(ExternalCommandData commandData, ref string message, ElementSet elements)

            {

                if (ElementMonitor.Instance == null)

                {

                    ElementMonitor.Register(commandData.Application);

                }


                ElementMonitor.Instance.DoubleClickElement += OnRaiseDoubleClickElement;


                return Result.Succeeded;

            }


            private int OnRaiseDoubleClickElement(object sender, DoubleClickElementEventArgs e)

            {

                if (e.Element == null)

                {

                    return 0;

                }


                System.Windows.Forms.MessageBox.Show(string.Format("雙擊擊元素Id: {0}", e.Element.Id)); 

                return 1;


            }

        }



    本文版權歸腿腿教學網及原創作者所有,未經授權,謝絕轉載。

    未標題-1.jpg

    上一篇:Revit二次開發教程:Revit族參數可見性設置

    下一篇:Revit二次開發教程:注冊Revit插件

    主站蜘蛛池模板: 久久精品成人一区二区三区| 精品一区二区三区免费毛片| 中文字幕人妻丝袜乱一区三区| 一色一伦一区二区三区| 中文乱码字幕高清一区二区| 性色AV 一区二区三区| 日本无卡码免费一区二区三区| 丝袜美腿一区二区三区| 亚洲日本va午夜中文字幕一区| 精品无人区一区二区三区| 国产成人精品无码一区二区 | 无码精品一区二区三区| 亚洲AV无码一区二区三区系列| 丝袜人妻一区二区三区网站| 中文字幕一区二区三区永久 | 精品无码国产一区二区三区51安| 日本一区二区在线| 国产免费一区二区三区| 日本一区二三区好的精华液| 精品福利一区二区三区免费视频| 久久久国产精品亚洲一区 | 国产在线精品一区在线观看| 国产女人乱人伦精品一区二区| 无码一区二区三区中文字幕| 日本视频一区二区三区| 亚洲永久无码3D动漫一区| 一区二区三区影院| 久久精品一区二区三区中文字幕| 亚洲爆乳无码一区二区三区| 久久se精品一区二区国产| 亚洲av无码一区二区三区不卡| 人体内射精一区二区三区| 亚洲一区在线视频观看| 国产在线第一区二区三区| 一区二区国产在线观看| 中文字幕色AV一区二区三区| 麻豆天美国产一区在线播放| 人妻互换精品一区二区| 波多野结衣电影区一区二区三区 | 日韩电影一区二区| 蜜臀AV在线播放一区二区三区|