Kean Walmsley

July 2009

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Twitter Updates

    follow me on Twitter



    « Getting access to an entity from its handle in AutoCAD .NET | Main | Allowing users to escape from long operations in AutoCAD .NET »

    February 21, 2007

    Using the COM interface for AutoCAD objects from .NET

    This question came in a couple of weeks ago from csharpbird, and I promised myself to turn it into a post:

    The Hatch class of the current AutoCAD version does not provide the OriginPoint property.How to get/set the OriginPoint of the Hatch object using P/Invoke?

    The reason I wanted to delay making an official post is that I have good news (that I couldn't talk about until the product was announced): the Autodesk.AutoCAD.DatabaseServices.Hatch object now has an Origin property in AutoCAD 2008. :-)

    But this does raise an interesting topic - how to get at information that isn't available through the managed interface? P/Invoke is an option for access certain ObjectARX functions, but as stated in this previous post, it cannot be used with instance members, such as AcDbHatch methods.

    This particular property (a Hatch's Origin) has been exposed for a few releases through COM; Property Palette support for object properties sometimes drives their COM exposure more quickly than their "managed" exposure (although increasingly the .NET API is there right from the beginning).

    Anyway, here's some C# code for AutoCAD 2007 that accesses the COM interface for a hatch object, returning the Origin property. The code first gets the object as a managed hatch, simply to show a technique for going from a managed object to a COM object:

    [Update: this is Version 1 of the code, posted before Albert's comment, below. Scroll down for the more elegant Version 2...]


    using Autodesk.AutoCAD.ApplicationServices;

    using Autodesk.AutoCAD.DatabaseServices;

    using Autodesk.AutoCAD.EditorInput;

    using Autodesk.AutoCAD.Runtime;

    using Autodesk.AutoCAD.Interop;

    using System.Runtime.InteropServices;


    namespace HatchQuery

    {

      public class HatchQueryCommands

      {

        [CommandMethod("QH")

        ]

        public void QueryHatchOrigin()

        {

          Document doc =

            Application.DocumentManager.MdiActiveDocument;

          Editor ed = doc.Editor;


          try

          {

            PromptEntityResult per =

              ed.GetEntity("\nSelect hatch object: ");


            if (per.Status == PromptStatus.OK)

            {

              Transaction tr =

                doc.TransactionManager.StartTransaction();

              using (tr)

              {

                // Open up the object

                DBObject obj =

                  tr.GetObject(per.ObjectId, OpenMode.ForRead);


                // Make sure we have a managed hatch object

                Hatch hat = obj as Hatch;

                if (hat != null)

                {

                  // Now let's pretend we had our managed hatch,

                  // and need to use COM to get at its Origin

                  Autodesk.AutoCAD.Interop.AcadApplication oAcad =

                    (AcadApplication)Marshal.GetActiveObject(

                      "AutoCAD.Application.17"

                    );


                  // Let's use the COM API to get a COM reference

                  // to the hatch (as a base object)

                  object obj2 =

                    oAcad.ActiveDocument.ObjectIdToObject(

                      obj.ObjectId.OldId

                    );


                  // Let's convert that object reference to

                  // a COM hatch

                  Autodesk.AutoCAD.Interop.Common.AcadHatch oHat =

                    obj2 as

                    Autodesk.AutoCAD.Interop.Common.AcadHatch;


                  if (oHat != null)

                  {

                    // Now let's get the Origin as an array

                    // of doubles, and print the contents

                    double[] orig = (double[])oHat.Origin;

                    ed.WriteMessage(

                      "\nHere's the hatch origin: X: " +

                      orig[0] + ", Y: " + orig[1]

                    );

                  }

                }

              }

            }

          }

          catch (System.Exception ex)

          {

            ed.WriteMessage(

              "Exception: " + ex

            );

          }

        }

      }

    }

    Version 2:

    using Autodesk.AutoCAD.ApplicationServices;

    using Autodesk.AutoCAD.DatabaseServices;

    using Autodesk.AutoCAD.EditorInput;

    using Autodesk.AutoCAD.Runtime;

    using Autodesk.AutoCAD.Interop;

    using System.Runtime.InteropServices;


    namespace HatchQuery

    {

      public class HatchQueryCommands

      {

        [CommandMethod("QH")

        ]

        public void QueryHatchOrigin()

        {

          Document doc =

            Application.DocumentManager.MdiActiveDocument;

          Editor ed = doc.Editor;


          try

          {

            PromptEntityResult per =

              ed.GetEntity("\nSelect hatch object: ");


            if (per.Status == PromptStatus.OK)

            {

              Transaction tr =

                doc.TransactionManager.StartTransaction();

              using (tr)

              {

                // Open up the object

                DBObject obj =

                  tr.GetObject(per.ObjectId, OpenMode.ForRead);


                // Make sure we have a managed hatch object

                Hatch hat = obj as Hatch;

                if (hat != null)

                {

                  // a COM hatch

                  Autodesk.AutoCAD.Interop.Common.AcadHatch oHat =

                    obj.AcadObject as

                    Autodesk.AutoCAD.Interop.Common.AcadHatch;


                  if (oHat != null)

                  {

                    // Now let's get the Origin as an array

                    // of doubles, and print the contents

                    double[] orig = (double[])oHat.Origin;

                    ed.WriteMessage(

                      "\nHere's the hatch origin: X: " +

                      orig[0] + ", Y: " + orig[1]

                    );

                  }

                }

              }

            }

          }

          catch (System.Exception ex)

          {

            ed.WriteMessage(

              "Exception: " + ex

            );

          }

        }

      }

    }

    And here's what happens when you run the code and select a hatch with an origin of 50,30:

    Command: QH

    Select hatch object:

    Here's the hatch origin: X: 50, Y: 30

    TrackBack

    TrackBack URL for this entry:
    http://www.typepad.com/services/trackback/6a00d83452464869e200d8341fa83c53ef

    Listed below are links to weblogs that reference Using the COM interface for AutoCAD objects from .NET:

    Comments

    This code could be simplified by using the DBObject.AcadObject property. This propery provides the "COM object" for a ".net object". There's also a static FromAcadObject method to go the other way around.

    Albert

    Kean, Albert ;

    Thank you.

    using Autodesk.AutoCAD.EditorInput;
    when using this for some reason the vs05 does nor give me the EditorInput as a choice could you pleas let me know what i'm doing wrong. sorry this is a elementry question but i'm very new to this. thank you for your patience.

    My first instinct would be to check the assembly references, to make sure they’re to the correct version. You haven’t mentioned which release of AutoCAD you’re working with, but this shouldn’t matter – I believe this namespace existed from when we introduced the .NET layer in AutoCAD.

    I’d suggest trying removing and re-adding the assembly references to acmgd.dll and acdbmgd.dll, to see if that helps.

    Hi Kean


    Great blog, thanks. Could you also show how to get from AcadObject to a Autocad Mechanical in my case a McadSymbol object?


    Cheers
    Tore

    Sorry


    My question was wrong. Asumed the McadSymbol was the equivalent of the AMDTNOTE object in ACAD M.

    If you know what to object to cast too in .NET using COM, feel free to answer.


    Regards
    Tore

    Adam Nagy, a member of the DevTech team in Prague, told me of a DevNote he'd published to the ADN site on this topic:

    >>>
    At this time there is no API support for AmdtNote objects. One possible workaround is using the AMEDIT command. Here are a couple of examples showing this approach.


    1) This C# example uses the AutoCAD COM API:

    private void button1_Click(object sender, System.EventArgs e)
    {
    AcadApplication app = (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application");

    AcadEntity ent;
    double []pt = new double [2];

    AcadDocument drawing = app.ActiveDocument;
    Object out1, out2;
    drawing.Utility.GetEntity(out out1, out out2, "Select a AMDTNOTE :");
    ent = (AcadEntity)out1;
    pt = (Double[])out2;

    drawing.SetVariable("CMDDIA", 0);
    drawing.SendCommand("AMEDIT (handent \"" + ent.Handle + "\") " + "\n");

    string str = (String)drawing.GetVariable("LASTPROMPT");

    drawing.SendCommand("");
    drawing.SetVariable("CMDDIA", 1);

    int start = str.IndexOf("<");
    System.Windows.Forms.MessageBox.Show(str.Substring(start + 2, (str.Length - 5) - start));
    }


    2) This example uses the AutoCAD .NET API. (acedCmd is enabled through PInvoke)


    [DllImport("acad.exe", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedCmd")]
    private static extern int acedCmd(System.IntPtr vlist);

    [CommandMethod("AsdkCmd1")]
    static public void test()
    {
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;

    ObjectId entId = ed.GetEntity("Select AmdtNote...").ObjectId;

    Application.SetSystemVariable("CMDDIA", 0);

    ResultBuffer rb = new ResultBuffer();
    rb = new ResultBuffer();
    rb.Add(new TypedValue(5005, "AMEDIT"));
    rb.Add(new TypedValue(5006, entId));
    rb.Add(new TypedValue(5005, "")); //"\n"));
    acedCmd(rb.UnmanagedObject);

    string str = (String)Application.GetSystemVariable("LASTPROMPT");

    Application.SetSystemVariable("CMDDIA", 1);

    int start = str.IndexOf("<");
    string strText = str.Substring(start + 2, (str.Length - 5) - start);
    }

    <<<

    sir,

    am new to this objectarx programming through c#.
    i tried the above code for hatch, but i hve problem relating to
    "using Autodesk.AutoCAD.Interop;" where am not getting the ".interop"
    please help me with the above.....

    regards
    vinay t tharakan

    Vinay -

    You will need to add a project references to AutoCAD's Type Libraries.

    Project -> Add Reference... -> COM -> Select "AutoCAD 200x Type Library" and "AutoCAD/ObjectDBX Common 17.0 Type Library".

    Regards,

    Kean

    thanks for the help sir......

    I'm converting handles into object ids as shown above using Autocad 2007. It works fine for an object, unless that object is a copy of another object. It then throws a null exception, even though the object is there. How can I get around this?

    Thanks,
    Derek

    Derek -

    It's not clear what you mean by a copy. And which code do you mean - code in the post itself (which doesn't deal with handles) or in one of the comments?

    I suggest posting some code to via ADN support, if you're a member, or otherwise someone on the AutoCAD .NET Discussion Group may be able to help.

    Kean

    Verify your Comment

    Previewing your Comment

    This is only a preview. Your comment has not yet been posted.

    Working...
    Your comment could not be posted. Error type:
    Your comment has been posted. Post another comment

    The letters and numbers you entered did not match the image. Please try again.

    As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

    Having trouble reading this image? View an alternate.

    Working...

    Post a comment

    Feed & Share

    Search