Revit二次开发——独立进程内读取、写入Revit文件

详解

不开启Revit,读取、写入Revit文件

要点:需要引入RevitNET.dll,RevitAddInUtility.dll和RevitAPI.dll三个dll到项目中

RevitAddInUtility.dll

此dll是Autodesk Revit 提供,用于方便开发者进行安装包的制作。使用此dll无需读注册表,可针对Revit版本,安装位置等信息的获取,也可以轻松的操控AddIn插件注册文件。此dll具体chm帮助文档,与此dll统一存在于Revit安装目录下。

RevitNET.dll

RevitNET.dll 在Revit安装目录下即可找到。此dll是Autodesk 用于开启一个简易版本 、无任何UI界面的小型化 Revit 所进行封装的。也就是使用此dll可做到无需启动Revit便可进行创建、修改、读取等等操作。并且因为是无界面操作,其效率要比Revit更高。其具体使用方法,如下代码所示。Navsiworks 即是使用了此dll。感兴趣的朋友可以进行尝试研究。

  	public class Program
    {
        static readonly string WorkPath = Path.GetDirectoryName(typeof(Program).Assembly.Location);

        static Program()
        {
            RevitCoreContext.Instance.Run();
        }

        /// <summary>
        /// Revit 内核必须加 STAThread 标签
        /// </summary>
        /// <param name="args"></param>

        [STAThread]
        static void Main(string[] args)
        {
            var app = RevitCoreContext.Instance.Application;

            // Todo ...

            var projectrTemplate = app.DefaultProjectTemplate;

            if (!File.Exists(projectrTemplate))
            {
                throw new FileNotFoundException("默认项目路径不存在 , 请指定 !");
            }

            var document = app.NewProjectDocument(projectrTemplate);

            if (document == null)
            {
                throw new InvalidOperationException();
            }

            // create wall demo ...

            var p1 = XYZ.Zero;

            var p2 = p1 + XYZ.BasisX * 10;

            var p3 = p2 + XYZ.BasisY * 10;

            var p4 = p1 + XYZ.BasisY * 10;

            var points = new XYZ[] { p1, p2, p3, p4 };

            document.Invoke(m =>
            {
                var level0 = document.QueryByType<Level>().OfType<Level>().FirstOrDefault(x => Math.Abs(x.Elevation - 0.0) <= 1e-7);

                if (level0 == null)
                {
                    level0 = Level.Create(document, 0);

                    document.Regenerate();
                }

                for (int i = 0; i < points.Length; i++)
                {
                    var a = points[i];

                    var b = i == points.Length - 1 ? points[0] : points[i + 1];

                    Wall.Create(document, Line.CreateBound(a, b), level0.Id, false);
                }
            });

            document.SaveAs(Path.Combine(WorkPath, "demowall.rvt"));

            RevitCoreContext.Instance.Stop();
        }
    }

 	public class RevitCoreContext
    {
        // 此路径为动态反射搜索路径 、 此路径可为任意路径(只要路径下有RevitNET 所需依赖项即可,完整依赖项可在 Naviswork 2016 下面找到)

        static readonly string[] Searchs = RevitProductUtility.GetAllInstalledRevitProducts().Select(x => x.InstallLocation).ToArray();

        static readonly object lockobj = new object();

        static RevitCoreContext _instance;

        private Product _product;

        public Application Application { get => _product.Application; }

        public static RevitCoreContext Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (lockobj)
                    {
                        if (_instance == null)
                        {
                            _instance = new RevitCoreContext();
                        }
                    }
                }

                return _instance;
            }
        }

        static RevitCoreContext()
        {
            AddEnvironmentPaths(Searchs);

            AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
        }

        public void Run()
        {
            _product = Product.GetInstalledProduct();

            var clientId = new ClientApplicationId(Guid.NewGuid(), "DotNet", "BIMAPI");

            // I am authorized by Autodesk to use this UI-less functionality. 必须是此字符串。 Autodesk 规定的.

            _product.Init(clientId, "I am authorized by Autodesk to use this UI-less functionality.");
        }

        public void Stop()
        {
            _product?.Exit();
        }

        static void AddEnvironmentPaths(params string[] paths)
        {
            var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty };

            var newPath = string.Join(System.IO.Path.PathSeparator.ToString(), path.Concat(paths));

            Environment.SetEnvironmentVariable("PATH", newPath);
        }

        private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
        {
            var assemblyName = new AssemblyName(args.Name);

            foreach (var item in Searchs)
            {
                var file = string.Format("{0}.dll", System.IO.Path.Combine(item, assemblyName.Name));

                if (File.Exists(file))
                {
                    return Assembly.LoadFile(file);
                }
            }

            return args.RequestingAssembly;
        }
    }
	public static class DocumentExtension
    {
        public static void Invoke(this Document doc, Action<Transaction> action, string name = "default")
        {
            using (var tr = new Transaction(doc, name))
            {
                tr.Start();

                action(tr);

                var status = tr.GetStatus();

                switch (status)
                {
                    case TransactionStatus.Started:
                        tr.Commit();
                        return;
                    case TransactionStatus.Committed:
                    case TransactionStatus.RolledBack:
                        return;
                    case TransactionStatus.Error:
                        tr.RollBack();
                        return;
                    default:
                        return;
                }
            }
        }

        public static TResult Invoke<TResult>(this Document doc, Func<Transaction, TResult> func, string name = "default")
        {
            using (var tr = new Transaction(doc, name))
            {
                tr.Start();

                var result = func(tr);

                var status = tr.GetStatus();
                switch (status)
                {
                    case TransactionStatus.Started:
                        tr.Commit();
                        return result;
                    case TransactionStatus.Committed:
                    case TransactionStatus.RolledBack:
                        return result;
                    case TransactionStatus.Error:
                        tr.RollBack();
                        return result;
                    default:
                        return result;
                }
            }
        }

        public static void InvokeSub(this Document doc, Action<SubTransaction> action)
        {
            using (var tr = new SubTransaction(doc))
            {
                tr.Start();

                action(tr);

                var status = tr.GetStatus();
                switch (status)
                {
                    case TransactionStatus.Started:
                        tr.Commit();
                        return;
                    case TransactionStatus.Committed:
                    case TransactionStatus.RolledBack:
                        break;
                    case TransactionStatus.Error:
                        tr.RollBack();
                        return;
                    default:
                        return;
                }
            }
        }


        public static TResult InvokeSub<TResult>(this Document doc, Func<SubTransaction, TResult> func)
        {
            using (var tr = new SubTransaction(doc))
            {
                tr.Start();

                var result = func(tr);

                var status = tr.GetStatus();
                switch (status)
                {
                    case TransactionStatus.Started:
                        tr.Commit();
                        return result;
                    case TransactionStatus.Committed:
                    case TransactionStatus.RolledBack:
                        return result;
                    case TransactionStatus.Error:
                        tr.RollBack();
                        return result;
                    default:
                        return result;
                }
            }
        }

        public static void InvokeGroup(this Document doc, Action<TransactionGroup> action, string name = "default")
        {
            using (var tr = new TransactionGroup(doc, name))
            {
                tr.Start();

                action(tr);

                var status = tr.GetStatus();
                switch (status)
                {
                    case TransactionStatus.Started:
                        tr.Commit();
                        return;
                    case TransactionStatus.Committed:
                    case TransactionStatus.RolledBack:
                        break;
                    case TransactionStatus.Error:
                        tr.RollBack();
                        return;
                    default:
                        return;
                }
            }
        }

        public static TResult InvokeGroup<TResult>(this Document doc, Func<TransactionGroup, TResult> func, string name = "default")
        {
            using (var tr = new TransactionGroup(doc, name))
            {
                tr.Start();

                var result = func(tr);

                var status = tr.GetStatus();
                switch (status)
                {
                    case TransactionStatus.Started:
                        tr.Commit();
                        return result;
                    case TransactionStatus.Committed:
                    case TransactionStatus.RolledBack:
                        return result;
                    case TransactionStatus.Error:
                        tr.RollBack();
                        return result;
                    default:
                        return result;
                }
            }
        }

        public static FilteredElementCollector QueryByType<T>(this Document doc) where T : Element
        {
            return new FilteredElementCollector(doc).OfClass(typeof(T));
        }
    }

