从C++回调到C#函数的访问冲突异常/崩溃

Tom*_*omO 6 c# c++ c++-cli callback access-violation

所以我有一个我正在使用的本地第三方C++代码库(.lib和.hpp文件),我曾经在C++/CLI中构建一个包装器,以便最终在C#中使用.

从调试模式切换到发布模式时,我遇到了一个特殊问题,因为当回调代码返回时,我遇到了一个访问冲突异常.

来自原始hpp文件的代码用于回调函数格式:

typedef int (*CallbackFunction) (void *inst, const void *data);
Run Code Online (Sandbox Code Playgroud)

来自C++/CLI Wrapper的代码用于回调函数格式:(我将解释为什么我暂时宣布两个)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
Run Code Online (Sandbox Code Playgroud)

- 很快,我宣布第二个"UnManagedCallbackFunction"的原因是我试图在包装器中创建一个"中间"回调,因此链从Native C++> C#更改为Native C++> C++/CLI Wrapper> C#的版本...完全公开,问题仍然存在,它刚刚被推送到C++/CLI Wrapper现在在同一行(返回).

最后,来自C#的崩溃代码:

public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
    {
        Console.WriteLine("in hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);

        // provide object context for static member function
        helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
        if (hw == null || pData == null)
        {
            Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
            return 0;
        }

        // typecast data to DataLogger object ptr
        IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
        DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

        //Do Logging Stuff

        Console.WriteLine("exiting hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("Setting pData to zero...");
        pData = IntPtr.Zero;
        pInstance = IntPtr.Zero;
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("pInstance: {0}", pInstance);

        return 1;
    }
Run Code Online (Sandbox Code Playgroud)

对控制台的所有写入都已完成,然后我们在返回时看到可怕的崩溃:

helloworld.exe中0x04d1004c处的未处理异常:0xC0000005:访问冲突读取位置0x04d1004c.

如果我从这里进入调试器,我看到的是调用堆栈上的最后一个条目是:>"04d1004c()",它的计算结果为十进制值:80805964

如果你看一下控制台显示:

entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0
Run Code Online (Sandbox Code Playgroud)

现在,我知道在调试和发布之间,微软世界中有些东西是完全不同的.我当然担心字节填充和变量的初始化,所以如果我在这里没有提供的东西,请告诉我,我将添加(已经很长)的帖子.我还认为托管代码可能不会释放所有所有权,然后原生C++内容(我没有代码)可能会尝试删除或终止pData对象,从而导致应用程序崩溃.

更全面的披露,它在调试模式下运行良好(貌似)!

一个真正的头部划痕问题,将不胜感激任何帮助!

jde*_*aan 4

我认为堆栈由于调用约定不匹配而被压垮:尝试放置属性

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Run Code Online (Sandbox Code Playgroud)

在回调委托声明上。