在實際的Revit 二次開發項目中,經常需要與Revit 模型元素進行交互,那麼除了藉助於過濾器來獲取對應元素之外,直接拾取元素(PickObjects 函數)也是常見的一種方式。然而在多選操作中,如果不是熟手,很容易找不到多選完成的按鈕(其位置見圖1,確實顯得不起眼)。
在Windows中,提供一種Hook機制,中文裏常常被譯作“鉤子”或者“掛鉤”,可以把Hook理解爲Windows操作系統消息處理機制的一個平臺;應用程序可以通過設置Hook對某個進程或窗口進行監視,即:對特定事件“掛鉤”;一旦預定義特定事件發生,Windows操作系統即會向鉤子hook發送通知消息,這時,應用程序可進行響應。
接下來我們來使用鉤子自動實現點擊多選操作中“完成”的按鈕!
目錄
Step 1 、 Step 2、 Step 3、Step 4、Step 5、Step 6
Step 1
首先我們在NuGet 中安裝如圖的工具包(MouseKeyHook);
Step 2
安裝各種鉤子;
public static class WindowsHelper
{
[DllImport("user32.dll", CharSet = CharSet.None, ExactSpelling = false)]
public static extern bool EnumChildWindows(IntPtr hwndParent, CallBack lpEnumFunc, IntPtr lParam);
public delegate bool CallBack(IntPtr hwnd, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "SendMessageA")]
public static extern int SendMessage(IntPtr hwnd, uint wMsg, int wParam, int lParam);
}
Step 3
註冊鼠標和鍵盤監視事件,作者添加了一個右鍵的鼠標事件和一個空格的鍵盤事件;
public void Subscribe()
{
// Note: for the application hook, use the Hook.AppEvents() instead
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.KeyUp += GlobalHookKeyUpExt;
m_GlobalHook.MouseUpExt += GlobalHookMouseUpExt;
}
private void GlobalHookMouseUpExt(object sender, MouseEventExtArgs e)
{
if (e.Button == MouseButtons.Right) { CompleteMultiSelection(); }
}
private void GlobalHookKeyUpExt(object sender, KeyEventArgs e)
{
// 32 represent Space
if (e.KeyValue == 32) { CompleteMultiSelection(); }
}
Step 4
獲取Revit 主窗體下的所有句柄,找到“完成”按鈕併發送Click消息;
private void CompleteMultiSelection()
{
var rvtWindow = Autodesk.Windows.ComponentManager.ApplicationWindow;
var list = new List<IntPtr>();
var flag = WindowsHelper.EnumChildWindows(rvtWindow,
(hwnd, l) =>
{
StringBuilder windowText = new StringBuilder(200);
WindowsHelper.GetWindowText(hwnd, windowText, windowText.Capacity);
StringBuilder className = new StringBuilder(200);
WindowsHelper.GetClassName(hwnd, className, className.Capacity);
if ((windowText.ToString().Equals("完成", StringComparison.Ordinal) ||
windowText.ToString().Equals("Finish", StringComparison.Ordinal)) &&
className.ToString().Contains("Button"))
{
list.Add(hwnd);
return false;
}
return true;
}, new IntPtr(0));
var complete = list.FirstOrDefault();
WindowsHelper.SendMessage(complete, 245, 0, 0);
}
Step 5
註銷監視事件。
public void Unsubscribe()
{
m_GlobalHook.MouseUpExt -= GlobalHookMouseUpExt;
m_GlobalHook.KeyUp -= GlobalHookKeyUpExt;
//It is recommened to dispose it
m_GlobalHook.Dispose();
}
Step 6
功能測試!
問題
運行鉤子程序之後,圖2的區域的按鈕失效,無法關閉當前窗口,也無法實現ViewCube功能!
經多次嘗試,需右擊Revit模型顯示區域,點擊“取消”,即可恢復操作!
參考資料:
鉤子讓PickObjects功力大增—BIMCoder樑老師