I generated bindings for a native library but realized that imports differ between 32-bit and 64-bit.
Not only the entry point differ, but also the calling convention:
32-bit import:
[DllImport("implot", EntryPoint = "??0ImPlotPoint@@QAE@XZ", CallingConvention = CallingConvention.ThisCall)]
64-bit import:
[DllImport("implot", EntryPoint = "??0ImPlotPoint@@QEAA@XZ", CallingConvention = CallingConvention.Cdecl)]
Since these are compile-time constants, there's no way to have an if (64bit) then ... else ...
for these imports.
Using ordinals instead of decorated names as entry points:
That won't work because they don't necessarily point to the same export.
Defer stuff to two inner classes, e.g. NativeMethods32, NativeMethods64:
One would have to put bit-ness checks everywhere to dispatch to the right class, tedious as well.
Generate two inner managed assemblies, one 32-bit, one 64-bit:
Have the AnyCPU assembly dynamically load the appropriate managed assembly at runtime.
Is there an effective, proven pattern to tackle such problem?
I solved the problem rewriting the entire stuff with Roslyn to produce an AnyCPU module.
Like so:
public class Whatever
{
internal partial struct __Internal
{
// keep fields
// remove methods
}
internal partial struct __Internal32
{
// remove fields
// insert 32-bit methods
}
internal partial struct __Internal64
{
// remove fields
// insert 64-bit methods
}
public static void Test()
{
if (IntPtr.Size == 4)
{
__Internal32.Test();
}
else
{
__Internal64.Test();
}
}
}
The result works very well, the platform target can be switched as usual and it just works.