深入浅出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有什么区别?
答: 在大多数情况下,它们是等价的。WorkingDatabase是HostApplicationServices的属性,而Application.DocumentManager.MdiActiveDocument.Database是从文档管理器获取。推荐使用WorkingDatabase,因为它更简洁,且在大多数上下文中表现一致。
Q2: 什么时候需要用到除了WorkingDatabase之外的其他功能?
答:
- 需要操作外部文件时 →
FindFile - 需要网络功能时 →
GetRemoteFile/PutRemoteFile - 需要环境适配时 →
GetEnvironmentVariable、ReleaseYear - 需要中断长操作时 →
UserBreak
Q3: FindFile找不到文件怎么办?
答: FindFile找不到文件时会抛出异常。建议:
csharp
try
{
string path = hs.FindFile(fileName, null, false);
}
catch
{
// 文件未找到,执行备用逻辑
}
六、总结
HostApplicationServices是AutoCAD .NET开发中不可绕过的基础类。掌握它,你就掌握了:
✅ 访问当前数据库的"钥匙"
✅ 在AutoCAD支持路径中查找文件的"方法"
✅ 与云端交互的"能力"
✅ 获取系统信息的"窗口"
虽然日常开发中90%的场景只需要WorkingDatabase,但了解其他功能可以在遇到特定需求时让你游刃有余。
下期预告: 我们将深入讲解Database类的更多高级用法,包括图元遍历、扩展数据操作等。敬请期待!
欢迎Star和Fork!
💬 有任何问题或补充,欢迎在评论区留言交流!