如何在Revit API的Execute方法外访问Revit Application?
在C#中无需
commandData获取Revit Application对象的方法 刚好我也折腾过这个问题,给你捋清楚:首先得明确,Revit的Application对象不能直接new出来——它的构造函数是内部权限,Revit不允许外部代码自己实例化,必须从当前运行的Revit进程里获取,这和pyRevit的底层逻辑其实是一致的,只是pyRevit帮你封装了全局的__revit__对象,省去了手动获取的步骤。
下面分两种常见场景给你说具体操作:
场景1:在Revit插件的非Execute方法中(同一个插件项目内)
这是最常用的情况,你可以在Execute方法里把获取到的UIApplication/Application对象保存成静态全局变量,之后在任意方法里直接调用:
// 先定义一个静态类用来存全局上下文 public static class RevitGlobalContext { // 保存UIApplication和Application对象 public static UIApplication CurrentUiApp { get; set; } public static Application CurrentApp { get; set; } } // 在你的命令Execute方法里初始化 public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { // 从commandData里拿到实例并保存 RevitGlobalContext.CurrentUiApp = commandData.Application; RevitGlobalContext.CurrentApp = commandData.Application.Application; // 现在你可以在其他方法里直接用了 PrintRevitVersion(); return Result.Succeeded; } // 非Execute方法中使用 private void PrintRevitVersion() { string versionNumber = RevitGlobalContext.CurrentApp.VersionNumber; TaskDialog.Show("Revit版本", $"当前Revit版本:{versionNumber}"); }
这种方式简单可靠,因为插件的所有代码都运行在Revit的进程内,静态变量可以跨方法、跨类访问。
场景2:在外部独立程序中连接运行中的Revit
如果你的代码是独立的EXE工具,不是Revit插件,那需要通过Windows的Running Object Table(ROT)来找到正在运行的Revit实例,代码稍微复杂一点:
using System; using System.Diagnostics; using System.Runtime.InteropServices; using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.UI; public static class RevitInstanceHelper { // 导入Windows API函数 [DllImport("ole32.dll")] private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); [DllImport("ole32.dll")] private static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); public static Application GetRunningRevitApp() { // 先找正在运行的Revit进程 Process[] revitProcesses = Process.GetProcessesByName("Revit"); if (revitProcesses.Length == 0) throw new Exception("没有找到正在运行的Revit实例"); // 获取系统的Running Object Table GetRunningObjectTable(0, out IRunningObjectTable rot); rot.EnumRunning(out IEnumMoniker enumMoniker); enumMoniker.Reset(); IntPtr fetched = IntPtr.Zero; IMoniker[] moniker = new IMoniker[1]; // 遍历ROT里的对象,匹配Revit实例 while (enumMoniker.Next(1, moniker, fetched) == 0) { CreateBindCtx(0, out IBindCtx bindCtx); moniker[0].GetDisplayName(bindCtx, null, out string displayName); foreach (Process process in revitProcesses) { // 通过进程ID匹配Revit实例 if (displayName.Contains(process.Id.ToString())) { rot.GetObject(moniker[0], out object revitAppObj); return revitAppObj as Application; } } } throw new Exception("获取Revit实例失败"); } } // 使用方式 public static void Main() { try { Application revitApp = RevitInstanceHelper.GetRunningRevitApp(); string version = revitApp.VersionNumber; Console.WriteLine($"Revit版本号:{version}"); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
这种方式需要注意Revit版本的API兼容性,以及程序运行的权限(需要和Revit同权限级别)。
总结一下:不管哪种场景,都不能直接实例化Application,必须从已运行的Revit进程中获取——插件里用全局静态变量缓存是最方便的,外部工具则需要通过ROT来查找。
内容的提问来源于stack exchange,提问作者Arnaud




