cad.net 定義lisp 20191227更新,20191228更新


通用枚舉值...

    // 本枚舉融合 Autodesk.AutoCAD.Runtime.LispDataType 
    //          Autodesk.AutoCAD.EditorInput.PromptStatus 
    public enum EnumBufCode
    { 
        // resbuf元素的類型  
        None           = 5000, //沒有結果   回車耶
        Double         = 5001, //實數      Real  
        Point2d        = 5002, //2維點    
        Int16          = 5003, //短整數     Short
        Angle          = 5004, //角度     
        Text           = 5005, //字符串     String
        ObjectId       = 5006, //實體名稱   Ename  
        SelectionSet   = 5007, //選擇集名   PickSet     
        Orientation    = 5008, //方向     
        Point3d        = 5009, //3維點    
        Int32          = 5010, //長整數     Long 
        Void           = 5014, //空白符號
        ListBegin      = 5016, //list begin
        ListEnd        = 5017, //list end
        DottedPair     = 5018, //點對
        Nil            = 5019, //nil(空表)
        Dxf0           = 5020, //DXF代碼0僅適用於ads_bListldlist
        T_atom         = 5021, //T(原子)

        Resbuf         = 5023, //resbuf

        Modeless       = 5027, //被無模式對話中斷
        Other          = 5028,

        // 錯誤返回代碼                       
        OK              = 5100, //請求成功,用戶輸入值有效  Norm
        Error          = -5001,//其他一些錯誤
        Cancel         = -5002,//用戶取消請求-Ctl-C
        RejectRequest  = -5003,//AutoCAD拒絕請求-無效
        FailureLink    = -5004,//鏈接失敗-Lisp可能已經死了
        Keyword        = -5005,//從getxxx()例程返回的關鍵字
        Inputtruncated = -5008,//輸入並不都適合緩沖區 
    } 
View Code

 

首先是傳參型lisp的定義,它在低版本有個問題,就是所有的返回值都要用表包裹着,而高版本就修復了這個問題.

