通用枚舉值...

// 本枚舉融合 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,//輸入並不都適合緩沖區 }
首先是傳參型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; //返回點對表 }
在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); } } }
再來是通過接口發送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的返回值 }
最后是提供一些發送命令的函數,這里有些備注,他們可以異步發送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; } }
最后的最后是一個發送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(); }
最最后,寫一下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 }