cad.net 重置cad之后創建文檔出錯,攔截cad致命錯誤


說明

如果重置過一次Acad08,然后直接創建文檔,那么你會得到一個致命錯誤.

然后你會重啟cad,再創建文件,這個時候就不會產生致命錯誤.

這個不起眼的bug似乎沒有人去理它..

直到我制作了文檔欄,在文檔欄上面創建文檔,然后彈出了一個致命錯誤...

為了修復這個致命錯誤,我嘗試了以下幾個步驟:

方案一:自寫模板

var lastTemplate = CadSystem.Getvar("LastTemplate");//最后使用的模板
if (!File.Exists(lastTemplate))
{
    var templatePath = CadSystem.Getvar("TemplatePath");//模板路徑
    lastTemplate = templatePath + "\\acad.dwt";//設置默認選中
}

var sa = new Autodesk.AutoCAD.Windows.OpenFileDialog("選擇模板", lastTemplate, "dwt", "",
    OpenFileDialogFlags.AllowAnyExtension | OpenFileDialogFlags.ForceDefaultFolder);
if (sa.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
    //System.Runtime.InteropServices.COMException:“內部應用程序出錯。”
    Acap.DocumentManager.Add(sa.Filename);
}

方案二:發送命令

然后我分析了一下,用 Acap.DocumentManager.Add() 創建文檔是愚蠢的(后來證明並不...)

正常也應該直接調用cad自帶的方式,畢竟官方的方法可以避免錯誤...

於是乎,我改用了

Acap.DocumentManager.MdiActiveDocument.SendStringToExecute("_new\n", false, true, true);
//第二個參數true時,命令必須有CommandFlags.Session,否則容易致命錯誤

方案三:Win32API發送消息

但是遇到一個尷尬的事情,沒有文檔的時候不存在 MdiActiveDocument 此時發送新建命令是錯誤的...

然后e大協助了我,利用了win32API的方式來處理:

//下面兩個值都行的
WinApi.SendMessage(Acap.MainWindow.Handle, (int)MsgType.WM_COMMAND, (IntPtr)18, IntPtr.Zero);//qnew
WinApi.SendMessage(Acap.MainWindow.Handle, (int)MsgType.WM_COMMAND, (IntPtr)57600, IntPtr.Zero);//new

子類化攔截

當我實現了方案三的時候,由於實現過<子類化窗口>來攔截cad的消息,突然間攔截了一個錯誤: Autodesk.AutoCAD.Runtime.Exception:“eFilerError”

而整個步驟就是: 重置cad--創建cad文檔(ctrl+n)--截獲了這個錯誤,非常的干脆利落得到.

img

封裝

子類化cad窗體--攔截cad創建文檔命令,如果不回調,就相當ban掉了命令,同時等價於攔截了致命錯誤,賊好玩:

using System;
using System.Windows.Forms;

namespace JoinBoxCurrency.Windows
{
    public class NativeCallProc : NativeWindow, IDisposable
    {
        Func<Message, bool> _WndProcAction;

        /// <summary>
        /// 窗口控件子類化,聲明一定要寫到類成員上,否則導致GC不確定的釋放,從而觸發析構
        /// </summary>
        /// <param name="intPtr">窗體句柄</param>
        public NativeCallProc(IntPtr intPtr)
        {
            this.AssignHandle(intPtr);
        }

        /// <summary>
        /// 消息循環攔截的委托
        /// </summary>
        /// <param name="WndProc">消息,true不攔截</param>
        public void WndProc(Func<Message, bool> WndProc)
        {
            _WndProcAction = WndProc;
        }

        /// <summary>
        /// 消息循環
        /// </summary>
        /// <param name="msg"></param>
        protected override void WndProc(ref Message msg)
        {
            if (_WndProcAction == null)
            {
                return;
            }
            if (_WndProcAction.Invoke(msg))
            {
                base.WndProc(ref msg);//回調函數
            }
        }

        #region Dispose
        public bool Disposed { private set; get; } = false;

