从 C++ 回调到 C# 函数的访问冲突异常/崩溃 [英] Access Violation Exception/Crash from C++ callback to C# function

查看:79
本文介绍了从 C++ 回调到 C# 函数的访问冲突异常/崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So I have a native 3rd party C++ code base I am working with (.lib and .hpp files) that I used to build a wrapper in C++/CLI for eventual use in C#.

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

I've run into a particular problem when switching from Debug to Release mode, in that I get an Access Violation Exception when a callback's code returns.

原始hpp文件中回调函数格式的代码:

The code from the original hpp files for callback function format:

typedef int (*CallbackFunction) (void *inst, const void *data);

来自 C++/CLI 包装器的用于回调函数格式的代码:(我稍后会解释为什么我声明了两个)

Code from the C++/CLI Wrapper for callback function format: (I'll explain why I declared two in a moment)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

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

--Quickly, the reason I declared a second "UnManagedCallbackFunction" is that I tried to create an "intermediary" callback in the wrapper, so the chain changed from Native C++ > C# to a version of Native C++ > C++/CLI Wrapper > C#...Full disclosure, the problem still lives, it's just been pushed to the C++/CLI Wrapper now on the same line (the return).

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

And finally, the crashing code from 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
");
            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;
    }

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

All writes to the console are done and then we see the dreaded crash on the return:

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

Unhandled exception at 0x04d1004c in helloworld.exe: 0xC0000005: Access violation reading location 0x04d1004c.

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

If I step into the debugger from here, all I see is that the last entry on the call stack is: > "04d1004c()" which evaluates to a decimal value of: 80805964

只有当您查看显示以下内容的控制台时才有趣:

Which is only interesting if you look at the console which shows:

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

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

Now, I know that between debug and release some things are quite different in the Microsoft world. I am, of course worried about byte padding and initialization of variables, so if there is something I am not providing here, just let me know and I'll add to the (already long) post. I also think the managed code may NOT be releasing all ownership and then the native C++ stuff (which I don't have the code for) may be trying to delete or kill off the pData object, thus crashing the app.

更全面的披露,在调试模式下一切正常(看起来)!

More full disclosure, it all works fine (seemingly) in Debug mode!

一个真正的头部划伤问题,希望得到任何帮助!

A real head scratch issue that would appreciate any help!

推荐答案

我认为堆栈由于调用约定不匹配而崩溃:尝试放属性

I think the stack got crushed because of mismatching calling conventions: try out to put the attribute

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

关于回调委托声明.

这篇关于从 C++ 回调到 C# 函数的访问冲突异常/崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