為了所有版本統一,返回值應該統一成 ResultBuffer ,在lisp再(car 返回值).... 我這里既有 ResultBuffer,又有object返回,供各位參考.

        //傳參型lisp的定義:傳點
        //復制到命令欄運行:  (Test_AddLine (getpoint))
        [LispFunction("Test_AddLine")] //注意: 這里不是command!
        public static ResultBuffer AddLine(ResultBuffer rbArgs)
        {
            Database db = Acap.DocumentManager.MdiActiveDocument.Database;
            Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;

            Point3d p1 = Point3d.Origin;
            Point3d p2 = Point3d.Origin;
            if (rbArgs != null)
            {
                foreach (TypedValue rb in rbArgs)
                {
                    try
                    {
                        //ed.WriteMessage(Environment.NewLine + "rb.ToString()=" + rb.ToString());
                        //ed.WriteMessage(Environment.NewLine + "rb.TypeCode.ToString()=" + rb.TypeCode.ToString());
                        //ed.WriteMessage(Environment.NewLine + "rb.Value.ToString()=" + rb.Value.ToString());

                        var str = rb.Value.ToString();
                        str = str.Substring(1).Substring(0, str.Length - 2);

                        var pts = str.Split(',');
                        p2 = new Point3d(double.Parse(pts[0]), double.Parse(pts[1]), double.Parse(pts[2]));
                    }
                    catch
                    { }
                }
            }
            var line = new Line(p1, p2);
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                var acBlkTbl = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                var acBlkTblRec = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
                // line.SetDatabaseDefaults();設置數據庫默認值
                acBlkTblRec.AppendEntity(line);
                tr.AddNewlyCreatedDBObject(line, true);
                tr.Commit();
            }
            var rbrtn = new ResultBuffer(new TypedValue[]
            {
                new TypedValue((int)EnumBufCode.ObjectId, line.ObjectId),
                new TypedValue((int)EnumBufCode.Point3d, p1),
                new TypedValue((int)EnumBufCode.Point3d, p2)
            });
            ed.WriteMessage(Environment.NewLine + " rbrtn=" + rbrtn.ToString());
            ed.WriteMessage(Environment.NewLine);
            return rbrtn; //返回值此處有圖元名
        }
         
        //傳參型lisp的定義:加法
        //復制到命令欄運行:  (Test_MyAdd 1 2 3)
        [LispFunction("Test_MyAdd")] //注意: 這里不是command!
        public static object Test_MyAdd(ResultBuffer args) //高版本這里可以返回double,但是08只能返回ResultBuffer
        {
            var ds = new List<double>();
            if (args != null)
            {
                foreach (TypedValue rb in args)
                {
                    try
                    {
                        var a = double.Parse(rb.Value.ToString());
                        ds.Add(a);
                    }
                    catch
                    { }
                }
            }

            double number = 0;
            foreach (var item in ds)
            {
                number += item;
            }

            //08只能返回ResultBuffer 會返回表內數字(6.0)
            //高版本可以返回其他的
            var rbrtn = new ResultBuffer(new TypedValue[]
            {
                 new TypedValue((int)EnumBufCode.Double, number),
            });

            var dotPair = new ResultBuffer(new TypedValue[] {
            new TypedValue((int)EnumBufCode.ListBegin, -1),
            new TypedValue((int)EnumBufCode.Int16, 0),
            new TypedValue((int)EnumBufCode.Int16, 100),
            new TypedValue((int)EnumBufCode.DottedPair, -1),
            });


#if AC2008
            return rbrtn;  //但是08只能返回ResultBuffer 會返回(6.0)
#else
            return number; //高版本這里可以返回double    會返回6.0
#endif

        }
         
        //傳參型lisp的定義:選擇集
        //復制到命令欄運行:  (Test_ssget (ssget))
        [LispFunction("Test_ssget")] //注意: 這里不是command!
        public static object Test_ssget(ResultBuffer args)
        {
            //var dt = new List<object>();
            var ds = new List<object>();
            if (args != null)
            {
                foreach (TypedValue rb in args)//{((5007,(((-2181752),Crossing,0,)((-2181760),Crossing,0,))))}
                {
                    try
                    {
                        //dt.Add(rb.TypeCode);
                        ds.Add(rb.Value);
                    }
                    catch
                    { }
                }
            }

            var tl = new List<TypedValue>();
            foreach (var item in ds)
            {
                tl.Add(new TypedValue((int)EnumBufCode.SelectionSet, item));
            }
            var rbrtn = new ResultBuffer(tl.ToArray());
            return rbrtn;
        }

        //傳參型lisp的定義:點對
        //復制到命令欄運行:  (Test_dotPair 0 100)
        [LispFunction("Test_dotPair")] //注意: 這里不是command!
        public static object Test_dotPair(ResultBuffer args)
        {
            var ds = new List<object>();
            if (args != null)
            {
                foreach (TypedValue rb in args)//{((5007,(((-2181752),Crossing,0,)((-2181760),Crossing,0,))))}
                {
                    try
                    {
                        ds.Add(rb.Value);
                    }
                    catch
                    { }
                }
            }

            var ls = new List<TypedValue>();

            ResultBuffer dotPair = null;
            if (ds.Count == 2)
            {
                ls.Add(new TypedValue((int)EnumBufCode.ListBegin, -1));

                ls.Add(new TypedValue((int)EnumBufCode.Int16, ds[0]));
                if (short.TryParse(ds[1].ToString(), out short num))
                {
                    ls.Add(new TypedValue((int)EnumBufCode.Int16, num));
                    ls.Add(new TypedValue((int)EnumBufCode.DottedPair, -1));
                    dotPair = new ResultBuffer(ls.ToArray());
                }
            }
            return dotPair; //返回點對表 
        }
View Code

 

 

在c#讀取和賦值lisp變量的值 ,測試命令: Test_setLisp

#if !HC2020
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Application = Autodesk.AutoCAD.ApplicationServices.Application;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.EditorInput;
using GrxCAD.Geometry;
using GrxCAD.ApplicationServices;
using GrxCAD.Runtime;
using GrxCAD.Colors;
using GrxCAD.GraphicsInterface;
using Viewport = GrxCAD.DatabaseServices.Viewport;
using Application = GrxCAD.ApplicationServices.Application;
#endif

