在 COM 中另存为挂 AutoCAD

发布于 2024-08-22 04:49:36 字数 2597 浏览 5 评论 0原文

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

根据文档,我应该能够调用 AcadDocument.SaveAs() 并传入文件名、“保存类型”和安全参数。该文档明确指出,如果 security 为 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);
}

I'm implementing an application which uses COM in AutoCAD's ObjectARX interface to automate drawing actions, such as open and save as.

According to the documentation, I should be able to call AcadDocument.SaveAs() and pass in a filename, a "save as type" and a security parameter. The documentation explicitly statses that if security is NULL, no security related operation is attempted. It doesn't, however, give any indication of the correct object type to pass as the "save as type" parameter.

I've tried calling SaveAs with a filename and null for the remaining arguments, but my application hangs on that method call and AutoCAD appears to crash - you can still use the ribbon but can't do anything with the toolbar and can't close AutoCAD.

I've got a feeling that it's my NULL parameters causing grief here, but the documentation is severely lacking in the COM/VBA department. In fact it says the AcadDocument class doesn't even have a SaveAs method, which it clearly does.

Has anyone here implemented the same thing? Any guidance?

The alternative is I use the SendCommand() method to send a _SAVEAS command, but my application is managing a batch of drawing and needs to know a) if the save fails, and b) when the save completes (which I'm doing by listening to the EndSave event.)

EDIT

Here's the code as requested - all it's doing is launching AutoCAD (or connecting to the running instance if it's already running), opening an existing drawing, then saving the document to a new location (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");
}

Then in my AutoCad class (this._acadDocument is an instance of the AcadDocument class.)

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心的位置 2024-08-29 04:49:36

从 Autodesk 讨论组,看起来第二个参数是要保存的类型,并且可能是必需的:


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。

From the Autodesk discussion groups, it looks like the second parameter is the type to save as, and may be required:


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

Since you are in AutoCAD 2010, the type should be incremented to acR17_dwg or acR18_dwg.

忆伤 2024-08-29 04:49:36

从关于此主题的 AutoDesk 论坛的链接来看,它听起来好像您需要在保存后关闭对象...并删除 null 的...如果我是您,我会将代码包装到 try/catch 块来检查并确保没有抛出异常!

我不得不质疑 using 子句的用法,因为您正在启动另一个副本,不是吗?即在 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();
    }
}

我想我会添加一些链接以供您参考。

希望这有帮助,
此致,
汤姆.

Judging by the link to AutoDesk's forum on this topic, it sounds like as you need to close the object after saving...and remove the null's...If I were you, I'd wrap up the code into try/catch blocks to check and make sure there's no exception being thrown!

I have to question the usage of the using clause, as you're Launching another copy aren't you? i.e. within the OpenDrawing and Save functions you are using this._acadApplication or have I misunderstood?

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();
    }
}

Thought I'd include some links for your information.

Hope this helps,
Best regards,
Tom.

后知后觉 2024-08-29 04:49:36

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

我是这样做的:

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

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

保存文档时,发出 _SAVEAS 命令,传入“2010”作为格式和文件名(完整路径):

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

this._acadDocument.SendCommand(commandString);

当退出 AutoCAD 打开文件对话框提示重新打开(可能没有必要,但只是确保):

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

I've managed to solve this in a non-optimal, very imperfect way so I'd still be interested to hear if anyone knows why the SaveAs method crashes AutoCAD and hangs my application.

Here's how I did it:

When opening a document or creating a new one, turn off the open/save dialog boxes:

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

When saving a document, issue the _SAVEAS command passing in "2010" as the format and the filename (fullPath):

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

this._acadDocument.SendCommand(commandString);

When exiting AutoCAD turn file dialog prompting back on (probably isn't necessary but just makes sure):

this._acadDocument.SetVariable("FILEDIA", 1);
我不咬妳我踢妳 2024-08-29 04:49:36

对于 C# 和 COM,当有可选参数时,您需要使用 Type.Missing 而不是 null:

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

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

this._acadDocument.SaveAs(fullPath);

With C# and COM, when there are optional arguments, you need to use Type.Missing instead of null:

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

But since Visual Studio 2010, you can simply omit the optional arguments:

this._acadDocument.SaveAs(fullPath);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文