Unamanged types in managed interface generates TypeLoadException

M

mats

Hi!

This is a quite involved question concerning two dll's that are consumed from a console application.

The first dll is called base.dll and is compiled in mixed mode (managed and unmanaged C++). One native class and one managed interface is declared and defined in base dll. The native class is exported via declspec(dllexport) and the managed interface via the public keyword. The managed interface has one property which returns a pointer to the unmanaged class. It looks like this:

// base.dll
// DLL_ITEM is defined as dllexport when base.dll is compiled
// and dllimport when some other dll imports it.

__nogc class DLL_ITEM Native
{
};

public __gc __interface NativeWrapper
{
__property Native* get_Native();
};

Now, base.dll is compiled and another dll, consumer1.dll, imports it.

In consumer1.dll two new classes are declared, one that implements the NativeWrapper interface and one that inherits from the Native class. To inherit from the native class, one must include its header file where it is declared. This is what is found in the consumer1.dll:

__nogc class Native2 : public Native
{
};

__gc class NativeWrapper2 : public NativeWrapper
{
__property Native* get_Native()
{
return new Native2();
}
}

Finally these two dll's are consumed in console.exe. Both base.dll and consumer1.dll are imported and console.exe compiles alright. But when consumer1.dll is loaded I get the following runtime error:

--

An unhandled exception of type 'System.TypeLoadException'
occurred in Unknown Module.

Additional information: Method get_Native in type
consumer1.Class1 from assembly consumer1, Version=1.0.1586.21893, Culture=neutral, PublicKeyToken=null does not have an implementation.

--

The reson for this seems to be the Native* return type which seems to be somewhat different between base.dll and consumer1.dll. If one changes Native* to void* everything works fine, no exception is thrown. So the question is, how can I use the Native class in both base.dll and consumer1.dll without getting the exception shown above?

I'm using VS .NET 2003.

/Mats

**********************************************************************
Sent via Fuzzy Software @ http://www.fuzzysoftware.com/
Comprehensive, categorised, searchable collection of links to ASP & ASP.NET resources...
 
M

mats

Ok, here is an answer to my own question.

First of all, the error message is wrong and should read: "... Method get_Native in type NativeWrapper2 from consumer1 ... "

Having corrected that now over to the reason for this error. The compiler will generate metadata for the class Native in base.dll to describe the type. The same goes for the assembly consumer1. The metadata will be the same but a type is not solely based on its name but also on its physical location. That means that there will be two different Native classes, Native[1] in base.dll and Native[2] in consumer1.dll. This is no problem for the VC compiler which actually thinks that you are implementing the interface NativeWrapper when you write your NativeWrapper2 class. But when the loader tries to find the overloads for the functions in NativeWrapper it doesn't find any get_Native that returns a type Native[1] but rather a type Native[2]. That's why I get the exception telling me I didn't implement get_Native.

The solution then? Well, i did like this:

public __gc __interface NativeWrapper
{
__property void* get_Native();
};

void* is the same in all assemblies so this will be easy to implement. The drawback is that the typesystem is disabled. I put together a bunch of helperfunctions to access the Native object so the risk of doing something unwanted is minimised. If someone finds out a typesafe way to do it, please let me know!


**********************************************************************
Sent via Fuzzy Software @ http://www.fuzzysoftware.com/
Comprehensive, categorised, searchable collection of links to ASP & ASP.NET resources...
 
C

cdrundles

I received the same error in very similar circumstances.
The failure happened when calling a delegate whose interface is
abstract and whose implementation overrides the interface method.

First thing to verify is that the override keyword is in the
implementation.
Second thing to verify is that the implementation has the same
signature
as the interface (delegate). This can be verified by running:

C:\Program Files\Microsoft Visual Studio .NET
2003\SDK\v1.1\Bin\ildasm.exe (a GUI app)

and opening the DLL containing the implementation and then the one
containing the interface.

The next thing to do is to see if the implementing assembly fails to
load:
http://msdn.microsoft.com/library/d...ools/html/cpgrfFusionLogViewerFuslogvwexe.asp
give instructions concerning the Fusion Log Viewer.
Bear in mind that this article should have said to add the DWORD
registry variables it refers to as they are not present by default.

In my case, the assembly loaded with no errors. This turned out to be
misleading, for the type load failure was caused by the inability to
load
an assembly on which the current delegate depended.

In particular, the delegate was implemented in one C++ DLL but
returned an object pointer defined in another C++ DLL. It was the
latter DLL that failed to load and yet fuslogvw showed no errors.

My error was resolved by copying the DLL, on which the delegate
implementation depended, to the current directory. I didn't try
having the DLL in LIBPATH, but that may have been sufficient. If you
see success on one system and failure on another, LIBPATH may be an
issue. Since LIBPATH differs for users and system, a load may
succeed for a user but fail for a service. Either way, having the
DLLs in the current directory works.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top