2

I have a C# application that (P/)invokes an ANSI C library, provided by the manufacturer, to access an RFID-Reader over the network. This works absolutely fine with .NET Framework versions 2.0 up to 4.5 if I manually set the platform to x86.

With the platform set to 64 Bit on the other hand, it only works with .NET Framework versions <= 3.5. The error code I get is defined as "InvalidHandle", where the handle is an int I'm given by the library identifying the reader. I don't get what an impact the Framework Version could have on a native library, especially if only so on a 64 Bit platform.

What I've observed, although I'm not sure if it is relevant at all: - In the case of failure, the handle is 10 digits long, sometimes positive, sometimes negative - In the case of success, the handle is 9 digits long, always positive

Based on this observation I've tried other data types (int, uint, long, ulong) without success (and with the same behaviour).

The "setup" of the component consists of multiple steps (method calls), which are: 1. Init (where I get the handle from) 2. SetChannel (takes a byte as a parameter) 3. SetAddress (takes a connection string containing an IP and a Port as parameter) 4. Open() Note: All those methods take the handle as an int out-parameter. Because the method SetAddress fails, when Init and SetChannel also take the handle as a parameter but don't, I suspect it might have something to do with the string, although I haven't found any evidence to support this theory.

Unfortunately the documentation is close to non-existent.

So any ideas are greatly appreciated. If you need more information, I'd be glad to provide it.

Regards,

Pascal

[DllImport("/x64/BLUEBOXLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
static extern int BLUEBOX_Init(out int Handle);

[DllImport("/x64/BLUEBOXLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
static extern int BLUEBOX_SetAddress(ref int Handle, byte Address);

[DllImport("/x64/BLUEBOXLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
static extern int BLUEBOX_SetChannel(ref int Handle, String Channel, String Settings);

Excerpt from the BLUEBOXLib.h file:

BLUEBOXLib_API BLUEBOX_ErrorCodes __stdcall BLUEBOX_Init (BLUEBOX_Handle *Handle);

BLUEBOXLib_API BLUEBOX_ErrorCodes __stdcall BLUEBOX_SetChannel (BLUEBOX_Handle *Handle, char *Channel, char *Settings);

BLUEBOXLib_API BLUEBOX_ErrorCodes __stdcall BLUEBOX_SetAddress (BLUEBOX_Handle *Handle, unsigned char Address);

typedef int BLUEBOX_Handle;
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Pascal
  • 105
  • 4
  • Perhaps the library in question isn't purely native, and ends up running some .NET code as an implementation detail. It might be worth enumerating the DLLs it uses when it is and when it isn't working, check for differences and also check whether any of them have .NET metadata. – Ben Voigt Nov 14 '14 at 14:44
  • 1
    It's *also* possible that some of your parameters should be pointer-sized, i.e. `IntPtr` in the C# signature. I should be able to confirm this for you if you show the definition of the `BLUEBOX_Handle` data type. – Ben Voigt Nov 14 '14 at 14:46
  • @BenVoigt Thank you, I've added the definition of BLUEBOX_Handle. In case of a 64 Bit architecture, there shouldn't be a difference between ulong, which I already tried, and IntPtr, am I right? – Pascal Nov 14 '14 at 15:05
  • Not only is there not a difference, but your typedef is NOT pointer-sized (it's unlike Windows API handles), so `Int32` (or `int`, but I like being explicit about sizes at binary interfaces) would be the best type. – Ben Voigt Nov 14 '14 at 18:09
  • @BenVoigt I've given your first comment a thought and after a long search I found the following statement in the documentation: BLUEBOXLib is a set of ANSI C functions which allows a user program to use and configure all the Soltec BLUEBOX readers. The library is available in the following formats:  Win32 DLL (Soltec provides the BLUEBOXLib.lib stub for Microsoft Visual C++ 6.0).  x64 DLL (Soltec provides the BLUEBOXLib.lib stub for Microsoft Visual C++ 6.0). – Pascal Nov 17 '14 at 08:22

1 Answers1

4
    typedef int BLUEBOX_Handle;

That is a problem, one you cannot fix because it doesn't appear in your code. There are multiple ways to implement a handle but they basically fall into two distinct categories. Either it a simple index into an internal array or it is a plain pointer. When you see "10 digits long, sometimes positive, sometimes negative" then it is 99% odds for a pointer.

That pointer takes 8 bytes in 64-bit mode, it cannot fit in an int. And yes, this sometimes still works, it depends on the operating system and the simplicity of the test program. On the x64 version of Vista or Win7, a 64-bit pointer can still fit in a 32-bit value by accident, allocations often happen in the lower 2 GB address range. You'll have zero odds for success on Win8, also a hint why it might seem to work on .NET 3.5. And yes, negative values won't work because they'll sign-extend when the C code casts the handle to the real pointer type, producing a garbage pointer value.

You cannot fix this bug, it has to be fixed by the vendor. They have to change the typedef to void*, now you can use IntPtr on your end. Give them a call. If they are unresponsive, then consider running this code in a separate 32-bit helper process that you interop with.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • He could also try disabling `/LARGEADDRESSAWARE` on his .NET app. – Ben Voigt Nov 17 '14 at 13:23
  • According to Microsoft, 64-bit code without LAA will use only 2GB of address space. – Ben Voigt Nov 17 '14 at 13:25
  • Thank you both very much. I will test /LARGEADDRESSAWARE as soon as possible and report my findings. Unfortunately, the reader suddenly reports "unknown error" and won't work anymore. It seems the manufacturer isn't exactly what you would call top-notch, especially if you consider this massive flaw in interface design. – Pascal Nov 19 '14 at 08:15
  • 1
    @HansPassant You were right. Support just e-mailed me a beta of the next library release, and the handle is now defined like this: typedef void * BLUEBOX_Handle;. After all the support seems to be capable, they responded within 3 days. – Pascal Nov 19 '14 at 13:27