从现有.NET应用程序启动AutoCAD 2013并写入窗口

时间:2014-01-28 20:43:40

标签: c# .net dll managed autocad

我尝试从现有的C#桌面应用程序启动AutoCAD 2013,使用数据库值绘制图表,然后将绘图作为可变位数组(varbyte)保存到数据库。除了将坐标放入现有的AutoCAD编辑器窗口之外,我在所有方面取得了很大的成功。

我尝试过NETLOAD,但是我无法通过命令行列出55个以上的AutoCAD Database Circle对象。试图通过COM Interop传递对象已经遇到了AutoCAD和我的应用程序的32位与64位状态的失败和混淆。虽然这个网站很有用,http://through-the-interface.typepad.com/,但我无法完成我想要的工作。

任何建议都将不胜感激。感谢。

编辑:

我接受了Locke的建议,并且我在.NET DLL中添加了函数,以根据简单的参数(如X,Y坐标,半径,标签等)绘制单个项目。以下是方法签名的样子:

[CommandMethod("DrawSmallCircle", CommandFlags.Session)]
public static void DrawSmallCircle(double x, double y, double aRadius, string aGuage, string aLabel, string aTitle)

在网上加载承载上述方法的.dll(并且它包含类)之后,我在实例化的互操作AcadApplication上使用SendCommand,如下所示:

acApp.ActiveDocument.SendCommand("DrawSmallCircle " +
circ.circle.Center.X.ToString() + ", " +
circ.circle.Center.Y.ToString() + ", " +
circ.circle.Radius.ToString() + ", " +
circ.guage + ", " +
circ.label + ", " +
circ.title + " "
);

不幸的是,我得到的错误只是“公共语言运行时检测到无效程序”。

我不确定在我的.dll中注册命令是否会有任何好处,因为据称“命令方法不能接受参数,但lispFunctions可以。”

  

http://forums.autodesk.com/t5/NET/CommandMethod-with-custom-params/td-p/2572973

1 个答案:

答案 0 :(得分:3)

好的,所以你遇到了Interop / In-Process自动化问题。传统上,AutoCAD不希望让流程模块与进程内模块进行通信,至少在来回发送参数的上下文中是这样。涉及注册进程内COM接口的形式方法对于正确行为具有挑战性,尤其是在x64位的上下文中。我还没有看到它在多台计算机上表现一致,因此我倾向于采用以下方法。

你是正确的,用[CommandMethod]标志标记的方法不能接受参数,因此它们显然需要是空洞。在运行时发送参数上下文的技巧是在定义的方法本身中包含参数提示。当您在AutoCAD中开发用户调用的命令时,可以考虑它,并在命令可以继续之前提示它们输入每​​个数据。与其他原生AutoCAD命令非常相似,参数数据可以在单个字符串中与命令一起发送。

实施例:

(命令“._CIRCLE”“0,0”“5”)< - 在半径为5的0,0处画一个圆圈。

所以你的命令调用最终会看起来像这样:

(命令“DRAWDBCIRCLE”“2.3,56.12”,“7”“Gauge”“Label”“Title”)

进程中代码

[CommandMethod("DRAWDBCIRCLE")]
public void DrawDbCircle()
{
    var acDb = HostApplicationServices.WorkingDatabase;
    var acEd = Application.DocumentManager.MdiActiveDocument.Editor;

    using (var acTrans = acDb.TransactionManager.StartOpenCloseTransaction())
    {
        var bt = (BlockTable)acTrans.GetObject(acDb.BlockTableId, OpenMode.ForWrite);
        var btr = (BlockTableRecord)acTrans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

        Point3d centerPoint;
        double radius;
        string gauge, label, title;

        // Prompt for the centerpoint
        var pointResult = acEd.GetPoint("ENTER CIRCLE ORIGIN: \n");
        centerPoint = pointResult.Value;

        // Prompt for the radius
        var doubleResult = acEd.GetDouble("ENTER CIRCLE RADIUS: \n");
        radius = doubleResult.Value;

        // Prompt for the strings
        var stringResult = acEd.GetString("ENTER CIRCLE GAUGE: \n");
        gauge = stringResult.StringResult;
        stringResult = acEd.GetString("ENTER CIRCLE LABEL: \n");
        label = stringResult.StringResult;
        stringResult = acEd.GetString("ENTER CIRCLE TITLE: \n");
        title = stringResult.StringResult;

        // Create the circle
        var circ = new Circle(centerPoint, Vector3d.ZAxis, radius);
        // <-- Add code for dealing with strings -->
        btr.AppendEntity(circ);
        acTrans.AddNewlyCreatedDBObject(circ, true);

        acTrans.Commit();
    }
}

互操作代码

private AcadApplication acApp;
private AcadDocument acDoc;

private void btnRun_Click(object sender, EventArgs e)
{
    if (acApp == null) return;
    acDoc = acApp.ActiveDocument;

    foreach (DataRow row in circleTable.Rows)
        DrawDatabaseCircle(row);
}

private void DrawDatabaseCircle(DataRow circRow)
{
    var cmdFormat = string.Format("\"{0},{1}\" \"{2}\" \"{3}\" \"{4}\" \"{5}\"", circRow.ItemArray);
    acDoc.SendCommand(string.Format("(Command \"DRAWDBCIRCLE\" {0})\n", cmdFormat));
}

显然这或多或少是伪代码。我假设这里有很多东西,比如正确设置的AcadApplication和AcadDocument字段,包含已定义命令方法的dll已正确上网,并且数据库圈来自DataTable。命令方法中需要进行错误处理以检查参数,将sendCommand方法包含在try / catch中是有意义的。

这种技术实际上只有在您拥有可以用字符串表示的数据类型时才有效,因此它不会涵盖所有情况。绝对值得尝试让COM注册接口长期工作,以便在输入/输出过程之间进行更强大的通信。