完善主體資料,免費贈送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一区二区三区| 国产福利一区二区在线视频 | 精品国产一区二区三区久久影院| 99精品一区二区三区无码吞精| 久久久国产一区二区三区 | 亚洲AV综合色区无码一区| 日韩精品福利视频一区二区三区| 曰韩人妻无码一区二区三区综合部| 日韩在线视频一区| 国产91精品一区二区麻豆网站 | 动漫精品专区一区二区三区不卡 | 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 亚洲一区二区三区写真| 无码人妻一区二区三区免费看| 一区二区高清视频在线观看| 欧美日韩一区二区成人午夜电影| 亚洲日本va午夜中文字幕一区| 久久精品国产一区二区三| 国产一区二区三区在线看| 熟女少妇丰满一区二区| 中文字幕久久亚洲一区 | 老湿机一区午夜精品免费福利| 日韩欧美一区二区三区免费观看| 竹菊影视欧美日韩一区二区三区四区五区 | 成人精品一区二区三区不卡免费看|