Here's my problem: within a PCL library I'm going to call unmanaged code from a C++ DLL. That DLL comes in two versions (x86 and x64) and for performance reasons, the correct library should be referenced depending on the platform where the PCL library is embedded.
Since the [DllImport]
attribute requires a constant string as the library name, this very convinient way renders useless, as the correct library is to be determined at runtime. There are some “hubby” ways to load the functions manually (LoadLibrary
, GetProcaddress
and GetDelegateForFunctionPointer
) but I’m going to make it more convenient for the programmer.
So, declaring an external function is not the problem. Well, the C# compiler detects the external and worried about the fact, that with the missing [DllImport]
attribute, the external might not be resolved when the type is loaded. Okay, I defined an attribute [MyImport]
and placed it at the external declaration and bingo, at least the compiler was happy.
At runtime, I of course get a TypeLoadException becauce my external is indeed unresolved. That raises two questions:
1) Why is the compiler happy with any attribute? Is there any magic from the loader with regard to using that attribute in order to resolve the pending external? This could straightforwardly done by providing an interface to be implemented by the attribute. This way the runtime would lookup the attributes of the external searching for those that implement the “magic” interface.
2) How can I catch the TypeLoadException in a way where I can implement my own loader? That loader would iterate all externals from the given type, read the [MyImport] attribute and resolve the external this way.
Any idea out there if one of the two ideas can possibly be implemented or is there any other solution to the mentioned problem?
I appreciate English lessons though, but that actually isn’t what I’m asking for:-))
Christian.
Actually I went with the solution mentioned by Hans, further down in the comment section.
As he mentioned, the whole issue is rather a deployment problem and less something to be addressed with workaround development. So, I gave the two platform versions the same name and let them reside in different directories - like this:
SystemTera.MyPCL.dll
x86\SystemTera.Platform.dll
x64\SystemTera.Platform.dll
Upon startup, I point the loader to the correct platform version:
public static class Platform
{
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetDllDirectory(string pathName) ;
public static void Setup()
{
if (Environment.Is64BitProcess)
SetDllDirectory("./x64/") ;
else // default Win32
SetDllDirectory("./x86/") ;
}
}
When I further refer to the platform libraries, the loader/jitter does the correct job:
public class MyClass
{
[DllImport("SystemTera.Platform.dll")]
static extern void MyPlatformFunction() ;
public void DoTheJob()
{
MyPlatformFunction() ;
}
}
That's a fine solution using existing concepts provided by the Framework.