在COM挂起AutoCAD中保存

时间:2010-02-18 10:31:38

标签: autocad objectarx

我正在实现一个应用程序,该应用程序在AutoCAD的ObjectARX界面中使用COM来自动执行绘图操作,例如打开和另存为。

根据文档,我应该能够调用AcadDocument.SaveAs()并传入文件名,“另存为类型”和安全参数。文档明确声明如果安全性为NULL,则不会尝试与安全性相关的操作。但是,它不会将正确的对象类型指示为“另存为类型”参数。

我尝试使用文件名调用SaveAs并为其余参数调用null,但我的应用程序挂起该方法调用并且AutoCAD似乎崩溃 - 您仍然可以使用功能区但无法对工具栏执行任何操作并且可以不要关闭AutoCAD。

我有一种感觉,这是我的NULL参数导致悲痛,但COM / VBA部门的文档严重缺乏。实际上它说AcadDocument类甚至没有SaveAs方法,它显然也是如此。

这里有没有人实现同样的事情?有什么指导吗?

另一种方法是使用SendCommand()方法发送_SAVEAS命令,但我的应用程序正在管理一批绘图,需要知道a)保存是否失败,以及b)保存完成时(我是通过收听EndSave事件来做。)

修改

以下是所要求的代码 - 它所做的只是启动AutoCAD(或连接到正在运行的运行实例),打开现有图形,然后将文档保存到新位置(C:\ Scratch \ Document01B.dwg 。)

using (AutoCad cad = AutoCad.Instance)
{
    // Launch AutoCAD
    cad.Launch();

    // Open drawing
    cad.OpenDrawing(@"C:\Scratch\Drawing01.dwg");

    // Save it
    cad.SaveAs(@"C:\Scratch\Drawing01B.dwg");
}

然后在我的AutoCad类中(this._acadDocument是AcadDocument类的一个实例。)

public void Launch()
{
    this._acadApplication = null;
    const string ProgramId = "AutoCAD.Application.18";

    try
    {
        // Connect to a running instance
        this._acadApplication = (AcadApplication)Marshal.GetActiveObject(ProgramId);
    }
    catch (COMException)
    {
        /* No instance running, launch one */

        try
        {
            this._acadApplication = (AcadApplication)Activator.CreateInstance(
                Type.GetTypeFromProgID(ProgramId), 
                true);
        }
        catch (COMException exception)
        {
            // Failed - is AutoCAD installed?
            throw new AutoCadNotFoundException(exception);
        }
    }

    /* Listen for the events we need and make the application visible */
    this._acadApplication.BeginOpen += this.OnAcadBeginOpen;
    this._acadApplication.BeginSave += this.OnAcadBeginSave;
    this._acadApplication.EndOpen += this.OnAcadEndOpen;
    this._acadApplication.EndSave += this.OnAcadEndSave;

#if DEBUG
    this._acadApplication.Visible = true;
#else
    this._acadApplication.Visible = false;
#endif

    // Get the active document
    this._acadDocument = this._acadApplication.ActiveDocument;
}

public void OpenDrawing(string path)
{
    // Request AutoCAD to open the document
    this._acadApplication.Documents.Open(path, false, null);

    // Update our reference to the new document
    this._acadDocument = this._acadApplication.ActiveDocument;
}

public void SaveAs(string fullPath)
{
    this._acadDocument.SaveAs(fullPath, null, null);
}

4 个答案:

答案 0 :(得分:2)

在Autodesk discussion groups中,看起来第二个参数是要保存的类型,可能是必需的:

app = new AcadApplicationClass();
AcadDocument doc = app.ActiveDocument; doc.SaveAs("d:\Sam.dwg",AcSaveAsType.acR15_dwg,new Autodesk.AutoCAD.DatabaseServices.SecurityParameters());

由于您使用的是AutoCAD 2010,因此类型应增加到acR17_dwg或acR18_dwg。