问题总结

1,异常:SEHException: 外部组件发生异常

解决方法:Revit 内核必须加 STAThread 标签
RevitCoreContext.Instance.Run();

2,在Windows应用程序提示无法加载RevitNET.dll。

可能的原因是:目标平台为Any CPU,首先32位。
应该取消首先32位的对勾,或者更改为X64 。
目标框架注意与引用的项目一致(主要针对其它dll)

3,如何跨线程访问吗?

将RevitNet封装为一个控制台应用程序(Revit启动程序),然后通过命令行去启动Revit启动程序。
在启动过程可以传入参数。

Process process=new Process();//AppDomain.CurrentDomain.BaseDirectory +
process.StartInfo.FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory ,"ExportStart.exe");//执行的exe路径
process.StartInfo.UseShellExecute = false;//不显示shell
process.StartInfo.CreateNoWindow = true;//不创建窗口
process.StartInfo.RedirectStandardInput = true;//打开流输入
process.StartInfo.RedirectStandardOutput = true;//打开流输出
process.StartInfo.RedirectStandardError = true;//打开错误流
process.StartInfo.Arguments = "" + revitCmd + " \"" + filePathList.First() + "\"";//输入参数,多个参数使用空间分割,如果一个参数包含空格,使用""包括此参数
process.Start();//执行
string msg = process.StandardOutput.ReadToEnd();//读取输出
process.WaitForExit();//等待执行完成
process.Close();//结束
4,未能加载由“RevitNET.dll”导入的过程?

