2

I'm developing a C# app that takes data from a SerialPort, then it uses a C++ project (that I cannot change) to compute the read data.

The C++ project is using some native C code, that will call C# functions when the data are computed.

This is some examples of the called C# code which calls the C++ function using PInvoke:

    [DllImport("MyLib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern void PacketHandler_HandlePacket(IntPtr packetHandler, IntPtr packet, int packetType);

    [SuppressUnmanagedCodeSecurity]
    [DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern float DeviceManager_AddSampleToBattery(IntPtr self, float sample, double sampleRate);

    [SuppressUnmanagedCodeSecurity]
    [DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern double DeviceManager_GetTimestamp(IntPtr self, int packetType);

    [DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern void PacketHandler_AddCallbackBattery(IntPtr self, Delegate @delegate);

Then, the C++ code:

extern "C"
{
    __declspec(dllexport) void _cdecl PacketHandler_HandlePacket(int * packetHandler, char * packet, int packetType){
        PacketHandler_handlePacket((PacketHandlerStruct *)packetHandler, packet, (PacketHandlerPacketType)packetType);}
}

This C function is calling a C# function that I've set like this:

__declspec(dllexport) void _cdecl  PacketHandler_AddCallbackBattery(int * packetHandler, void(*f)(void * obj, unsigned short int sample)){
    PacketHandlerStruct * myPointer = ((PacketHandlerStruct *)packetHandler);
    myPointer->delegate.addSampleToBattery = f;
}

Finally, the C code will call the "addSampleToBattery" function which is this C# callback (in where the first two are PInvoke calls like the first one I've posted)

private static float CallbackBattery(IntPtr self, ushort sample)
    {
        var value = DeviceManager_AddSampleToBattery(DeviceManager, sample, Const.BaseBvpSampleRate);
        var timestamp = DeviceManager_GetTimestamp(DeviceManager, (int)PacketHandlerPacketType.Battery);
        SocketManager.OnNewBatteryArrived(value, timestamp);
        return value;
    }

Other details:

The C# delegates are declared as follows:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 private delegate float DelegateBattery(IntPtr self, short sample);

 private static readonly DelegateBattery DelegateCallbackBattery = CallbackBattery;

And setted like this:

var intptrDelegate = Marshal.GetFunctionPointerForDelegate(DelegateCallbackBattery);
var a = Marshal.GetDelegateForFunctionPointer(intptrDelegate, typeof(DelegateBattery));
PacketHandler_AddCallbackBattery(packetHandler, a);

So, everything seems to works, but a lot of times a IndexOutOfRangeException occurs. The main issue is that, even in Debug Mode with all the symbols loaded, I can't see the line that is throwing the exception because only the Disassembly View is available, and of course I can't get meaningful info from it.

Unhandled Exception: 'MyProgram.exe' (Win32): 
The program '[3000] MyProgram.exe' has exited with code 0 (0x0).
 System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Threading.ThreadPoolWorkQueue.Dequeue(ThreadPoolWorkQueueThreadLocals tl, IThreadPoolWorkItem& callback, Boolean& missedSteal)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

Thanks!

Alessio
  • 2,018
  • 25
  • 26
  • Calling @HansPassant – Jonathon Reinhart Mar 10 '15 at 13:49
  • There's nowhere near enough information here. – David Heffernan Mar 10 '15 at 14:14
  • Unfortunately I don't know which info to provider for let other users better understand the problem. The same C code is running in another app so the problem is not there, it seems to throw the Exception randomly so not after a given period of time of in the same function. How can I help you to better understand the issue? Thanks – Alessio Mar 10 '15 at 14:15
  • You've provided very little code. Apparently there's a callback. We cannot see it. What you could do is make an MCVE. If you can't do that then you could show all the relevant code from both a functioning C or C++ consumer of the interface, and your matching C# code. – David Heffernan Mar 10 '15 at 15:17
  • I've included more code, hope that it's better now – Alessio Mar 10 '15 at 15:38
  • Actually, do you have any idea why there's an exception I can't see the line of code that caused it but only the disassembly which is useless? – Alessio Mar 11 '15 at 11:44
  • Probably I've found the issue: all the delegates (like DelegateBattery) has a return type which is not used, and the corresponding delegate in C code has no return type (void). – Alessio Mar 12 '15 at 13:58

1 Answers1

0

Semantics in correspondence with an IndexOutOfRangeException indicate that you've attempted to access memory too far from a base memory address, and thus you shouldn't be trying to deference that point in memory.

Think of an int array of 3 elements. If you try to index [3], that is *(base_address + (sizeof(int) * 3))* being dereferenced so that the next 4 bytes at that place in memory are provided for the value as an int. The only valid indexes are 0, 1, and 2, because those offsets are within the range of the 3 elements that we've allocated the space for.

We still need more code, as I don't see where any of this is relevant to the exception message.

bitm0de
  • 45
  • 1
  • 7