答案 1 :(得分:1)

通过AutoDesk关于这个主题的论坛的链接来判断,听起来就像你需要在保存后关闭对象...并删除null ...如果我是你,我会将代码包装到try / catch块中以检查并确保没有抛出异常!

我必须质疑using子句的用法,因为你Launch另一个副本不是吗?即在您使用的OpenDrawingSave函数内this._acadApplication或我误解了吗?

using (AutoCad cad = AutoCad.Instance)
{
    try{
       // Launch AutoCAD
       cad.Launch();

       // Open drawing
       cad.OpenDrawing(@"C:\Scratch\Drawing01.dwg");

       // Save it
       cad.SaveAs(@"C:\Scratch\Drawing01B.dwg");
    }catch(COMException ex){
       // Handle the exception here
    }
}

public void Launch()
{
    this._acadApplication = null;
    const string ProgramId = "AutoCAD.Application.18";

    try
    {
        // Connect to a running instance
        this._acadApplication = (AcadApplication)Marshal.GetActiveObject(ProgramId);
    }
    catch (COMException)
    {
        /* No instance running, launch one */

        try
        {
            this._acadApplication = (AcadApplication)Activator.CreateInstance(
                Type.GetTypeFromProgID(ProgramId), 
                true);
        }
        catch (COMException exception)
        {
            // Failed - is AutoCAD installed?
            throw new AutoCadNotFoundException(exception);
        }
    }

    /* Listen for the events we need and make the application visible */
    this._acadApplication.BeginOpen += this.OnAcadBeginOpen;
    this._acadApplication.BeginSave += this.OnAcadBeginSave;
    this._acadApplication.EndOpen += this.OnAcadEndOpen;
    this._acadApplication.EndSave += this.OnAcadEndSave;

#if DEBUG
    this._acadApplication.Visible = true;
#else
    this._acadApplication.Visible = false;
#endif

    // Get the active document
    // this._acadDocument = this._acadApplication.ActiveDocument; 
    // Comment ^^^ out? as you're instantiating an ActiveDocument below when opening the drawing?
}

public void OpenDrawing(string path)
{
    try{
       // Request AutoCAD to open the document
       this._acadApplication.Documents.Open(path, false, null);

       // Update our reference to the new document
       this._acadDocument = this._acadApplication.ActiveDocument;
    }catch(COMException ex){
       // Handle the exception here
    }
}

public void SaveAs(string fullPath)
{
    try{
       this._acadDocument.SaveAs(fullPath, null, null);
    }catch(COMException ex){
       // Handle the exception here
    }finally{
       this._acadDocument.Close();
    }
}

我以为我会提供一些链接供您参考。

希望这有帮助, 最好的祝福, 汤姆。

答案 2 :(得分:0)

我已经设法以非最佳,非常不完美的方式解决这个问题,所以我仍然有兴趣听听是否有人知道为什么SaveAs方法会崩溃AutoCAD并挂起我的应用程序。

我是这样做的:

打开文档或创建新文档时,请关闭打开/保存对话框:

this._acadDocument.SetVariable("FILEDIA", 0);

保存文档时,发出_ASVEAS命令,传入“2010”作为格式和文件名(fullPath):

string commandString = string.Format(
    "(command \"_SAVEAS\" \"{0}\" \"{1}\") ",
    "2010",
    fullPath.Replace('\\', '/'));

this._acadDocument.SendCommand(commandString);

退出AutoCAD时,返回文件对话框提示重新开启(可能不是必需但只是确保):

this._acadDocument.SetVariable("FILEDIA", 1);

答案 3 :(得分:0)

使用C#和COM时,如果有可选参数,则需要使用Type.Missing而不是null:

this._acadDocument.SaveAs(fullPath, Type.Missing, Type.Missing);

但是从Visual Studio 2010开始,您可以简单地省略可选参数:

this._acadDocument.SaveAs(fullPath);