9

I have a C library. It has many function calls like the following:

void init_foo( unsigned long x, unsigned long y );

The library itself is dynamically loaded at runtime (rather like a plugin). The headers are consistent across all platforms.

My problem is that on windows and 32bit linux, unsigned long is 32bits, yet on 64bit linux this is 64bits.

The various implementations of this library all accept this, you need to build your C program for the right target platform (as expected).

My interop method will need to be one of these depending on the architecture.

#if lin64
[DllImport("libfoo")]
public static void init_foo( Uint64 x, Uint64 y );
#else
[DllImport("libfoo")]
public static void init_foo( Uint32 x, Uint32 y );
#endif

The C# types I can use are fixed size on all platforms (as they should be). So my managed long passed from .Net/Mono will always be an unmanaged uint64_t.

How can I cope with this variable integer size yet have a single assembly that will run on .Net or mono in either 32bit or 64bit mode?

IanNorton
  • 7,145
  • 2
  • 25
  • 28
  • IanNorton:"My problem is that on windows and 32bit linux, unsigned long is 32bits, yet on 64bit linux this is 64bits." Really? I thought a long was always 64bits, since an int is 32bits... You could release a seperate version for the 64bits versions, otherwise I don't know. – MrFox Apr 08 '11 at 10:30
  • @MrFox, yes I could, I'm thinking that might do. – IanNorton Apr 08 '11 at 19:13
  • why are you using long? Why don't you use int? – David Heffernan Jul 04 '11 at 19:10

2 Answers2

4

The problem is that on 64bit Windows C long is still 32bit unlike on Linux where it's 64bit and that causes a bit of a pain.

If you don't plan to support 64bit Windows it's easy - you can map the long to IntPtr in your DllImport definition. IntPtr is 32bit on both 32bit windows and linux, which is the same as long. Long on 64bit Linux is also 64bit and so is IntPtr, however on Windows 64bit while IntPtr is 64bit long is 32bit.

If you want to support 64bit Windows you can maybe define two signatures at the same time - one for 64bit and one for 32bit like that:

[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_64bit( Uint64 x, Uint64 y );

[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_32bit( Uint32 x, Uint32 y );

Then in your code you can dynamically decide at run-time which one to call like that:

public void InvokeFoo(long x, long y)
{
    if (Environment.Is64BitProcess)
        return init_foo_64bit(x, y);
    return init_foo_32bit((int)x, (int)y);
}

P.S: If you aren't on .NET 4 another way to check if you are a 64bit process will be bool is64Bit = IntPtr.Size == 8

Ivan Zlatev
  • 13,016
  • 9
  • 41
  • 50
  • Many thanks, this looks like what I'm most likley to go with for function calls, I also have the problem with a struct that contains longs. I'll keep a lookout for more answers. – IanNorton Apr 08 '11 at 18:18
  • Define two structs and two signatures whih take either of them. In your code use the 64bit struct since it has the higher precision. In the InvokeMehod if 32bit copy the 64bit structure to the 32bit one by casting long to int. – Ivan Zlatev Apr 08 '11 at 19:03
0

Another possibility would be to write another C library with a single API that does not vary between .Net platforms and instead ship the correct wrapper library for each.

IanNorton
  • 7,145
  • 2
  • 25
  • 28