调用AutoCad命令的方法
本帖最后由 作者 于 2010-6-28 20:17:52 编辑从Lisp转向.Net的朋友可能都有点郁闷,Lisp可能很短的代码,.NetApi要写很长的
而且很多功能都习惯于使用Command函数去调用AutoCad的命令实现,因为这样很简单
而NetApi提供的调用命令的方法SendStringToExecute确实鸡肋,它的机理和VBA的SendCommand相同,只是简单的向命令行发送字符,要实现Command函数的复杂控制是不可能的
那么应该怎么办呢?P/Invoke可以!
Lisp的Command函数实质是ObjectArx函数acedCmd的封装,那么使用平台调用,在.Net里也可以实现自己的封装,具体的方式可以看看Kean的相关文章:)
最终的版本
InvokeArx.cs
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
namespace TlsCad.Utils
{
/// <summary>
/// 平台调用类
/// </summary>
public class InvokeArx
{
private static void AddValueToResultBuffer(ref ResultBuffer rb, object obj)
{
if (obj == null)
{
rb.Add(new TypedValue((int)LispDataType.Text, ""));
}
else
{
if (obj is string)
{
rb.Add(new TypedValue((int)LispDataType.Text, obj));
}
else if (obj is Point2d)
{
rb.Add(new TypedValue((int)LispDataType.Text, "_non"));
rb.Add(new TypedValue((int)LispDataType.Point2d, obj));
}
else if (obj is Point3d)
{
rb.Add(new TypedValue((int)LispDataType.Text, "_non"));
rb.Add(new TypedValue((int)LispDataType.Point3d, obj));
}
else if (obj is ObjectId)
{
rb.Add(new TypedValue((int)LispDataType.ObjectId, obj));
}
else if (obj is SelectionSet)
{
rb.Add(new TypedValue((int)LispDataType.SelectionSet, obj));
}
else if (obj is double)
{
rb.Add(new TypedValue((int)LispDataType.Double, obj));
}
else if (obj is short)
{
rb.Add(new TypedValue((int)LispDataType.Int16, obj));
}
else if (obj is int)
{
rb.Add(new TypedValue((int)LispDataType.Int32, obj));
}
else if (obj is TypedValue)
{
rb.Add(obj);
}
}
}
#region Redraw
private static extern Int32 acedRedraw(long[] name, Int32 mode);
public static void Redraw()
{
acedRedraw(null, 1);
}
//
//private static extern int acdbGetAdsName(long[] name, ObjectId objId);
//public static void Redraw(ObjectId id)
//{
// long[] adsname = new long;
// acdbGetAdsName(adsname, id);
// acedRedraw(adsname, 1);
//}
#endregion
#region TextScr
private static extern int acedTextScr();
private static extern int acedGraphScr();
public static bool DisplayTextScreen
{
set
{
if (value)
acedTextScr();
else
acedGraphScr();
}
}
#endregion
#region Command
/// <summary>
/// 控制命令行回显
/// </summary>
public static bool CmdEcho
{
get
{
return (int)Application.GetSystemVariable("cmdecho") == 1;
}
set
{
Application.SetSystemVariable("cmdecho", Convert.ToInt16(value));
}
}
private static extern int acedCmd(IntPtr vlist);
/// <summary>
/// 调用AutoCad命令
/// </summary>
/// <param name="prompt">命令行提示</param>
/// <param name="arg">参数</param>
public static void Command(string prompt, object arg)
{
EdUtility.WriteMessage(prompt);
ResultBuffer rb = new ResultBuffer();
AddValueToResultBuffer(ref rb, arg);
try
{
acedCmd(rb.UnmanagedObject);
}
catch { }
finally
{
rb.Dispose();
}
}
/// <summary>
/// 调用AutoCad命令
/// </summary>
/// <param name="endCommandByUser">命令结束方式</param>
/// <param name="ldnode">参数</param>
public static void Command(bool endCommandByUser, ResultBuffer rb)
{
ResultBuffer rbend = new ResultBuffer();
try
{
Document doc = Application.DocumentManager.MdiActiveDocument;
string currCmdName = doc.CommandInProgress;
acedCmd(rb.UnmanagedObject);
if (endCommandByUser)
{
rbend.Add(new TypedValue((int)LispDataType.Text, "\\"));
}
while (doc.CommandInProgress != currCmdName)
{
acedCmd(rbend.UnmanagedObject);
}
}
catch { }
finally
{
rb.Dispose();
rbend.Dispose();
}
}
/// <summary>
/// 调用AutoCad命令
/// </summary>
/// <param name="endCommandByUser">命令结束方式</param>
/// <param name="args">参数</param>
public static void Command(bool endCommandByUser, params object[] args)
{
ResultBuffer rb = new ResultBuffer();
ResultBuffer rbend = new ResultBuffer();
foreach (object val in args)
{
AddValueToResultBuffer(ref rb, val);
}
try
{
Document doc = Application.DocumentManager.MdiActiveDocument;
string currCmdName = doc.CommandInProgress;
acedCmd(rb.UnmanagedObject);
if (endCommandByUser)
{
rbend.Add(new TypedValue((int)LispDataType.Text, "\\"));
}
while (doc.CommandInProgress != currCmdName)
{
acedCmd(rbend.UnmanagedObject);
}
}
catch { }
finally
{
rb.Dispose();
rbend.Dispose();
}
}
#endregion
#region Lisp
extern static private int acedPutSym(string name, IntPtr result);
extern static private int acedGetSym(string name, out IntPtr result);
extern static private int acedInvoke(IntPtr args, out IntPtr result);
public static ResultBuffer CallLispFunction(ResultBuffer args)
{
IntPtr ip = IntPtr.Zero;
int st = acedInvoke(args.UnmanagedObject, out ip);
if (ip != IntPtr.Zero)
{
ResultBuffer rbRes = ResultBuffer.Create(ip, true);
return rbRes;
}
return null;
}
public static ResultBuffer CallLispFunction(string name, params object[] args)
{
ResultBuffer rbArgs = new ResultBuffer();
rbArgs.Add(new TypedValue((int)LispDataType.Text, name));
foreach (object val in args)
{
AddValueToResultBuffer(ref rbArgs, val);
}
return CallLispFunction(rbArgs);
}
internal static ResultBuffer GetLispSym(string name)
{
IntPtr ip = IntPtr.Zero;
acedGetSym(name, out ip);
if (ip != IntPtr.Zero)
{
ResultBuffer rbRes = ResultBuffer.Create(ip, true);
return rbRes;
}
return null;
}
#endregion
}
}
测试代码,结合ResultList/ResultTree类
public static void Test11()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityResult res1 = ed.GetEntity("\nSelect a Entity:");
InvokeArx.CmdEcho = false;
InvokeArx.Command(
false,
new ResultTree
{
"break",
new ResultTree(ResultType.List)
{
res1.ObjectId,
res1.PickedPoint
},
res1.PickedPoint
});
InvokeArx.CmdEcho = true;
}
学习了,胡歌 厉害了 本帖最后由 作者 于 2010-6-28 20:02:27 编辑
两段简单的测试代码,但注意NetApi最好还是少调用命令为好
public static void Test10()
{
//调用Line命令,由用户结束
InvokeArx.Command(true, "_.line");
//调用Line命令并结束
InvokeArx.Command(false, "_.line", Point3d.Origin, new Point3d(10, 10, 0));
}
public static void Test11()
{
//找回Hatch边界的命令版,当然你需要有一个填充先
PromptEntityOptions opts = new PromptEntityOptions("\nselect a Hatch:");
opts.SetRejectMessage("\nnot a Hatch!");
opts.AddAllowedClass(typeof(Hatch), false);
PromptEntityResult res = Helper.Editor.GetEntity(opts);
InvokeArx.Command(false, "_.HATCHEDIT", res.ObjectId, "B", "P", "Y");
} 本帖最后由 作者 于 2009-12-28 10:24:39 编辑
完整的代码
同时测试代码提供了可更改CommandLine提示的调用方式,
但是如果不小心键入U(回退),效果就会消失
public static void Test10()
{
EdUtility.CmdEcho = false;
EdUtility.Command("Hello", "_.line");
EdUtility.Command("请输入第一点", "\\");
EdUtility.Command("请输入第二点", "\\");
EdUtility.Command("结束", "");
EdUtility.CmdEcho = true;
}
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
namespace TlsCad.Utils
{
public struct DottedPair
{
private ObjectId _id;
private Point3d _pnt;
public ObjectId ObjectId
{
get { return _id; }
}
public Point3d Point
{
get { return _pnt; }
}
public DottedPair(ObjectId id,Point3d pnt)
{
_id = id;
_pnt = pnt;
}
public DottedPair(PromptEntityResult res)
{
_id = res.ObjectId;
_pnt = res.PickedPoint;
}
}
public static class EdUtility
{
#region Command
public static bool CmdEcho
{
get
{
return (int)Application.GetSystemVariable("cmdecho") == 1;
}
set
{
Application.SetSystemVariable("cmdecho", Convert.ToInt16(value));
}
}
private static void AddValueToResultBuffer(ref ResultBuffer rb, object obj)
{
if (obj == null)
{
rb.Add(new TypedValue((int)LispDataType.Text, ""));
}
else
{
if (obj is string)
{
rb.Add(new TypedValue((int)LispDataType.Text, obj));
}
else if (obj is Point2d)
{
rb.Add(new TypedValue((int)LispDataType.Text, "_non"));
rb.Add(new TypedValue((int)LispDataType.Point2d, obj));
}
else if (obj is Point3d)
{
rb.Add(new TypedValue((int)LispDataType.Text, "_non"));
rb.Add(new TypedValue((int)LispDataType.Point3d, obj));
}
else if (obj is ObjectId)
{
rb.Add(new TypedValue((int)LispDataType.ObjectId, obj));
}
else if (obj is SelectionSet)
{
rb.Add(new TypedValue((int)LispDataType.SelectionSet, obj));
}
else if (obj is double)
{
rb.Add(new TypedValue((int)LispDataType.Double, obj));
}
else if (obj is short)
{
rb.Add(new TypedValue((int)LispDataType.Int16, obj));
}
else if (obj is int)
{
rb.Add(new TypedValue((int)LispDataType.Int32, obj));
}
else if (obj is TypedValue)
{
rb.Add(obj);
}
else if (obj is DottedPair)
{
DottedPair dp = (DottedPair)obj;
rb.Add(new TypedValue((int)LispDataType.ListBegin));
rb.Add(new TypedValue((int)LispDataType.ObjectId,dp.ObjectId));
rb.Add(new TypedValue((int)LispDataType.Point3d, dp.Point));
rb.Add(new TypedValue((int)LispDataType.ListEnd));
}
}
}
private static extern int acedCmd(IntPtr vlist);
public static void Command(string prompt, object arg)
{
WriteMessage(prompt);
ResultBuffer rb = new ResultBuffer();
AddValueToResultBuffer(ref rb, arg);
try
{
acedCmd(rb.UnmanagedObject);
}
catch { }
finally
{
rb.Dispose();
}
}
/*
*功能:
* 调用AutoCad命令
*参数:
* endCommandByUse 命令结束方式
* args 参数
*返回:
* 无
*/
public static void Command(bool endCommandByUser, params object[] args)
{
ResultBuffer rb = new ResultBuffer();
ResultBuffer rbend = new ResultBuffer();
foreach (object val in args)
{
AddValueToResultBuffer(ref rb, val);
}
try
{
Document doc = Application.DocumentManager.MdiActiveDocument;
string currCmdName = doc.CommandInProgress;
acedCmd(rb.UnmanagedObject);
if (endCommandByUser)
{
rbend.Add(new TypedValue((int)LispDataType.Text, "\\"));
}
while (doc.CommandInProgress != currCmdName)
{
acedCmd(rbend.UnmanagedObject);
}
}
catch { }
finally
{
rb.Dispose();
rbend.Dispose();
}
}
//2009版本提供了acedCmd函数的封装
//但可能有Bug,所以未公开
//谨慎使用
private static MethodInfo _runCommand =
typeof(Editor).GetMethod(
"RunCommand",
BindingFlags.NonPublic | BindingFlags.Instance);
/*
*功能:
* 反射调用AutoCad命令(2009版本以上)
*参数:
* editor Editor对象
* args 参数
*返回:
* 无
*/
public static PromptStatus Command(Editor editor, params object[] args)
{
return (PromptStatus)_runCommand.Invoke(editor, new object[] { args });
}
#endregion
}
}
好像无法执行load命令,如果(load"d:\\1.lsp")就无法执行 <p>load在这里不是命令,而是Lisp函数,</p><p>P/Invoke的话要用acedInvoke调用</p><p>但我在2008、2010似乎都无法正确使用,汗,以前的版本倒是可以</p><p>不过Lisp可以实现的,NetApi也可以实现,为什么不直接用NetApi做?</p> lzh741206发表于2009-9-19 15:17:00static/image/common/back.gifload在这里不是命令,而是Lisp函数,P/Invoke的话要用acedInvoke调用但我在2008、2010似乎都无法正确使用,汗,以前的版本倒是可以不过Lisp可以实现的,NetApi也可以实现,为什么不直接用NetAp
<p>NetApi如何实现这个功能,先生给点提示和简单代码好吧?谢谢!</p> <p>在theswamp看到过的用法</p><p>不过似乎只能调用.Net自己定义的Lisp</p> 2008.12.28
加入点对支持
3楼代码已更改
调用示例
public static void Test10()
{
Editor ed = Helper.Editor;
PromptEntityResult res1 = ed.GetEntity("\n选择直线:");
PromptPointResult res2 = ed.GetPoint("选择第二点");
InvokeArx.Command(false, "._break", new DottedPair(res1), res2.Value);
}
在狐哥的基础上修改了一点点:
调用格式与Lisp的command函数高度一致
自动将object[] ,解释成相当于Lisp中的 (list ....))
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
namespace FsxmAcad
{
public static class EdUtility
{
public static bool CmdEcho
{
get
{
return (int)Application.GetSystemVariable("cmdecho") == 1;
}
set
{
Application.SetSystemVariable("cmdecho", Convert.ToInt16(value));
}
}
/// <summary>将一个对像生成TypedValue后加入到ResultBuffer</summary>
/// <param name="rb">Ref 集合ResultBuffer</param>
/// <param name="obj">要加入的对象</param>
public static void AddValue(this ResultBuffer rb, object obj)
{
if (obj == null)
{
rb.Add(new TypedValue((int)LispDataType.Text, ""));
}
else if (obj is object[])
{
rb.Add(new TypedValue((int)LispDataType.ListBegin)); //5016
foreach (object item in (object[])obj)
{
AddValue(rb, item);
}
rb.Add(new TypedValue((int)LispDataType.ListEnd));//5017
}
else if (obj is string)//5005
{
rb.Add(new TypedValue((int)LispDataType.Text, obj));
}
else if (obj is Point2d)//5002
{
rb.Add(new TypedValue((int)LispDataType.Point2d, obj));
}
else if (obj is Point3d)//5009
{
rb.Add(new TypedValue((int)LispDataType.Point3d, obj));
}
else if (obj is ObjectId)//5006
{
rb.Add(new TypedValue((int)LispDataType.ObjectId, obj));
}
else if (obj is SelectionSet)//5007
{
rb.Add(new TypedValue((int)LispDataType.SelectionSet, obj));
}
else if (obj is double)//5001
{
rb.Add(new TypedValue((int)LispDataType.Double, obj));
}
else if (obj is short)//5003
{
rb.Add(new TypedValue((int)LispDataType.Int16, obj));
}
else if (obj is int)//5010
{
rb.Add(new TypedValue((int)LispDataType.Int32, obj));
}
else if (obj is TypedValue)
{
rb.Add(obj);
}
}
/// <summary>调用AutoCad命令原始Api</summary>
public static extern int acedCmd(IntPtr vlist);
/// <summary>调用AutoCad命令</summary>
/// <param name="args">参数列表</param>
public static void Command(params object[] args)
{
ResultBuffer rb;
using (rb = new ResultBuffer())
{
foreach (object val in args)
{
rb.AddValue(val);
}
acedCmd(rb.UnmanagedObject);
}
}
public static void Test10()
{
PromptEntityResult er = Application.DocumentManager.MdiActiveDocument.Editor.GetEntity("选剪切对像:");
if (rst.Status != PromptStatus.OK)
return;
EdUtility.CmdEcho = true;
EdUtility.Command(".trim", "", new object[] { rst.ObjectId, rst.PickedPoint }, "");
}
}
}
本帖最后由 作者 于 2010-6-28 19:59:42 编辑
最终的版本
InvokeArx.cs
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using TlsCad.Collections;
namespace TlsCad.Utils
{
/// <summary>
/// 平台调用类
/// </summary>
public class InvokeArx
{
private static void AddValueToResultBuffer(ref ResultBuffer rb, object obj)
{
if (obj == null)
{
rb.Add(new TypedValue((int)LispDataType.Text, ""));
}
else
{
if (obj is string)
{
rb.Add(new TypedValue((int)LispDataType.Text, obj));
}
else if (obj is Point2d)
{
rb.Add(new TypedValue((int)LispDataType.Text, "_non"));
rb.Add(new TypedValue((int)LispDataType.Point2d, obj));
}
else if (obj is Point3d)
{
rb.Add(new TypedValue((int)LispDataType.Text, "_non"));
rb.Add(new TypedValue((int)LispDataType.Point3d, obj));
}
else if (obj is ObjectId)
{
rb.Add(new TypedValue((int)LispDataType.ObjectId, obj));
}
else if (obj is SelectionSet)
{
rb.Add(new TypedValue((int)LispDataType.SelectionSet, obj));
}
else if (obj is double)
{
rb.Add(new TypedValue((int)LispDataType.Double, obj));
}
else if (obj is short)
{
rb.Add(new TypedValue((int)LispDataType.Int16, obj));
}
else if (obj is int)
{
rb.Add(new TypedValue((int)LispDataType.Int32, obj));
}
else if (obj is TypedValue)
{
rb.Add(obj);
}
}
}
#region Redraw
private static extern Int32 acedRedraw(long[] name, Int32 mode);
public static void Redraw()
{
acedRedraw(null, 1);
}
//
//private static extern int acdbGetAdsName(long[] name, ObjectId objId);
//public static void Redraw(ObjectId id)
//{
// long[] adsname = new long;
// acdbGetAdsName(adsname, id);
// acedRedraw(adsname, 1);
//}
#endregion
#region TextScr
private static extern int acedTextScr();
private static extern int acedGraphScr();
public static bool DisplayTextScreen
{
set
{
if (value)
acedTextScr();
else
acedGraphScr();
}
}
#endregion
#region Command
/// <summary>
/// 控制命令行回显
/// </summary>
public static bool CmdEcho
{
get
{
return (int)Application.GetSystemVariable("cmdecho") == 1;
}
set
{
Application.SetSystemVariable("cmdecho", Convert.ToInt16(value));
}
}
private static extern int acedCmd(IntPtr vlist);
/// <summary>
/// 调用AutoCad命令
/// </summary>
/// <param name="prompt">命令行提示</param>
/// <param name="arg">参数</param>
public static void Command(string prompt, object arg)
{
EdUtility.WriteMessage(prompt);
ResultBuffer rb = new ResultBuffer();
AddValueToResultBuffer(ref rb, arg);
try
{
acedCmd(rb.UnmanagedObject);
}
catch { }
finally
{
rb.Dispose();
}
}
/// <summary>
/// 调用AutoCad命令
/// </summary>
/// <param name="endCommandByUser">命令结束方式</param>
/// <param name="ldnode">参数</param>
public static void Command(bool endCommandByUser, ResultBuffer rb)
{
ResultBuffer rbend = new ResultBuffer();
try
{
Document doc = Application.DocumentManager.MdiActiveDocument;
string currCmdName = doc.CommandInProgress;
acedCmd(rb.UnmanagedObject);
if (endCommandByUser)
{
rbend.Add(new TypedValue((int)LispDataType.Text, "\\"));
}
while (doc.CommandInProgress != currCmdName)
{
acedCmd(rbend.UnmanagedObject);
}
}
catch { }
finally
{
rb.Dispose();
rbend.Dispose();
}
}
/// <summary>
/// 调用AutoCad命令
/// </summary>
/// <param name="endCommandByUser">命令结束方式</param>
/// <param name="args">参数</param>
public static void Command(bool endCommandByUser, params object[] args)
{
ResultBuffer rb = new ResultBuffer();
ResultBuffer rbend = new ResultBuffer();
foreach (object val in args)
{
AddValueToResultBuffer(ref rb, val);
}
try
{
Document doc = Application.DocumentManager.MdiActiveDocument;
string currCmdName = doc.CommandInProgress;
acedCmd(rb.UnmanagedObject);
if (endCommandByUser)
{
rbend.Add(new TypedValue((int)LispDataType.Text, "\\"));
}
while (doc.CommandInProgress != currCmdName)
{
acedCmd(rbend.UnmanagedObject);
}
}
catch { }
finally
{
rb.Dispose();
rbend.Dispose();
}
}
#endregion
#region Lisp
extern static private int acedPutSym(string name, IntPtr result);
extern static private int acedGetSym(string name, out IntPtr result);
extern static private int acedInvoke(IntPtr args, out IntPtr result);
public static ResultBuffer CallLispFunction(ResultBuffer args)
{
IntPtr ip = IntPtr.Zero;
int st = acedInvoke(args.UnmanagedObject, out ip);
if (ip != IntPtr.Zero)
{
ResultBuffer rbRes = ResultBuffer.Create(ip, true);
return rbRes;
}
return null;
}
public static ResultBuffer CallLispFunction(string name, params object[] args)
{
ResultBuffer rbArgs = new ResultBuffer();
rbArgs.Add(new TypedValue((int)LispDataType.Text, name));
foreach (object val in args)
{
AddValueToResultBuffer(ref rbArgs, val);
}
return CallLispFunction(rbArgs);
}
internal static ResultBuffer GetLispSym(string name)
{
IntPtr ip = IntPtr.Zero;
acedGetSym(name, out ip);
if (ip != IntPtr.Zero)
{
ResultBuffer rbRes = ResultBuffer.Create(ip, true);
return rbRes;
}
return null;
}
#endregion
}
}
测试代码,结合ResultList/ResultTree类
public static void Test11()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityResult res1 = ed.GetEntity("\nSelect a Entity:");
InvokeArx.CmdEcho = false;
InvokeArx.Command(
false,
new ResultTree
{
"break",
new ResultTree(ResultType.List)
{
res1.ObjectId,
res1.PickedPoint
},
res1.PickedPoint
});
InvokeArx.CmdEcho = true;
}