Visual Studio Versions and Inventor Interop

rjay75
Collaborator
Collaborator

Visual Studio Versions and Inventor Interop

rjay75
Collaborator
Collaborator

Has anyone else run into this issue? I'm in the process of finally updating my Addins for 2016/2017 and thought I would take the opportunity to also move my projects to Visual Studio 2015 so I could take advantage of some of the new C# 6 language features.

 

As seen in this post (parameter.get_Units() vs. parameter.Units) the Inventor interop doesn't always line up nicely with C#. Using Visual Studio 2015 the same issue still exists. However even though the project compiles fine it throws a member not found exception when trying to resolve parameter.get_Units() method. The CommandType enum also sometimes shows an error in the editor but compiles ok. Reverted back to VS 2013 and the same code works fine. I know the VS uses the new Roslyn C# compiler so I'm wondering if it's something to do with that or if it's something with my .NET installation.

0 Likes
Reply
Accepted solutions (1)
3,223 Views
10 Replies
Replies (10)

xiaodong_liang
Autodesk Support
Autodesk Support
Hi Rodney ,

This sounds a like a legacy issue while what we have known it does not either work in VS2013. The workaround is to call the get_Units and set_Units methods separately instead of using the Units property.

Could you provide some code sample on the issue of VS2015, thus we can make sure if it is the same issue we have known above.
0 Likes

rjay75
Collaborator
Collaborator

I think I've figured out the issue. It has to deal with how the Inventor interop is referenced. In updating my reference from 2013 to 2015 I didn't realize I had the interop marked to be embedded.

 

It seems with the 2015 interop set to embed the reference using Visual Studio 2015 it has resolution issues. Of not is it also compiles to the largest dll size too. If you're not careful in setting the reference it will mark it to embed. If it's set to true the resolution error happens. Making sure it's set to false allows it to work.

 

IV_interop.png

 

In the sample there are 4 dlls. To test them place them in your iLogic Dlls Addin folder. Rename the dll you're testing to test IVApiTest.dll.

 

Create a rule with the following code to run the test sample.

 

AddReference "IVApiTest.dll"
Imports IVApiTest

IVTest.ConvertParams(ThisDoc.Document)

 

Attach is a sample project with 4 dlls and the project. Using "IVApiTest_e_15_2015.dll" renamed to IVApiTest.dll causes the error. It is the dll compiled with the embed option set to True in Visual Studio 2015.

 

I always use the get_Units() method for parameters on all versions because this has always been an issue. Just recently realized the embedded option causes an issue.

 

Hopefully this may help others if they have strange resolution issues when migrating projects.

0 Likes

adam.nagy
Autodesk Support
Autodesk Support
Accepted solution

Hi Rodney,

 

And also set it to False to avoid issues with events:

http://modthemachine.typepad.com/my_weblog/2012/07/set-embed-interop-types-to-false-to-avoid-problem...

 

So basically, I'm not aware of any good reason to set it to True.

 

Cheers,



Adam Nagy
Autodesk Platform Services
0 Likes

josiah_pekary
Contributor
Contributor

I have a dilemma related to this topic. I am running an Inventor Addin using Forge DA for Inventor. If I set the Autodesk.Inventor.Interop Embed Interop Types to "False" I get this error:

 

[10/30/2020 02:19:40] Could not load file or assembly 'Autodesk.Inventor.Interop, Version=25.1.0.0, Culture=neutral, PublicKeyToken=[some key]' or one of its dependencies. The system cannot find the file specified.
[10/30/2020 02:19:41] End Inventor Core Engine standard output dump.
[10/30/2020 02:19:41] Error: Application InventorCoreConsole.exe exits with code -1 which indicates an error.
[10/30/2020 02:19:41] End script phase.
[10/30/2020 02:19:41] Error: An unexpected error happened during phase CoreEngineExecution of job.
[10/30/2020 02:19:41] Job finished with result FailedExecution

 

However I want to use the parameter.get_Units() method. If I set it to "True" It runs but throws the "member not found" exception.

 

Any advice

Thanks,

0 Likes

adam.nagy
Autodesk Support
Autodesk Support

Apart from setting "Embed Interop Types"  to "False", you should also set "Copy Local" to "True" so that the specific Inventor interop dll your project is using will be available in the AppBundle:

