1

We have a .Net assembly, A, that makes use of a class Foo from a COM library, B.

We've created an interop for B (Interop.b.dll) and A makes use of Foo via the interop.

If I decompile Interop.b.dll I can see the following interface defined within it:

using System.Runtime.InteropServices;

namespace Interop.b
{
  [Guid("SOME-GUID")]
  [CoClass(typeof (FooClass))]
  [ComImport]
  public interface Foo : _Foo
  {
  }
}

In the references settings of .Net assembly A, I have the option to embed the interop types for Interop.b.dll. If I set this to true the interfaces defined within Interop.b.dll are embedded within A.dll. If I then decompile A.dll I can see the same interface as I found in the interop:

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Interop.b
{
  [CompilerGenerated]
  [Guid("SOME-GUID")]
  [CoClass(typeof (object))]
  [TypeIdentifier]
  [ComImport]
  public interface Foo : _Foo
  {
  }
}

Except that it's not the same. In this version we have [TypeIdentifier] as an additional attribute and the parameter of the CoClass attribute has changed from typeof(FooClass) to typeof(object).

I note that Interop.b.dll contains the type FooClass, which I believe is a wrapper class for the COM type Foo that is responsible for marshalling parameter types between .Net and COM, but this type has not been embedded in A.dll.

Within A.dll, Foo is used like this:

using Interop.b;

namespace My.Product
{
    public class AClass: IAClass
    {
        private Foo LocalFoo { get; }

        public AClass()
        {
            LocalFoo = new Foo();
        }
    }
}

On a clean install, this fails with the following exception:

System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to interface type 'Interop.b.Foo'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{SOME-GUID}' failed due to the following error: Error loading type library/DLL. (Exception from HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY)).

(Interop.b.dll has been installed to the GAC by the product installer)

On a development machine, reinstalling the product and running from installed binaries fails in the same way. Subsequently recompiling the product, which overwrites the installed binaries, and running from either code (in debug) or the fresh binaries then works.

Now, I believe the error is that the code in A.dll should be instantiating FooClass rather than Foo. i.e. something like this:

LocalFoo = new FooClass(); 

...because Foo is an interface (in the interop) and FooClass is the thing that handles the marshalling of the parameter types between .Net and COM.

So, questions:

1) Am I correct that the code should be instantiating FooClass rather than Foo?

2) Why does it work at all on a dev machine?

3) Why is the embedded interface using typeof(object) instead of typeof(FooClass)?

4) What is the benefit of embedding the interfaces from the interop in A.dll when we will still need Interop.b.dll on the target machine to allow us to make use of FooClass?

Montgomery 'monty' Jones
  • 1,061
  • 2
  • 14
  • 27
  • Interop assembly or embedded interop assembly are just metadata definitions that explain to .NET what are the coclasses, the interfaces, the guids, and how interface methods are layout for a COM component, basically. You shouldn't need an interop .dll if you have embedded the types. Also, if your A component needs a type library, you must install it, .NET or not. To me, it seems your installer must be fixed. It works on your dev machine because your COM component is registered properly on it. – Simon Mourier Apr 16 '20 at 08:51
  • Note: this question, from 9 years ago is, effectively, asking the same question: https://stackoverflow.com/questions/3062960/why-does-accessing-a-com-object-from-net-without-going-through-the-interop-cla?rq=1 – Montgomery 'monty' Jones Apr 16 '20 at 14:51
  • Additional information here: https://stackoverflow.com/questions/1093536/how-does-the-c-sharp-compiler-detect-com-types – Montgomery 'monty' Jones Apr 16 '20 at 14:55
  • You're barking at the wrong tree. – Simon Mourier Apr 16 '20 at 15:22
  • Those links contain answers to questions 1 & 4. – Montgomery 'monty' Jones Apr 16 '20 at 15:34
  • You don't need to deploy interop.b.dll, you only need the declaration "somewhere" (in a.dll is enough). But none of these questions are related to your initial tlb question (well, 2 shoudl be replaced by "why it doesn't work on another machine?" => because deployment is broken, but that has nothing to do with interop.b.dll nor class instantiation) – Simon Mourier Apr 16 '20 at 16:16
  • Simon is right, teeth in the rear bus bumper. What you have to fret about is *needing* the type library at runtime. It is normal to have it on your dev machine, since that's how you got the declarations, but not on the user's machine. You'll get this exception when you use the library from a worker thread and the author chose to not support this usage. Best to call and ask them. – Hans Passant Apr 17 '20 at 14:51

0 Answers0