在这里插入图片描述
解决办法:
查看环境变量,将RevitInstallPath的path放至第一位。

5,不启动获取Revit文件的版本
		/// <summary>
        /// 获取Revit文件的版本
        /// </summary>
        /// <param name="path">文件路径</param>
        /// <returns></returns>
        public static string GetRevitVision(string path)
        {
            string revitVision = null;
            FileStream stream = new FileStream(path, FileMode.Open);

            int size = 1024 * 1024;
            byte[] bytes = new byte[size];       
            while (stream.Read(bytes, 0, size) > 0)
            {
                string str = Encoding.Unicode.GetString(bytes);

                string pattern = @"Autodesk Revit \d{4}";
                var match = Regex.Match(str, pattern);
                if (match.Success)
                {
                    revitVision = match.Value.Substring(match.Length - 4, 4);
                    //File.WriteAllText(@"D:\abc.txt", str);
                    break;
                }
            }
            return revitVision;
        }
6,程序运行目录(OutputDll)能否删除RevitAPI.dll或RevitAPIUI.dll等相关dll

可以,设置环境变量后,Revit会去Revit安装目录下查找以上dll。
注意:如果如果程序运行目录(OutputDll)存在Revit相关的dll,版本必须正确,否则会报错。(如果不能保证版本正确,不如将Revit相关dll全部删除)

7,RevitNet启动程序,能否取消RevitAddInUtility.dll的引用?

可以取消,RevitAddInUtility.dll 此dll的作用是用于获取Revit的安装目录,可以手动指定Revit的安装目录。从而取消此dll的引用。(完全可以不安装Revit,只复制Revit需要的dll,但区别那些dll是Revit需要的会很麻烦。不过可以将Revit安装目录下的文件全部复制到指定位置)

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
您好!对于Revit二次开发读取Excel,可以使用Revit API和.NET Framework中的相关功能来实现。 首先,您需要使用Revit API中的Document类来打开Revit项目文件。然后,可以使用.NET Framework中的System.IO和System.Data命名空间来读取Excel文件。 以下是一个简单的示例代码,演示了如何使用Revit API和.NET Framework来读取Excel文件中的数据: ```csharp using Autodesk.Revit.DB; using System; using System.Data; using System.Data.OleDb; namespace RevitExcelReader { public class ExcelReader { public DataTable ReadExcel(string filePath) { // 使用OleDb连接字符串打开Excel文件 string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1;'"; using (OleDbConnection connection = new OleDbConnection(connectionString)) { connection.Open(); // 获取Excel文件中的第一个工作表 DataTable dataTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null); string sheetName = dataTable.Rows[0]["TABLE_NAME"].ToString(); // 从工作表中查询数据 OleDbCommand command = new OleDbCommand("SELECT * FROM [" + sheetName + "]", connection); using (OleDbDataAdapter adapter = new OleDbDataAdapter(command)) { DataTable excelData = new DataTable(); adapter.Fill(excelData); return excelData; } } } } public class RevitExcelReader { public void ReadExcelInRevit(string excelFilePath) { // 获取当前打开Revit文档 Document document = Revit.ActiveUIDocument.Document; // 调用ExcelReader类读取Excel数据 ExcelReader excelReader = new ExcelReader(); DataTable excelData = excelReader.ReadExcel(excelFilePath); // 在Revit中处理您的Excel数据,例如创建元素、修改参数等 // 这里只打印Excel数据的内容到Revit的输出窗口 foreach (DataRow row in excelData.Rows) { foreach (DataColumn column in excelData.Columns) { string cellValue = row[column].ToString(); TaskDialog.Show("Revit Excel Reader", cellValue); } } } } } ``` 请注意,以上代码只是一个基本示例,并且可能需要根据您的具体需求进行修改和扩展。在实际开发中,您可能还需要处理Revit元素和Excel数据之间的映射关系,以便将数据正确地应用到Revit模型中。 希望这个示例能帮助到您!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值