EmbedInteropTypes.png

 



Adam Nagy
Autodesk Platform Services

alain_miltenburg
Advocate
Advocate

Hi Adam,

 

I found one reason for setting Embed Interop Types to true. The GetType() method on a SelectSet item returns a "__ComObject", so it it useless for determining the type of the Inventor object.

 

drawingDocument.SelectSet[1].GetType()

 

 

Setting Embed Interop Types to true, makes the Type property available on the SelectSet, which returns an ObjectTypeEnum.

 

drawingDocument.SelectSet[1].Type

 

 

But choosing between this and the reported issues with events, let's me think twice about actually enabling it.

Luckily I have found a workaround to get the ComObject type.

 

Regards,

Alain

0 Likes

abdullah_elq
Advocate
Advocate

@alain_miltenburg  what's the workaround you found to get the ComObject type in C#?

0 Likes

adam.nagy
Autodesk Support
Autodesk Support

If you treat the selected object as dynamic then you can still access the Type property. With Microsoft.VisualBasic assembly you can also get the TypeName 

 

adamnagy_0-1684398763705.png



Adam Nagy
Autodesk Platform Services
0 Likes

rjay75
Collaborator
Collaborator

This is the way I access the Type property for the com objects using reflection so I don't have to embed types or add more dependencies.

                Type objType = obj.GetType();
                ObjectTypeEnum ote;
                try
                {
                    ote = (ObjectTypeEnum)objType.InvokeMember("Type", BindingFlags.InvokeMethod, null, obj, null);

                }
                catch (Exception castExp)
                {

                    throw new InvalidCastException("Object is not an Inventor Type:/n" + castExp.Message);
                }

I also took this one step further and passed the ote variable to a giant switch statement to return the actual Inventor type. You can also have it only contain the types you're interested in.

        public Type GetInventorType(object obj)
        {
            Type rVal = null;
            if (obj != null)
            {
                Type objType = obj.GetType();
                ObjectTypeEnum ote;
                try
                {
                    ote = (ObjectTypeEnum)objType.InvokeMember("Type", BindingFlags.InvokeMethod, null, obj, null);

                }
                catch (Exception castExp)
                {

                    throw new InvalidCastException("Object is not an Inventor Type:/n" + castExp.Message);
                }
                switch (ote)
                {
                    case ObjectTypeEnum.kAngularGeneralDimensionObject:
                        rVal = typeof(AngularGeneralDimension);
                        break;
                    case ObjectTypeEnum.kApplicationAddInObject:
                        rVal = typeof(ApplicationAddIn);
                        break;
                    case ObjectTypeEnum.kApplicationAddInSiteObject:
                        rVal = typeof(ApplicationAddInSite);
                        break;
                    case ObjectTypeEnum.kApplicationAddInsObject:
                        rVal = typeof(ApplicationAddIns);
                        break;
                    case ObjectTypeEnum.kApplicationEventsObject:
                        rVal = typeof(ApplicationEvents);
                        break;
                    case ObjectTypeEnum.kApplicationObject:
                        rVal = typeof(Application);
                        break;
                    case ObjectTypeEnum.kDiameterGeneralDimensionObject:
                        rVal = typeof(DiameterGeneralDimension);
                        break;
                    default:
                        break;
                }
            }
                return rVal;
        }

 

 

alain_miltenburg
Advocate
Advocate

Hi Adam,

 

 

Thanks for your suggestion! In general, am not that fond of using the dynamic keyword, but I will definitely review your solution for replacement of my current solution. As mine has downsides as well.

 

As with the solution of Rodney, I am currently using reflection to get the ObjectTypeEnum:

 

        public static ObjectTypeEnum GetObjectTypeEnum(object comObject)
        {
            const string propertyName = "Type";

            if (comObject is null)
            {
                throw new ArgumentNullException(nameof(comObject), "Argument cannot be null.");
            }
          
            try
            {
                return (ObjectTypeEnum)comObject.GetType().InvokeMember(propertyName,
                    BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance,
                    null, comObject, null);
            }
            catch
            {
                throw new MissingMemberException($"Property '{propertyName}' is not found on object.");
            }
        }

 

 

0 Likes