深入浅出AutoCAD .NET二次开发:HostApplicationServices完全解析

深入浅出AutoCAD .NET二次开发:HostApplicationServices完全解析

掌握AutoCAD二次开发的"全局服务提供者"

写在前面

在AutoCAD .NET二次开发中,有一个类虽然不常被直接大篇幅讨论,但几乎每一个有用的插件都离不开它------那就是HostApplicationServices。很多初学者可能只是机械地使用HostApplicationServices.WorkingDatabase来获取数据库,却不知道这个类背后还藏着多少"宝藏功能"。

今天,我们就来全面剖析这个"熟悉又陌生"的类,让你从"只会用"进阶到"精通用"。

一、HostApplicationServices是什么?

1.1 官方定义

HostApplicationServices是Autodesk.AutoCAD.ApplicationServices命名空间下的一个抽象类 ,它继承自RXObject。简单来说,它是AutoCAD为开发者提供的运行时服务提供者

1.2 通俗理解

把AutoCAD想象成一个操作系统,HostApplicationServices就像是这个操作系统的系统服务层。它负责管理:

  • 当前正在编辑的图纸(WorkingDatabase)
  • 文件查找路径(FindFile)
  • 字体配置(FontFilePath、AlternateFontName)
  • 远程文件访问(GetRemoteFile、PutRemoteFile)
  • 环境变量(GetEnvironmentVariable)

与hostDatabase参数的区别:

很多朋友容易把HostApplicationServices和之前文章提到的hostDatabase参数搞混。这里简单对比一下:

对比项 HostApplicationServices hostDatabase参数
本质 一个 一个参数
作用 提供全局系统服务 指明嵌套对象的宿主数据库
使用方式 HostApplicationServices.WorkingDatabase 作为CompoundObjectId构造函数的参数
常见场景 获取数据库、查找文件 处理外部参照中的嵌套对象

记住:HostApplicationServices是服务提供者,hostDatabase只是一个数据库参数。

二、核心属性详解

2.1 WorkingDatabase(最重要,没有之一)

这是整个AutoCAD .NET开发中最常用的属性,没有它,你甚至无法开始任何数据库操作。

csharp 复制代码
// 基本用法:获取当前活动文档的数据库
Database db = HostApplicationServices.WorkingDatabase;

典型应用场景:

csharp 复制代码
[CommandMethod("CreateLine")]
public void CreateLine()
{
    // 获取当前数据库
    Database db = HostApplicationServices.WorkingDatabase;
    
    using (Transaction trans = db.TransactionManager.StartTransaction())
    {
        // 获取块表
        BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
        // 获取模型空间
        BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
        
        // 创建一条直线
        Line line = new Line(new Point3d(0, 0, 0), new Point3d(100, 100, 0));
        btr.AppendEntity(line);
        trans.AddNewlyCreatedDBObject(line, true);
        
        trans.Commit();
    }
}

注意事项: WorkingDatabase获取的是当前活动文档 的数据库。如果你的插件需要处理非活动文档,请使用DocumentManager来切换上下文。

2.2 Current(单例访问器)

csharp 复制代码
HostApplicationServices services = HostApplicationServices.Current;

由于HostApplicationServices是抽象类,你不能直接new它。通过Current静态属性获取当前正在使用的实例。

实际上,以下两种写法效果相同(WorkingDatabase是实例属性,但内部实现也是从Current获取):

csharp 复制代码
Database db1 = HostApplicationServices.WorkingDatabase;
Database db2 = HostApplicationServices.Current.WorkingDatabase;
// db1和db2指向同一个数据库

2.3 系统信息属性

这些属性帮助你获取AutoCAD的安装信息和运行环境:

csharp 复制代码
[CommandMethod("GetAutoCADInfo")]
public void GetAutoCADInfo()
{
    HostApplicationServices hs = HostApplicationServices.Current;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    
    ed.WriteMessage($"\n=== AutoCAD 环境信息 ===");
    ed.WriteMessage($"\n程序名称: {hs.Program}");
    ed.WriteMessage($"\n产品名称: {hs.Product}");
    ed.WriteMessage($"\n公司: {hs.Company}");
    ed.WriteMessage($"\n发布年份: {hs.ReleaseYear}");
    ed.WriteMessage($"\n版本号: {Application.Version}");
}

实际应用: 当你的插件需要针对不同AutoCAD版本做兼容处理时,这些信息就非常有用了。

2.4 字体相关属性

csharp 复制代码
// 获取/设置备用字体名称
string altFont = HostApplicationServices.Current.AlternateFontName;
// 获取字体映射文件路径
string fontMapPath = HostApplicationServices.Current.FontMapFilePath;

典型场景: 当打开的DWG文件中包含当前系统没有的字体时,AutoCAD会使用备用字体替代。你可以通过修改AlternateFontName来控制使用哪个备用字体。

2.5 路径相关属性

