You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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

火山引擎 最新活动