using System.Runtime.InteropServices;
using System;

namespace JoinBox.CommandLisp
{
    // 操作lisp賦值
    // https://blog.csdn.net/qq_21489689/article/details/80630817
    // 我驗證了2008和2019,32位 DllImport("accore.dll" 好像不對,沒有環境驗證

    public static class LStructure
    {
        //LSP變量的寫入-64位
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("accore.dll", EntryPoint = "acedPutSym", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        extern static private int AcedPutSym64(string args, IntPtr result);

#if AC2008
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("acad.exe", EntryPoint = "acedPutSym", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        extern static private int AcedPutSym32(string args, IntPtr result);
#else
        //沒有環境驗證
        //LSP變量的寫入-32位  
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("accore.dll", EntryPoint = "_acedPutSym", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        extern static private int AcedPutSym32(string args, IntPtr result); 
#endif

        /// <summary>
        /// 設置Lisp變量值
        /// </summary>
        /// <param name="name">變量名</param>
        /// <param name="rb">變量值</param>
        static int SetLispSym(string name, ResultBuffer rb)
        {
            int ret = 0;
            //判斷系統是32位還是64位
            switch (Marshal.SizeOf(typeof(IntPtr)))
            {
                case 4:
                    {
                        ret = AcedPutSym32(name, rb.UnmanagedObject);
                    }
                    break;
                case 8:
                    {
                        ret = AcedPutSym64(name, rb.UnmanagedObject);
                    }
                    break;
            }
            return ret;
        }

        //LSP變量的讀取-64位
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("accore.dll", EntryPoint = "acedGetSym", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        extern static private int AcedGetSym64(string args, out IntPtr result);

#if AC2008
        //LSP變量的讀取-32位
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("acad.exe", EntryPoint = "acedGetSym", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        extern static private int AcedGetSym32(string args, out IntPtr result);
#else   
        //沒有環境驗證
        //LSP變量的讀取-32位
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("accore.dll", EntryPoint = "_acedGetSym", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        extern static private int AcedGetSym32(string args, out IntPtr result);
#endif

        /// <summary>
        /// 獲取Lisp變量值
        /// </summary>
        /// <param name="name">變量名</param>
        /// <returns>變量值,如果失敗則為空</returns>
        static ResultBuffer GetLispSym(string name)
        {
            IntPtr ip;
            //判斷系統是32位還是64位
            switch (Marshal.SizeOf(typeof(IntPtr)))
            {
                case 4:
                    {
                        int status = AcedGetSym32(name, out ip);
                        if (status == (int)EnumBufCode.OK && ip != IntPtr.Zero)
                        {
                            return ResultBuffer.Create(ip, true);
                        }
                    }
                    break;
                case 8:
                    {
                        int status = AcedGetSym64(name, out ip);
                        if (status == (int)EnumBufCode.OK && ip != IntPtr.Zero)
                        {
                            return ResultBuffer.Create(ip, true);
                        }
                    }
                    break;
            }
            return null;
        }

        /// <summary>
        /// lisp變量賦值
        /// </summary>
        /// <param name="varName">變量名</param>
        /// <param name="varValue">變量值</param>
        /// <param name="cEnumRes">變量值類型,原子,字符串等等</param>
        public static void SetLspVar(EnumBufCode cEnumRes, string varName, object varValue = null)
        {
            using (var rb = new ResultBuffer())
            {
                rb.Add(new TypedValue((int)cEnumRes, varValue));
                SetLispSym(varName, rb);
            }
        }

        /// <summary>
        /// 讀取LSP變量
        /// </summary>
        /// <param name="varName">變量名</param>
        /// <returns></returns>
        public static object GetLspVar(string varName)
        {
            object varValue = null;
            ResultBuffer rb = GetLispSym(varName);
            if (rb != null)
            {
                foreach (var val in rb)
                {
                    varValue = val.Value;
                }
            }
            return varValue;
        }

        [CommandMethod("Test_setLisp")]
        public static void Test_setLisp()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            string varName = "a";
            object v;
            // 賦值例子 
            // (setq a "35432")
            SetLspVar(EnumBufCode.Text, varName, "35432");   //返回  "3543252351515"
            v = GetLspVar(varName);
            ed.Princ(v);

            // (setq a 35432)                                  
            SetLspVar(EnumBufCode.Double, varName, "35432"); //返回   3543252351515
            v = GetLspVar(varName);
            ed.Princ(v);

            // (setq a T)                                      
            SetLspVar(EnumBufCode.T_atom, varName, true);    //返回   T
            SetLspVar(EnumBufCode.T_atom, varName, false);   //返回   T
            v = GetLspVar(varName);
            ed.Princ(v);

            // (setq a nil)                                    
            SetLspVar(EnumBufCode.Nil, varName);             //返回   nil 
            v = GetLspVar(varName);
            ed.Princ(v);
        }

        static void Princ(this Editor ed, object var)
        {
            string varString = "";
            if (var == null)
            {
                varString = "nil";
            }
            else
            {
                string type = var.GetType().Name;
                switch (type)
                {
                    case "String":
                        {
                            varString = var.ToString();
                            varString = "\"" + varString + "\"";
                        }
                        break;
                    case "Double":
                        {
                            varString = var.ToString();
                        }
                        break;
                    case "Boolean":
                        {
                            varString = "T"; //返回布爾值都是為true的,不返回才是nil
                        }
                        break;
                }
            }
            ed.WriteMessage("\n" + varString);
        }
    }
}
View Code

 

再來是通過接口發送lisp,這個可以避免用明文方式發送到命令欄,而且它在自動執行函數上面也是同步發送的,很有趣喲: testLisp

#if AC2008 || AC2012
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("acad.exe", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "?acedEvaluateLisp@@YAHPB_WAAPAUresbuf@@@Z")]
        private static extern int AcedEvaluateLisp(string lispLine, out IntPtr result);

        [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedInvoke")]
        private static extern int AcedInvoke(IntPtr args, out IntPtr result);
#else
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?acedEvaluateLisp@@YAHPEB_WAEAPEAUresbuf@@@Z")]
        private static extern int AcedEvaluateLisp(string lispLine, out IntPtr result);

        [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedInvoke")]
        private static extern int AcedInvoke(IntPtr args, out IntPtr result);
#endif

        /// <summary>
        /// 定義lisp
        /// </summary>
        /// <param name="arg">lisp語句</param>
        /// <returns>緩沖結果,返回值</returns>
        public static ResultBuffer RunLisp(string arg)
        {
            AcedEvaluateLisp(arg, out IntPtr rb);
            if (rb != IntPtr.Zero)
            {
                try
                {
                    var rbb = DisposableWrapper.Create(typeof(ResultBuffer), rb, true) as ResultBuffer;
                    return rbb;
                }
                catch
                {
                    return null;
                }
            }
            return null;
        }

        /// <summary>
        /// c#發送lisp,這個同步方式可以在自動運行函數上跑,也是同步的
        /// </summary>
        /// <returns></returns>
        [CommandMethod("testLisp")]
        public void Cmdtest()
        {
            string Strlisp = "(setq a 10)";
            var res = RunLisp(Strlisp); //有lisp的返回值
        }
View Code

 

最后是提供一些發送命令的函數,這里有些備注,他們可以異步發送lisp,有些會導致自動執行時候發送lisp出錯,但是卻是異步發送的必需品.

    public partial class SendToCad
    {
#if AC2006 || AC2007 || AC2008 || AC2009 || AC2010 || AC2011 || AC2012
        /// <summary> 
        /// 發送命令
        /// </summary>
        /// <param name="strExpr"></param>
        /// <returns></returns>    
        [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ads_queueexpr")]
        private static extern int Ads_queueexpr(string strExpr);//非同步,這個在08/12發送lisp不會出錯,但是發送bo命令出錯了..

        /// <summary>
        /// 發送命令,設置CommandFlags.Session可以同步,
        /// 發送lisp也可以,但是非同步,在自動執行函數上面會非同步
        /// </summary>
        /// <param name="str"></param>
        public static void SendLisp(string str)
        {
            try
            {
                Ads_queueexpr(str + "\n");
            }
            catch (Exception ee)
            {
                //自執行發送lisp都是在最后的(異步執行)   
                var ed = Application.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage(Environment.NewLine + "發送命令失敗,導致加載失敗!");
                ed.WriteMessage(Environment.NewLine + "" + ee.Message + Environment.NewLine);
            }
        }

        /// <summary>
        /// 發送命令
        /// </summary>
        /// <param name="strExpr"></param>
        /// <returns></returns> 
        [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedPostCommand@@YAHPB_W@Z")]
        private static extern int AcedPostCommand(string strExpr);
#else
        /// <summary>
        /// 發送命令
        /// </summary> 
        /// <param name="str">發送lisp加載命令</param> 
        /// <returns></returns>
        public static void SendLisp(string str)
        {
            Document dc = Application.DocumentManager.MdiActiveDocument;
            string commands = str + "\n";
            try
            {
                dc.SendStringToExecute(commands, false, false, false);//08所有都flase會有問題,出現報錯
            }
            catch (System.Exception ee)
            {
                //自執行發送lisp都是在最后的(異步執行)   
                var ed = dc.Editor;
                ed.WriteMessage(ee.Message);
                ed.WriteMessage(Environment.NewLine + "發送命令失敗,導致加載失敗!");
                ed.WriteMessage(Environment.NewLine + ee.Message);
            }
        }
#endif  
        /// <summary>
        /// 發送命令
        /// </summary>
        /// <param name="str">命令</param>
        /// <returns></returns>
        public static bool SendCommand(string str) //非同步,這里加載lisp第二個文檔有問題...
        {
            object ActiveDocument = Com.App.GetType().InvokeMember("ActiveDocument", BindingFlags.GetProperty, null, Com.App, null);
            object[] commandArray = { str + "\n" };
            ActiveDocument.GetType().InvokeMember("SendCommand", BindingFlags.InvokeMethod, null, ActiveDocument, commandArray);
            return true;
        }
    }
View Code

 

最后的最后是一個發送esc的操作,我也不知道為什么要放這里,可能他存在的價值不高...

        //http://www.tiancao.net/blogview.asp?logID=1871&cateID=3&tdsourcetag=s_pcqq_aiomsg
        /*
        我想從我的非模態對話框的按鈕中啟動一些命令。我已經發現,對於SendStringToExecute,我應該使用‘\x03’字符而不是^C。
        我唯一的問題是,在這種情況下,如果沒有運行命令,那么我將在命令窗口,如果單擊菜單項時沒有運行命令,則菜單的^C^C不會導致* Cancel*出現。
        我怎樣才能達到同樣的目的呢?
        解:
        你可以查帳CMDNAMES系統變量,根據當前運行的命令數量,可以在命令字符串的開頭添加許多轉義字符。
        這里有一個樣本這表明:  
        */
        [CommandMethod("sendEsc")]
        public void SendEsc()
        {
            //c#非模態窗體發命令
            string esc = "";
            string cmds = CadSystem.Getvar("CMDNAMES");
            if (cmds.Length > 0)
            {
                int cmdNum = cmds.Split(new char[] { '\'' }).Length;
                for (int i = 0; i < cmdNum; i++)
                    esc += '\x03';
            }
            Document doc = Application.DocumentManager.MdiActiveDocument;
            doc.SendStringToExecute(esc + "_.LINE ", true, false, true);
            //設置cad窗口的焦點激活繪圖區
            //acApp.MainWindow.Focus();
        }
View Code

 

最最后,寫一下com接口的新舊版本寫法:

    public static class Com
    {
#if AC2006 || AC2007 || AC2008 || AC2009 || AC2010 || AC2011 || AC2012 
        public static AcadDocument Adm { get; } = Application.DocumentManager.MdiActiveDocument.AcadDocument as AcadDocument;
#else     
        public static AcadDocument Adm { get; } = Application.DocumentManager.MdiActiveDocument.GetAcadDocument() as AcadDocument;
#endif

#if !HC2020
        public static AcadApplication App { get; } = Application.AcadApplication as AcadApplication;
#else
        public static GcadApplication App { get; } = Application.AcadApplication as GcadApplication;
#endif
    }


免責聲明!

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



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