属性 说明 典型值(Windows)
LocalDirectory 本地用户目录 C:\Users\[用户名]\AppData\Local\Autodesk\...
RoamableRootFolder 可漫游根目录 C:\Users\[用户名]\AppData\Roaming\Autodesk\...
AllUsersFolder 所有用户共享目录 C:\ProgramData\Autodesk\...

这些路径在需要读写配置文件、缓存数据时非常有用。

三、核心方法详解

3.1 FindFile - 在支持路径中查找文件

这是除了WorkingDatabase之外最常用的方法。

csharp 复制代码
public string FindFile(string fileName, string databaseDirectory, bool findInDirectoriesOnly);

参数说明:

  • fileName:要查找的文件名(可以是相对路径)
  • databaseDirectory:查找的起始目录(通常传null或当前图纸目录)
  • findInDirectoriesOnly:是否只查找目录(通常传false

完整示例 - 查找字体文件:

csharp 复制代码
[CommandMethod("FindFontFile")]
public void FindFontFile()
{
    HostApplicationServices hs = HostApplicationServices.Current;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    
    string fontName = "simsun.ttf";
    
    try
    {
        // 在所有AutoCAD支持路径中查找字体文件
        string fullPath = hs.FindFile(fontName, 
                                       System.Environment.GetFolderPath(System.Environment.SpecialFolder.Windows),
                                       false);
        ed.WriteMessage($"\n✅ 找到字体文件: {fullPath}");
    }
    catch
    {
        ed.WriteMessage($"\n❌ 未找到字体文件: {fontName}");
    }
}

查找顺序: FindFile会按照AutoCAD的支持文件搜索路径 (Support File Search Paths)依次查找,这些路径可以在OP命令的"文件"选项卡中查看和配置。

3.2 GetRemoteFile / PutRemoteFile - 远程文件操作

这两个方法使得AutoCAD插件可以直接从网络获取或上传文件。

csharp 复制代码
// 下载远程文件到本地
public void GetRemoteFile(Uri url, string localFileName, bool ignoreCache);

// 上传本地文件到远程
public void PutRemoteFile(Uri url, string localFileName);

实战示例 - 从云端加载图块:

csharp 复制代码
[CommandMethod("LoadCloudBlock")]
public void LoadCloudBlock()
{
    HostApplicationServices hs = HostApplicationServices.Current;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    
    // 云端图块的URL(假设公司内部搭建了文件服务器)
    Uri remoteBlockUrl = new Uri("http://company-server/blocks/standard_door.dwg");
    string localTempPath = Path.GetTempFileName() + ".dwg";
    
    try
    {
        // 1. 下载云端图块
        ed.WriteMessage("\n⏳ 正在从云端下载图块...");
        hs.GetRemoteFile(remoteBlockUrl, localTempPath, true);
        
        // 2. 插入图块到当前图纸
        Database db = HostApplicationServices.WorkingDatabase;
        using (Transaction trans = db.TransactionManager.StartTransaction())
        {
            ObjectId blockId = db.Insert("STANDARD_DOOR", localTempPath, true);
            // 使用blockId插入块参照...
            trans.Commit();
        }
        
        ed.WriteMessage("\n✅ 云端图块加载成功!");
        
        // 3. 清理临时文件
        File.Delete(localTempPath);
    }
    catch (Exception ex)
    {
        ed.WriteMessage($"\n❌ 加载失败: {ex.Message}");
    }
}

3.3 IsUrl - URL判断

csharp 复制代码
bool isUrl = HostApplicationServices.Current.IsUrl("http://example.com/file.dwg"); // true
bool isUrl2 = HostApplicationServices.Current.IsUrl(@"C:\drawing.dwg"); // false

在编写同时支持本地和远程文件的代码时,这个判断非常有用。

3.4 GetEnvironmentVariable - 读取环境变量

csharp 复制代码
[CommandMethod("CheckAcadEnv")]
public void CheckAcadEnvironment()
{
    HostApplicationServices hs = HostApplicationServices.Current;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    
    // 读取AutoCAD相关环境变量
    string acadPath = hs.GetEnvironmentVariable("ACAD");           // AutoCAD支持路径
    string acadDrvPath = hs.GetEnvironmentVariable("ACADDRV");     // 驱动程序路径
    string tempPath = hs.GetEnvironmentVariable("TEMP");           // 临时目录
    
    ed.WriteMessage($"\nACAD环境变量: {acadPath ?? "(未设置)"}");
    ed.WriteMessage($"\nACADDRV: {acadDrvPath ?? "(未设置)"}");
    ed.WriteMessage($"\nTEMP: {tempPath ?? "(未设置)"}");
}

3.5 UserBreak - 检测用户中断

在进行耗时的批量操作时,可以定期检查用户是否按下了Ctrl+C,以便优雅地退出。

csharp 复制代码
[CommandMethod("BatchProcess")]
public void BatchProcess()
{
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    HostApplicationServices hs = HostApplicationServices.Current;
    
    for (int i = 0; i < 10000; i++)
    {
        // 每处理100个对象,检查一次用户是否按下Ctrl+C
        if (i % 100 == 0 && hs.UserBreak())
        {
            ed.WriteMessage($"\n⚠️ 用户中断操作,已处理 {i} 个对象");
            return;
        }
        
        // 执行实际的批量处理逻辑...
    }
    
    ed.WriteMessage("\n✅ 批量处理完成");
}

四、实战综合示例

下面是一个综合应用了多种HostApplicationServices功能的功能:从网络加载标准图块库并批量插入

csharp 复制代码
[CommandMethod("SmartLoadBlocks")]
public void SmartLoadBlocks()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    HostApplicationServices hs = HostApplicationServices.Current;
    Database db = hs.WorkingDatabase;
    
    // 块配置信息(名称和云端URL)
    var blocks = new Dictionary<string, string>
    {
        { "DOOR_A", "http://company-server/blocks/door_a.dwg" },
        { "DOOR_B", "http://company-server/blocks/door_b.dwg" },
        { "WINDOW", "http://company-server/blocks/window_std.dwg" },
    };
    
    // 创建临时目录
    string tempDir = Path.Combine(Path.GetTempPath(), "AutoCADBlockCache");
    Directory.CreateDirectory(tempDir);
    
    using (Transaction trans = db.TransactionManager.StartTransaction())
    {
        foreach (var block in blocks)
        {
            try
            {
                ed.WriteMessage($"\n⏳ 正在加载块: {block.Key}");
                
                // 1. 构建本地缓存路径
                string localPath = Path.Combine(tempDir, $"{block.Key}.dwg");
                
                // 2. 如果缓存不存在或需要更新,从网络下载
                if (!File.Exists(localPath))
                {
                    hs.GetRemoteFile(new Uri(block.Value), localPath, true);
                }
                
                // 3. 插入块到当前数据库
                ObjectId blockId = db.Insert(block.Key, localPath, true);
                ed.WriteMessage($" ✅");
            }
            catch (Exception ex)
            {
                ed.WriteMessage($" ❌ {ex.Message}");
            }
        }
        
        trans.Commit();
    }
    
    ed.WriteMessage($"\n\n✅ 所有块加载完成,临时文件位于: {tempDir}");
}

