Shallow understanding of COM interop leads to TYPE_E_CANTLOADLIBRARY exception - where's the mistake?

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?

c#
.net
com
com-interop

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0