本文章主要是使用C#对CAD进行开发时,需要用到的一些简单的、常规的方法介绍,仅供参考。
1、RealDwg辅助类:
public class HostServices : HostApplicationServices
{
public override string FindFile(string fileName, Database database, FindFileHint hint)
{
throw new NotImplementedException();
}
}
public class RealDwgHelper
{
///
/// 创建新的Database
///
/// dwg文件路径
///
public static Database CreateNewDatabase(string dwgPath)
{
// 初始化依赖环境
Initialize();
// 创建database实例
Database db = new Database(false, true);
if (dwgPath.ToLower().EndsWith("dwg"))
{
db.ReadDwgFile(dwgPath, FileShare.ReadWrite, true, "");
}
else if (dwgPath.ToLower().EndsWith("dxf"))
{
db.DxfIn(dwgPath, dwgPath + ".log");
}
else
{
Console.WriteLine("不支持的格式");
}
db.CloseInput(true);
return db;
}
public static bool IsInitialized;
public static void Initialize()
{
if (!IsInitialized)
{
IsInitialized = true;
// 初始化依赖环境
InitHashTable();
HostServices dwg = new HostServices();
RuntimeSystem.Initialize(dwg, 1033);
}
}
static public Hashtable mOverrides;
///
/// This initializes the hashtable with all the functions and properties which are overridden in the class.
/// It is using Reflection to achieve this.
///
static public void InitHashTable()
{
mOverrides = new Hashtable();
Type t = typeof(HostServices);
MethodInfo[] methods = t.GetMethods();
foreach (MethodInfo method in methods)
{
if (!mOverrides.Contains(method.Name) && method.DeclaringType == t)
mOverrides.Add(method.Name, true);
}
}
///
/// 创建新的Database
///
/// dwg文件地址
/// 是否需要修复文件,true需要修复
/// 返回一个Database
public static Database CreateNewDatabase(string dwgPath, bool needRecovery)
{
string fileName = dwgPath;
if (needRecovery)
{
var newPath = Path.ChangeExtension(dwgPath, "recover.dwg");
if (TextStyleRecovery(dwgPath, ref newPath))
{
fileName = newPath;
}
}
return CreateNewDatabase(fileName);
}
///
/// 修复字体样式
///
/// dwg文件地址
/// 修复后保存的文件地址
[System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions]
[System.Security.SecurityCritical]
public static bool TextStyleRecovery(string fileName, ref string newFileName)
{
try
{
using (var acDb = CreateNewDatabase(fileName))
{
acDb.TextStyleRecovery();
acDb.SaveAs(newFileName, acDb.OriginalFileVersion);
return true;
}
}
catch (AccessViolationException)
{
newFileName = Path.ChangeExtension(newFileName, "2.dwg");
File.Copy(fileName, newFileName, true);
return UsedRecoveryCommand(newFileName, 120000);
}
catch (System.Exception e)
{
return false;
}
}
///
/// 使用修复命令
///
/// 文件地址
/// 等待命令退出的时间(以毫秒为单位)。
/// 如果修复成功,则为true;否则为false;
public static bool UsedRecoveryCommand(string fileName, int milliseconds)
{
System.Diagnostics.Process accoreconsole = null;
try
{
var scrComment = new StringBuilder();
scrComment.AppendLine("secureload")
.AppendLine("0")
.AppendLine("netload")
.AppendLine(typeof(RealDwgHelper).Assembly.Location)
.AppendLine("CustomRecover");
var scrPath = Path.ChangeExtension(fileName, "recover.scr");
File.WriteAllText(scrPath, scrComment.ToString());
var args = $"/i \"{fileName}\" /s \"{scrPath}\" /l zh-CN";
var appPath = AutoCADHelper.FindConsoleApp(fileName);
accoreconsole = new System.Diagnostics.Process();
//accoreconsole.StartInfo.FileName = Common.GolbalSetter.AccoreConsoleAppPath;
accoreconsole.StartInfo.FileName = appPath;
accoreconsole.StartInfo.Arguments = args;
accoreconsole.StartInfo.CreateNoWindow = true;
accoreconsole.StartInfo.UseShellExecute = false;
accoreconsole.Start();
accoreconsole.WaitForExit(milliseconds);
if (!accoreconsole.HasExited)
{
accoreconsole.Kill();
return false;
}
else
{
return accoreconsole.ExitCode == 0;
}
}
catch (System.Exception e)
{
accoreconsole?.Kill();
Console.WriteLine("CADTool.RealDwg.RealDwgHelper.RecoveryCommand()发生异常!" + e.Message);
return false;
}
}
///
/// 创建新的Database
///
/// 文件路径
/// 超时时间(单位毫秒)
/// 返回一个Database实例对象
public static Database CreateNewDatabase(string fileName, int timeout)
{
if (timeout <= 0)
throw new ArgumentOutOfRangeException(nameof(timeout), "值小于等于0");
// 初始化依赖环境
Initialize();
// 创建database实例
Database db = new Database(false, true);
var cancellationTokenSource = new CancellationTokenSource(timeout);
try
{
var dbCreationTask = Task.Factory.StartNew(() => LoadFile(db, fileName), cancellationTokenSource.Token);
dbCreationTask.Wait();
}
catch (AggregateException e) when ((e.InnerException as TaskCanceledException) != null)
{
Console.WriteLine("Database初始化超时。");
}
catch (AggregateException e) when (e.InnerException != null)
{
throw e.InnerException;
}
catch
{
throw;
}
return db;
}
///
/// 载入文件
///
/// 数据库对象
/// 文件地址
private static void LoadFile(Database db, string dwgPath)
{
if (dwgPath.ToLower().EndsWith("dwg"))
{
db.ReadDwgFile(dwgPath, FileShare.ReadWrite, true, "");
}
else if (dwgPath.ToLower().EndsWith("dxf"))
{
db.DxfIn(dwgPath, dwgPath + ".log");
}
else
{
Console.WriteLine("不支持的格式");
}
db.CloseInput(true);
}
}
2、开发过程中,经常会使用到注册表中的某些数据:
public static class RegistryHelper
{
///
/// 打开AutoCAD注册表节点
///
/// 返回注册表节点
public static RegistryKey OpenAutoCADKey()
{
var keyAutoCad = Registry.CurrentUser.OpenSubKey("Software\\Autodesk\\AutoCAD");
return keyAutoCad;
}
///
/// 打开AutoCAD的指定版本号的注册表节点
/// 默认打开CurVer
///
/// 版本代号
/// 返回注册表节点
public static RegistryKey OpenAutoCADVersionKey(string version = null)
{
var acKey = OpenAutoCADKey();
if (acKey == null)
return null;
string subKeyName = version;
if (string.IsNullOrEmpty(version))
{
subKeyName = acKey.GetValue("CurVer").ToString();
if (string.IsNullOrEmpty(subKeyName))
return null;
}
return acKey.OpenSubKey(subKeyName);
}
///
/// 打开AutoCAD的默认版本下的指定语言的注册表节点
/// 默认打开CurVer
///
/// 语言代号
/// 返回注册表节点
public static RegistryKey OpenAutoCADLanguageKey(string language = null)
{
var acKey = OpenAutoCADVersionKey();
if (acKey == null)
return null;
string subKeyName = language;
if (string.IsNullOrEmpty(language))
{
subKeyName = acKey.GetValue("CurVer").ToString();
if (string.IsNullOrEmpty(subKeyName))
return null;
}
return acKey.OpenSubKey(subKeyName);
}
///
/// 打开AutoCAD的默认版本和语言下的Profiles注册表节点
///
/// 返回注册表节点
public static RegistryKey OpenAutoCADProfilesKey()
{
var acKey = OpenAutoCADLanguageKey();
if (acKey == null)
return null;
return acKey.OpenSubKey(@"Profiles\<<未命名配置>>");
}
///
/// 打开AutoCAD的默认Profiles下的General注册表节点
///
/// 返回注册表节点
public static RegistryKey OpenAutoCADProfilesGeneralKey()
{
var acKey = OpenAutoCADProfilesKey();
if (acKey == null)
return null;
return acKey.OpenSubKey("General");
}
}
3、本地安装多个版本的CAD程序时,可以通过下面的一些方法,控制程序使用最符合需求的CAD版本:
public static class AutoCADHelper
{
///
/// 获取AutoCAD支持文件搜索路径
///
/// 返回一个字符串
public static string GetSupportedPath()
{
var acKey = RegistryHelper.OpenAutoCADProfilesGeneralKey();
if (acKey == null)
return string.Empty;
return acKey.GetValue("ACAD", "").ToString();
}
///
/// 增加AutoCAD支持文件搜索路径
///
/// 需增加的路径
public static void AddAutoCADSupportedPath(string path)
{
var acKey = RegistryHelper.OpenAutoCADProfilesGeneralKey();
if (acKey == null)
return;
var acadValue = acKey.GetValue("ACAD", "").ToString();
var paths = acadValue.Split(';');
if (!paths.Contains(path))
{
acKey.SetValue("ACAD", acadValue + ";" + path);
}
}
///
/// 获取完整的搜索路径
///
/// 返回一个字符串
public static string GetSearchedFullName()
{
// 用户自定义环境变量Path
var userPathVariable = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
// 用分号拼接
return string.Format("{0};{1}", userPathVariable, GetSupportedPath());
}
///
/// 获取搜索路径地址数组
///
/// 返回一个字符串数组
public static string[] GetSearchedPaths()
{
var path = GetSearchedFullName();
if (string.IsNullOrEmpty(path))
return new string[0];
return path.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.Distinct()
.ToArray();
}
///
/// 获取所有AutoCAD程序的Roaming根目录
///
/// 返回所有AutoCAD程序的Roaming根目录
public static string[] GetAllRoamableRootFolder()
{
//增加固定目录作为备选目录
var spareFolders = new List();
spareFolders.Add("C:\\Program Files\\Autodesk\\AutoCAD 2014");
spareFolders.Add("C:\\Program Files\\Autodesk\\AutoCAD 2019");
var autocadKey = RegistryHelper.OpenAutoCADKey();
if (autocadKey == null || autocadKey.SubKeyCount == 0)
return spareFolders.ToArray();
var subkeyNames = autocadKey.GetSubKeyNames();
var folders = new List();
for (int i = 0; i < autocadKey.SubKeyCount; i++)
{
var versionKey = autocadKey.OpenSubKey(subkeyNames[i]);
var curver = versionKey.GetValue("CurVer")?.ToString();
if (curver == null) continue;
var curverKey = versionKey.OpenSubKey(curver);
var folder = curverKey.GetValue("RoamableRootFolder")?.ToString();
if (folder == null) continue;
folders.Add(folder);
}
if (folders.Count <= 0)
{
folders.AddRange(spareFolders);
}
return folders.ToArray();
}
///
/// 获取所有AutoCAD程序的安装目录
///
/// 返回所有AutoCAD程序的安装目录
public static Dictionary GetAllInstallationFolder()
{
var autocadKey = Registry.LocalMachine.OpenSubKey("Software\\Autodesk\\AutoCAD");
if (autocadKey == null || autocadKey.SubKeyCount == 0)
return null;
var subkeyNames = autocadKey.GetSubKeyNames();
var folders = new Dictionary();
for (int i = 0; i < autocadKey.SubKeyCount; i++)
{
var versionKey = autocadKey.OpenSubKey(subkeyNames[i]);
var folder = versionKey.OpenSubKey("InstalledProducts")?.GetValue("").ToString();
if (folder == null) continue;
folders.Add(subkeyNames[i], folder);
}
return folders;
}
///
/// 根据dwg版本号查找合适的accoreconsole.exe程序地址集合
///
/// dwg格式文件版本号
/// 返回accoreconsole.exe程序地址集合
public static string[] FindConsoleAppCollection(DwgVersion version)
{
var appPaths = GetAllInstallationFolder()?.ToDictionary(item => item.Key, item => Path.Combine(item.Value, "accoreconsole.exe"));
if (appPaths != null)
{
return appPaths.Where(item =>
SupportLatestVersion.ContainsKey(item.Key) &&
SupportLatestVersion[item.Key] >= version)
?.OrderByDescending(item => SupportLatestVersion[item.Key])
.Select(item => item.Value)
.ToArray();
}
return null;
}
///
/// 根据dwg版本号查找合适的accoreconsole.exe
///
/// dwg格式文件版本号
/// 返回accoreconsole.exe地址
public static string FindConsoleApp(DwgVersion version)
{
return FindConsoleAppCollection(version)?.First();
}
///
/// 查找最符合打开指定文件的accoreconsole.exe程序地址集合
///
/// 文件地址
/// 返回accoreconsole.exe程序地址集合
public static string[] FindConsoleAppCollection(string fileName)
{
var acversion = GetACVersion(fileName);
var dwgversion = ConvertDwgVersion(acversion);
return FindConsoleAppCollection(dwgversion);
}
///
/// 查找最符合打开指定文件的accoreconsole.exe程序
///
/// 文件地址
/// 返回accoreconsole.exe地址
public static string FindConsoleApp(string fileName)
{
return FindConsoleAppCollection(fileName)?.First();
}
///
/// AutoCAD各版本支持的最新dwg格式版本
///
public static Dictionary SupportLatestVersion = new Dictionary
{
{"R19.1", DwgVersion.AC1027 },
{"R23.0", DwgVersion.AC1032 }
};
///
/// 获取dwg文件版本号
///
/// 文件地址
/// 返回版本号字符串
public static string GetACVersion(string fileName)
{
using (var reader = new StreamReader(fileName))
{
var chars = new char[6];
reader.Read(chars, 0, chars.Length);
return new string(chars);
}
}
///
/// AC格式版本号转换为dwg格式版本号枚举值
///
/// ac版本号
/// 返回dwg格式版本号枚举值
public static DwgVersion ConvertDwgVersion(string acversion)
{
switch (acversion)
{
case "MC0.0 ": return DwgVersion.MC0To0;
case "AC1.2 ": return DwgVersion.AC1To2;
case "AC1.50": return DwgVersion.AC1To50;
case "AC2.10": return DwgVersion.AC2To10;
case "AC1002": return DwgVersion.AC1002;
case "AC1003": return DwgVersion.AC1003;
case "AC1004": return DwgVersion.AC1004;
case "AC1006": return DwgVersion.AC1006;
case "AC1009": return DwgVersion.AC1009;
case "AC1012": return DwgVersion.AC1012;
case "AC1014": return DwgVersion.AC1014;
case "AC1015": return DwgVersion.AC1015;
case "AC1018": return DwgVersion.AC1800;
case "AC1021": return DwgVersion.AC1021;
case "AC1024": return DwgVersion.AC1024;
case "AC1027": return DwgVersion.AC1027;
case "AC1032": return DwgVersion.AC1032;
default: return DwgVersion.Current;
}
}
#region 【Purge】命令扩展
///
/// 清理数据库
///
///
public static void DatabasePurge(this Database db)
{
using (var trans = db.TransactionManager.StartTransaction())
{
TablePurge(db.BlockTableId);
TablePurge(db.LayerTableId);
TablePurge(db.LinetypeTableId);
TablePurge(db.DimStyleTableId);
TablePurge(db.RegAppTableId);
TablePurge(db.TextStyleTableId);
trans.Commit();
}
}
///
/// 清理表数据
///
///
public static void TablePurge(ObjectId tableId)
{
var acdb = tableId.Database;
var acTrans = acdb.TransactionManager.TopTransaction;
if (acTrans == null)
{
throw new NullReferenceException("未开启事务, TransactionManager.TopTransaction is null");
}
var blockTable = (SymbolTable)acTrans.GetObject(tableId, OpenMode.ForRead);
var ids = new ObjectIdCollection();
foreach (ObjectId id in blockTable)
ids.Add(id);
acdb.Purge(ids);
foreach (ObjectId id in ids)
{
var obj = acTrans.GetObject(id, OpenMode.ForWrite);
obj.Erase();
}
}
///
/// 空间清理
///
///
///
public static void LayoutPurge(this Database acDb, string layoutName)
{
HostApplicationServices.WorkingDatabase = acDb;
var acLayoutMgr = LayoutManager.Current;
if (acLayoutMgr.LayoutExists(layoutName))
{
var layoutId = acLayoutMgr.GetLayoutId(layoutName);
using (var acTrans = acDb.TransactionManager.StartTransaction())
{
var acLayout = acTrans.GetObject(layoutId, OpenMode.ForRead) as Layout;
// 清理图元
if (acLayout.BlockTableRecordId.IsValid)
{
var acBlkRec = (BlockTableRecord)acTrans.GetObject(acLayout.BlockTableRecordId, OpenMode.ForRead);
foreach (var objId in acBlkRec)
{
var obj = acTrans.GetObject(objId, OpenMode.ForWrite);
obj.Erase();
}
}
acTrans.Commit();
}
}
else
{
acLayoutMgr.CreateLayout(layoutName);
}
}
#endregion
#region 【RECOVER】命令扩展
///
/// 字体样式修复
///
/// CAD数据库
/// 新的SHX字体文件
/// 新的大字体文件
public static void TextStyleRecovery(this Database acDb, string newFileName = "tssdeng.shx", string newBigFontFileName = "gbcbig.shx")
{
var names = new string[2];
var actions = new Action[]
{
new Action(tsr => tsr.FileName = newFileName),
new Action(tsr => tsr.BigFontFileName = newBigFontFileName)
};
// CAD支持的搜索路径
var searchPaths = GetSearchedPaths();
// 路径名称中的非法字符
var invalidChars = new String(System.IO.Path.GetInvalidFileNameChars());
var regFixFileName = new System.Text.RegularExpressions.Regex("[" + System.Text.RegularExpressions.Regex.Escape(invalidChars) + "]");
using (var trans = acDb.TransactionManager.StartTransaction())
{
// 字体样式表
using (var tst = (TextStyleTable)trans.GetObject(acDb.TextStyleTableId, OpenMode.ForRead))
{
foreach (var styleId in tst)
{
using (var DbObj = trans.GetObject(styleId, OpenMode.ForWrite))
{
TextStyleTableRecord tsr = DbObj as TextStyleTableRecord;
if (tsr is null)
{
continue;
}
names[0] = tsr.FileName;
names[1] = tsr.BigFontFileName;
for (int i = 0; i < names.Length; i++)
{
var name = names[i];
if (!string.IsNullOrEmpty(name) && !regFixFileName.IsMatch(name) && !name.ToLower().EndsWith(".ttf"))
{
if (!name.Contains('.')) name = name + ".shx";
if (searchPaths.All(p => !System.IO.File.Exists(System.IO.Path.Combine(p, name))))
{
actions[i](tsr);
}
}
}
if (tsr.FileName.ToLower().EndsWith(".ttf"))
{
string ttfFontPath = string.Format(@"{0}\fonts\{1}", System.Environment.GetEnvironmentVariable("WINDIR"), tsr.FileName);//系统FONT目录
if (!File.Exists(ttfFontPath))
{
tsr.FileName = "simfang.ttf";
}
}
else if (string.IsNullOrEmpty(tsr.FileName))
{
string fontName = tsr.Font.TypeFace;
System.Drawing.Font font = new System.Drawing.Font(fontName, 10);
if (font.Name != fontName)
{
tsr.FileName = "simfang.ttf";
}
}
}
}
}
trans.Commit();
}
}
#endregion
}