IndexOutOfRangeException - 无法使用PInvoke查看调用堆栈

时间:2015-03-10 13:27:17

标签: c# c++ c pinvoke indexoutofrangeexception

我正在开发一个从SerialPort获取数据的C#应用​​程序,然后它使用C ++项目(我无法更改)来计算读取数据。

C ++项目正在使用一些本机C代码,它将在计算数据时调用C#函数。

这是被调用的C#代码的一些示例,它使用PInvoke调用C ++函数:

    [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);

然后,C ++代码:

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

这个C函数正在调用我设置的C#函数:

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

最后,C代码将调用“addSampleToBattery”函数,这就是这个C#回调(前两个是PInvoke调用,就像我发布的第一个一样)

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;
    }

其他细节:

C#代理声明如下:

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

 private static readonly DelegateBattery DelegateCallbackBattery = CallbackBattery;

并设置如下:

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

因此,一切似乎都有效,但很多时候会发生IndexOutOfRangeException。主要问题是,即使在加载了所有符号的调试模式下,我也看不到引发异常的行,因为只有反汇编视图可用,当然我无法从中获取有意义的信息。

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()

谢谢!

1 个答案:

答案 0 :(得分:0)

IndexOutOfRangeException 对应的语义表明您试图访问距离基本内存地址太远的内存,因此您不应该尝试遵循这一点。存储器中。

想想一个包含3个元素的int数组。如果您尝试索引[3],即*(base_address +(sizeof(int)* 3))*被解除引用,以便在内存中该位置的后4个字节作为int提供。唯一有效的索引是0,1和2,因为这些偏移在我们为其分配空间的3个元素的范围内。

我们仍然需要更多代码,因为我不知道其中任何一个与异常消息相关。