C#-CAD二开相关

本文章主要是使用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
}

你可能感兴趣的:(c#)