五、常见问题与最佳实践

Q1: WorkingDatabase和Application.DocumentManager.MdiActiveDocument.Database有什么区别?

答: 在大多数情况下,它们是等价的。WorkingDatabaseHostApplicationServices的属性,而Application.DocumentManager.MdiActiveDocument.Database是从文档管理器获取。推荐使用WorkingDatabase,因为它更简洁,且在大多数上下文中表现一致。

Q2: 什么时候需要用到除了WorkingDatabase之外的其他功能?

答:

  • 需要操作外部文件时 → FindFile
  • 需要网络功能时 → GetRemoteFile / PutRemoteFile
  • 需要环境适配时 → GetEnvironmentVariableReleaseYear
  • 需要中断长操作时 → UserBreak

Q3: FindFile找不到文件怎么办?

答: FindFile找不到文件时会抛出异常。建议:

csharp 复制代码
try
{
    string path = hs.FindFile(fileName, null, false);
}
catch
{
    // 文件未找到,执行备用逻辑
}

六、总结

HostApplicationServices是AutoCAD .NET开发中不可绕过的基础类。掌握它,你就掌握了:

✅ 访问当前数据库的"钥匙"

✅ 在AutoCAD支持路径中查找文件的"方法"

✅ 与云端交互的"能力"

✅ 获取系统信息的"窗口"

虽然日常开发中90%的场景只需要WorkingDatabase,但了解其他功能可以在遇到特定需求时让你游刃有余。


下期预告: 我们将深入讲解Database类的更多高级用法,包括图元遍历、扩展数据操作等。敬请期待!


📌 AutoCAD.EntityTools

欢迎Star和Fork!

💬 有任何问题或补充,欢迎在评论区留言交流!

相关推荐
AQin10122 小时前
【对比向】细算“成本”——Hive vs. Doris
大数据·数据库·hive·doris·实时数仓
承渊政道2 小时前
【MySQL数据库学习】MySQL基本查询(上)
linux·数据库·学习·mysql·bash·数据库开发·数据库系统
学计算机的计算基2 小时前
MySQL 性能调优面试复习:Explain、索引、慢查询、缓存和架构优化
java·数据库·笔记·mysql
运维行者_2 小时前
如何为您的企业选择最佳网络监控工具
大数据·运维·服务器·网络·数据库
caimouse2 小时前
Godot 4.7 内嵌 C# 模块切换到 .NET 9.0 编译指南
c#·.net·godot
刃神太酷啦2 小时前
MySQL 库表操作 +数据类型+ 基础概念全梳理----《Hello MySQL!》(2)
java·c语言·数据库·c++·vscode·mysql·adb
GIS数据转换器3 小时前
无人机车载巡检系统
大数据·数据库·人工智能·数据挖掘·数据分析·无人机
AOwhisky11 小时前
MySQL 学习笔记(第四期):SQL 语言之多表查询
linux·运维·网络·数据库·笔记·学习·mysql
小红卒11 小时前
mysql之udf提权
数据库·mysql·网络安全