How to create .Net app to use with multiple versions of AutoCAD (2013-2017)

How to create .Net app to use with multiple versions of AutoCAD (2013-2017)

Anonymous
Not applicable
3,132 Views
10 Replies
Message 1 of 11

How to create .Net app to use with multiple versions of AutoCAD (2013-2017)

Anonymous
Not applicable

I am developing .Net application that use AutoCAD. I want application to wok with multiple versions i.e A2013 to A2017. currently i need to create different application for each version of AutoCAD. The library i am referencing is  AutoCAD 2017 Type Libray, but it does not work with A2013 or A2016.

I tested with objectARX 2017 interop dlls , but not working.

0 Likes
Accepted solutions (1)
3,133 Views
10 Replies
Replies (10)
Message 2 of 11

_gile
Consultant
Consultant

Hi,

 

As it seems you're using the COM API (Autodesk.AutoCAD.Interop.dll and Autodesk.AutoCAD.Interop.Common.dll), you have to compile a different assembly at least for each AutoCAD major version (R19 for 2013-2014, R20 for 2015-2016, R21 for 2017 and R22 for 2018-?) even if the source code remains the same.

To avoid this, you can use late binding (with the dynamic type in C#) instead of referencing interop libraries.

 

With the AutoCAD .NET API, most of assemblies build for AutoCAD 2013 can be run up to A2018.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 11

Anonymous
Not applicable

Thanks for reply. Could you give a URL to sample code which use the method you mentioned. What i understood is use of proxy class method instead of referencing AutoCAD dlls. 

0 Likes
Message 4 of 11

_gile
Consultant
Consultant
Accepted solution

For a general purpose about the dynamic type, you can start with this topic.

 

Here's a trivial example using the AutoCAD COM API in a standalone application (the only context which requires COM using).

 

Referencing AutoCAD 19 interop libraries, this application will only work with AutoCAD 3013 and 3014 (the main interest is Visual Studio intellisense works).

 

using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace EarlyBindingStandaloneSample
{
    class Program
    {
        static void Main(string[] args)
        {
            AcadApplication acadApp;
            // check if a AutoCAD session exists
            try
            {
                acadApp = (AcadApplication)Marshal.GetActiveObject("AutoCAD.Application.19");
            }
            catch
            {
                // if there is no AutoCAD session active then there will be one created
                try
                {
                    acadApp = (AcadApplication)Activator.CreateInstance(
                        Type.GetTypeFromProgID("AutoCAD.Application.19"), true);
                }
                catch
                {
                    MessageBox.Show("Unable to start AutoCAD 19.");
                    return;
                }
            }

            // if successful set visibility status
            while (true)
            {
                try { acadApp.Visible = true; break; }
                catch { }
            }
            acadApp.WindowState = AcWindowState.acMax;

            // get AutoCAD active document
            AcadDocument acadDoc = acadApp.ActiveDocument;

            // add a circle to de active document model space
            AcadCircle circle = acadDoc.ModelSpace.AddCircle(new[] { 20.0, 10.0, 0.0 }, 10.0);
            circle.color = ACAD_COLOR.acRed;
            acadApp.ZoomWindow(new[] { 5.0, -5.0, 0.0 }, new[] { 35.0, 25.0, 0.0 });

        }
    }
}

The same app using late binding with the 'dynamic' type, this application should work with every AutoCAD version. Typically, just remove references to AutoCAD interop from the upper code and repair the errors due to AutoCAD COM types missing by using the dynamic type and the enumeration integer equivalences.

 

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace LateBindingStandaloneSample
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic acadApp;
            // check if a AutoCAD session exists
            try
            {
                acadApp = Marshal.GetActiveObject("AutoCAD.Application");
            }
            catch
            {
                // if there is no AutoCAD session active then there will be one created
                try
                {
                    acadApp = Activator.CreateInstance(
                        Type.GetTypeFromProgID("AutoCAD.Application"), true);
                }
                catch
                {
                    MessageBox.Show("Unable to start AutoCAD.");
                    return;
                }
            }

            // if successful set visibility status
            while (true)
            {
                try { acadApp.Visible = true; break; }
                catch { }
            }
            acadApp.WindowState = 3;

            // get AutoCAD active document
            var acadDoc = acadApp.ActiveDocument;

            // add a circle to de active document model space
            var circle = acadDoc.ModelSpace.AddCircle(new[] { 20.0, 10.0, 0.0 }, 10.0);
            circle.color = 1;
            acadApp.ZoomWindow(new[] { 5.0, -5.0, 0.0 }, new[] { 35.0, 25.0, 0.0 });

        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 11

Anonymous
Not applicable

could you help me with some issues i am facing,

 

public class AutoCADBase 
{
//.......

dynamic _ZoomItems;// = new AcadEntity[0];

//......


	public void ZoomHandleObjects(string[] _ObjHandles)
        {
            for (int _Index = 0; _Index < _ObjHandles.Length; _Index++)
            {
                try
                {
                    Array.Resize(ref _ZoomItems, _ZoomItems.Length + 1);
                    _ZoomItems[_ZoomItems.Length - 1] = (AcadEntity)_Doc.HandleToObject(_ObjHandles.GetValue(_Index).ToString());
                }
                catch (Exception)
                {
                    throw;
                }
            }

            GroupAndZoom();
        }

}

In the above code snip '_ZoomItems' type 'AcadEntity' is need to use in the function. Also how to dynamic type cast 'AcadEntity' from Doc.HandleToObject. Thanks in advance.

 

0 Likes
Message 6 of 11

_gile
Consultant
Consultant

Hi,

 

First, you do not need to call ResizeArray() at each loop as you already know the array size (the same size as the _ObjHandles array)*.

 

Second, you should choose if you want to use early binding with strong and static types or late binding with dynamic type, but there's no interest to mix both (at least in your example).

 

using early binding:

        AcadEntity[] _ZoomItems;

        public void ZoomHandleObjects(string[] _ObjHandles)
        {
            _ZoomItems = new AcadEntity[_ObjHandles.Length];
            for (int _Index = 0; _Index < _ObjHandles.Length; _Index++)
            {
                try
                {
                    _ZoomItems[_Index] = (AcadEntity)_Doc.HandleToObject(_ObjHandles[_Index].ToString());
                }
                catch (Exception)
                {
                    throw;
                }
            }
            GroupAndZoom();
        }

using late binding:

 

        dynamic[] _ZoomItems;

        public void ZoomHandleObjects(string[] _ObjHandles)
        {
            _ZoomItems = new dynamic[_ObjHandles.Length];
            for (int _Index = 0; _Index < _ObjHandles.Length; _Index++)
            {
                try
                {
                    _ZoomItems[_Index] = _Doc.HandleToObject(_ObjHandles[_Index].ToString());
                }
                catch (Exception)
                {
                    throw;
                }
            }
            GroupAndZoom();
        }

 

* .NET provides many generic collection types including List<T> which is mainly a resizable array.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 11

Anonymous
Not applicable

 

object _MinPoints = new double[3];
object _MaxPoints = new double[3];

foreach (var _Item in _ZoomItems) // _ZoomItems = AcadEntity[] (dynamic) { _Item.GetBoundingBox(out _MinPoints, out _MaxPoints); <= exception.

i am getting exception when calling _Item.GetBoundingBox function. how to resolve this

 

 

Stack Trace

 

{System.Runtime.InteropServices.COMException (0x80020010): Invalid callee. (Exception from HRESULT: 0x80020010 (DISP_E_BADCALLEE))
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)
at CallSite.Target(Closure , CallSite , ComObject , Object& , Object& )
at CallSite.Target(Closure , CallSite , ComObject , Object& , Object& )
at CallSite.Target(Closure , CallSite , Object , Object& , Object& )
at CallSite.Target(Closure , CallSite , Object , Object& , Object& )
...

0 Likes
Message 8 of 11

_gile
Consultant
Consultant

You must not initialize _MinPoint and _MaxPoint and you should declare them 'dynamic' so that their real type will be automatically determined at run time.

 

dynamic _MinPoints, _MaxPoints;

foreach (var _Item in _ZoomItems) // _ZoomItems = AcadEntity[] (dynamic)
{
     _Item.GetBoundingBox(out _MinPoints, out _MaxPoints);

If you do not absolutely need to use the COM API (i.e. building a standalone application) these thinks should be much more simple in plain .NET...



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 11

Anonymous
Not applicable

i have similar error mentioned in this link https://forums.autodesk.com/t5/net/passing-late-bound-variant-array-to-group/td-p/5404201?nobounce

 

dynamic[] _HatchObjs= new dynamic[0];
dynamic _ObjGroup;

_ObjGroup.AppendItems(_HatchObjs);  // <= exception - "Invalid object array"

 

 

How to solve this ?

 

 

0 Likes
Message 10 of 11

_gile
Consultant
Consultant

Hi,

 

Things become much more complicated when using late binding with COM variants.

If you absolutely need to use the COM API (instead of plain .NET API) and these ugly variants, it should be simpler to use early binding and build a project per AutoCAD major version all these projects can share the same code).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 11 of 11

Alexander.Rivilis
Mentor
Mentor

@_gile

 


@_gile wrote:

 

Referencing AutoCAD 19 interop libraries, this application will only work with AutoCAD 3013 and 3014 (the main interest is Visual Studio intellisense works).


Beautiful joke turned out!

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

0 Likes