        /// <summary>
        /// 顯式調用Dispose方法,繼承IDisposable
        /// </summary>
        public void Dispose()
        {
            //由手動釋放
            Dispose(true);
            //通知垃圾回收機制不再調用終結器(析構器)_跑了這里就不會跑析構函數了
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 析構函數,以備忘記了顯式調用Dispose方法
        /// </summary>
        ~NativeCallProc()
        {
            //由系統釋放
            Dispose(false);
        }

        /// <summary>
        /// 釋放
        /// </summary>
        /// <param name="ing"></param>
        protected virtual void Dispose(bool ing)
        {
            if (Disposed)
            {
                //不重復釋放
                return;
            }
            //讓類型知道自己已經被釋放
            Disposed = true;

            //釋放占用窗體的句柄
            ReleaseHandle();
        }
        #endregion
    }
}

調用

using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
using JoinBoxCurrency.Windows;
public class Anchor{  
//子類化 聲明一定要放這里哦,不然GC會釋放掉哦!
NativeCallProc _AcadCallWProc;
    
public Anchor()
{
    //Acad主窗口的句柄   
    _AcadCallWProc = new NativeCallProc(Acap.MainWindow.Handle);

    //57600_new || 18_qnew 對應cad命令
    IntPtr _new = (IntPtr)57600;
    IntPtr _qnew = (IntPtr)18;
    IntPtr _chongZhi = (IntPtr)0x0001e100;//重置之后ctrl+n取得的

    _AcadCallWProc.WndProc(m =>
    {
        try
        {
            var msg = (WM)m.Msg;
            if (msg == WM.WM_COMMAND)
            {
                //攔截原生的發送方式,因其(發送消息)導致致命錯誤,調用我自己寫的新建文檔函數
                //WinApi.SendMessage(Acap.MainWindow.Handle, (int)MsgType.WM_COMMAND, (IntPtr)18, IntPtr.Zero);//qnew
                //WinApi.SendMessage(Acap.MainWindow.Handle, (int)MsgType.WM_COMMAND, (IntPtr)57600, IntPtr.Zero);//new
                if (m.WParam == _new || m.WParam == _qnew || m.WParam == _chongZhi)
                {                                     
                    this._DocWindow.Qnew();
                    // Qnew見
                    // https://gitee.com/inspirefunction/CadLabelBar/blob/master/src/LabelBarStandard/View/DocWindow.xaml.cs
                    // 之后是阻止cad接收win32的ctrl+n消息,需要鍵盤鈎子hook
                    return false;//不回調,禁止了命令
                }
            }
            AutoDocs.SyncForm?.Loaded(); //為什么有這句?見 https://www.cnblogs.com/JJBox/p/14179921.html
        }
        catch //cad崩潰的時候會觸發
        {
           Debugger.Break();
        }
        return true;//可回調的都進入這里
    });
}}

注冊表修補

但是截獲了又該如何處理呢?

從"重置"二字中得知,cad將當前配置放在注冊表中,

而重置之后不關閉cad直接去獲取注冊表,是一份殘缺的注冊表.

而重置之后重啟cad,cad會自動補充完成這份注冊表,是一份完整的注冊表.

對比兩份注冊表就可以得知需要添加一些什么注冊表到內部..

如果你有興趣一個個嘗試刪除,你會得到某個注冊表才是必須的,我懶得實驗了,直接修復了全部...

public static class AcadRegistry
{
    /// <summary>
    /// Acad08重置之后,新建文檔會致命錯誤.
    /// 重置cad會清理注冊表,這個時候新建圖紙就會致命錯誤(即使是自帶的ctrl+n操作)
    /// 所以這個時候導出-用戶配置注冊表-是缺失的.
    /// 重啟cad之后,會自動補充這部分注冊表,這個時候是完整的(另存為圖紙也可以實現,就是完全關閉掉所有文檔則沒法另存).
    /// 兩份注冊表就可以用來對比.
    /// </summary>
    public static void CreateDocumentsComplementation()
    {
        bool writable = true;
        //通過注冊表獲取上次另存為的路徑
        var cprofile = CadSystem.Getvar("cprofile"); //當前用戶配置的名稱

        #if AC2006 || AC2007 || AC2008 || AC2009 || AC20081 || AC2011 || AC2012
            string key = HostApplicationServices.Current.RegistryProductRootKey; //這里浩辰讀出來是""
        #elif !HC2020
            string key = HostApplicationServices.Current.UserRegistryProductRootKey;
        #endif
            var currentUser = Registry.CurrentUser.OpenSubKey(key, writable);

        //注冊表_當前配置
        var regedit_Cprofile = currentUser.CreateSubKey($"Profiles\\{cprofile}");

        //注冊表_
        var regedit_Dialogs = regedit_Cprofile.CreateSubKey("Dialogs");
        {
            var acDim_DimstyleFormat = regedit_Dialogs.CreateSubKey("AcDim:DimstyleFormat");
            {
                ChangReg(acDim_DimstyleFormat, "ActiveTab", 0, RegistryValueKind.DWord);
            }


            var allAnavDialogs = regedit_Dialogs.CreateSubKey("AllAnavDialogs");
            {
                ChangReg(allAnavDialogs, "PlacesOrder0", "History");
                ChangReg(allAnavDialogs, "PlacesOrder0Display", "歷史記錄");
                ChangReg(allAnavDialogs, "PlacesOrder0Ext", string.Empty);

                ChangReg(allAnavDialogs, "PlacesOrder1", "Personal");
                ChangReg(allAnavDialogs, "PlacesOrder1Display", "文檔");
                ChangReg(allAnavDialogs, "PlacesOrder1Ext", string.Empty);

                ChangReg(allAnavDialogs, "PlacesOrder2", "Favorites");
                ChangReg(allAnavDialogs, "PlacesOrder2Display", "收藏夾");
                ChangReg(allAnavDialogs, "PlacesOrder2Ext", string.Empty);

                ChangReg(allAnavDialogs, "PlacesOrder3", "FTPSites");
                ChangReg(allAnavDialogs, "PlacesOrder3Display", "FTP");
                ChangReg(allAnavDialogs, "PlacesOrder3Ext", string.Empty);

                ChangReg(allAnavDialogs, "PlacesOrder4", "Desktop");
                ChangReg(allAnavDialogs, "PlacesOrder4Display", "桌面");
                ChangReg(allAnavDialogs, "PlacesOrder4Ext", string.Empty);

                ChangReg(allAnavDialogs, "PlacesOrder5", "ACPROJECT");
                ChangReg(allAnavDialogs, "PlacesOrder5Display", "Buzzsaw");
                ChangReg(allAnavDialogs, "PlacesOrder5Ext", string.Empty);

                ChangReg(allAnavDialogs, "PlacesOrder6", string.Empty);
            }

            string[] cus = { "CustomizeDialog", "DrawingSettingsDialog", "OptionsDialog" };
            foreach (var item in cus)
            {
                var cu = regedit_Dialogs.CreateSubKey(item + "\\TabExtensions");
                ChangReg(cu, "acmgd.dll", "acmgd.dll");
            }

            var xzyb = regedit_Dialogs.CreateSubKey("選擇樣板");
            {
                var templatePath = CadSystem.Getvar("TemplatePath");//模板路徑

                ChangReg(xzyb, "InitialFilterIndex", 0x00000000, RegistryValueKind.DWord);
                ChangReg(xzyb, "ViewMode", 0x00000004, RegistryValueKind.DWord);

                ChangReg(xzyb, "InitialDirectory", templatePath + "\\", RegistryValueKind.String);

                ChangReg(xzyb, "PreviewVisible", 0x00000001, RegistryValueKind.DWord);
                ChangReg(xzyb, "X", 0x00000226, RegistryValueKind.DWord);
                ChangReg(xzyb, "Y", 0x00000158, RegistryValueKind.DWord);

                ChangReg(xzyb, "Width", 0x00000283, RegistryValueKind.DWord);
                ChangReg(xzyb, "Height", 0x000001a1, RegistryValueKind.DWord);
            }
        }


        //注冊表_Dialogs_Window
        var regedit_Drawing_Window = regedit_Cprofile.CreateSubKey("Drawing Window");
        {
            ChangReg(regedit_Drawing_Window, "SDIMode", 0, RegistryValueKind.DWord);
        }

        //注冊表_Editor_Configuration
        var regedit_Editor_Configuration = regedit_Cprofile.CreateSubKey("Editor Configuration");
        {
            //"CustomDictionary" = "C:\\Users\\LQH\\AppData\\Roaming\\Autodesk\\AutoCAD 2008\\R17.1\\chs\\support\\sample.cus"
            //這里沒有設置好
            ChangReg(regedit_Editor_Configuration, "CustomDictionary", "", RegistryValueKind.String);
            ChangReg(regedit_Editor_Configuration, "MainDictionary", "enu", RegistryValueKind.String);
            ChangReg(regedit_Editor_Configuration, "MTextEditor", "內部", RegistryValueKind.String);

            var temp = Path.GetTempPath();
            ChangReg(regedit_Editor_Configuration, "SaveFilePath", temp, RegistryValueKind.String);
            ChangReg(regedit_Editor_Configuration, "XrefLoadPath", temp, RegistryValueKind.String);
        }

        //注冊表_General
        var regedit_General = regedit_Cprofile.CreateSubKey("General");
        {
            ChangReg(regedit_General, "ACET-ACETMAIN-MENULOADED", "1", RegistryValueKind.String);
            ChangReg(regedit_General, "Anyport", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Attdia", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Attreq", 1, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Blipmode", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Coords", 1, RegistryValueKind.DWord);

            //try
            //{
            //     ChangReg(regedit_General, "Delobj", 0xffffffff, RegistryValueKind.DWord);//這句會報錯,不設置也沒事
            //}
            //catch (Exception e)
            //{ 
            //    throw e;
            //}

            ChangReg(regedit_General, "Dragmode", 2, RegistryValueKind.DWord);
            ChangReg(regedit_General, "HideSystemPrinters", 0, RegistryValueKind.DWord);

            ChangReg(regedit_General, "LayerPMode", "1", RegistryValueKind.String);
            ChangReg(regedit_General, "MRUConfig", "Adobe PDF", RegistryValueKind.String);

            ChangReg(regedit_General, "OLEQUALITY", 3, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Osmode", 0x00001025, RegistryValueKind.DWord);
            ChangReg(regedit_General, "PAPERUPDATE", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Pickstyle", 1, RegistryValueKind.DWord);
            ChangReg(regedit_General, "PLOTLEGACY", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "PLSPOOLALERT", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "PSTYLEPOLICY", 1, RegistryValueKind.DWord);
            ChangReg(regedit_General, "RASTERTHRESHOLD", 0x14, RegistryValueKind.DWord);
            ChangReg(regedit_General, "RASTERPERCENT", 0x14, RegistryValueKind.DWord);
            ChangReg(regedit_General, "UseMRUConfig", 0, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Validation Policy", 0x3, RegistryValueKind.DWord);
            ChangReg(regedit_General, "Validation Strategy", 0x1, RegistryValueKind.DWord);
        }
        //注冊表_
        var regedit_MLeader = regedit_Cprofile.CreateSubKey("MLeader");
        {
            ChangReg(regedit_MLeader, "", "", RegistryValueKind.String);//這種是默認嗎???
            ChangReg(regedit_MLeader, "CreatedMode", 1, RegistryValueKind.DWord);
        }
        //注冊表_
        var regedit_Previous_plot_settings = regedit_Cprofile.CreateSubKey("Previous plot settings");
        {
            regedit_Previous_plot_settings.CreateSubKey("Layout");
            regedit_Previous_plot_settings.CreateSubKey("Model");
        }
        //注冊表_
        var regedit_StatusBar = regedit_Cprofile.CreateSubKey("StatusBar");
        {
            var regedit_Application = regedit_StatusBar.CreateSubKey("Application");
            ChangReg(regedit_Application, "AnnotationScales", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "AnnotationVisibility", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "AutoScale", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "CleanScreenPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "CursorCoordinatesPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "DynamicUCSPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "DynInputPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "FloatPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "GridPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "LayoutIconPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "LayoutMoreIconPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "LineweightPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "ModelIconPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "OrthoPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "OSnapPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "OTrackPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "Paper/ModelPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "PolarPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "SnapPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "SpacerPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "TabletPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "ViewportLockState", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "ViewportScales", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "VpMaxPrevPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "VpMaxPane", 1, RegistryValueKind.DWord);
            ChangReg(regedit_Application, "VpMaxNextPane", 1, RegistryValueKind.DWord);
        }
    }

    /// <summary>
    /// 如果注冊表沒有這個值才加入,否則就不加入
    /// </summary>
    /// <param name="regedit"></param>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="kind"></param>
    private static void ChangReg(RegistryKey regedit, string name, object value, 
                                 RegistryValueKind kind = RegistryValueKind.String)
    {
        bool flag = true;
        foreach (var item in regedit.GetValueNames())
        {
            if (item == name)
            {
                flag = false;
                break;
            }
        }
        if (flag)
        {
            regedit.SetValue(name, value, kind);
        }
    } 
}

這樣創建cad文檔就沒有了致命錯誤了...開心~

若其他cad也存在這樣的情況,那么如上設置就可以了...

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM