.net C++/CLI委托作为函数指针(System.AccessViolationException)
我一直在尝试使用C++/CLI委托(因为我正在尝试创建一个.NET参考库),我遇到了以下问题.net C++/CLI委托作为函数指针(System.AccessViolationException),.net,c#-4.0,interop,c++-cli,.net,C# 4.0,Interop,C++ Cli,我一直在尝试使用C++/CLI委托(因为我正在尝试创建一个.NET参考库),我遇到了以下问题 在C++中定义委托,然后在C++中创建委托实例,然后通过函数指针调用委托的实例。这一切都按预期进行 说明这一点的代码(首先是我的C#) 下一步,我的托管C++文件(托管.CPP) 这段代码按预期工作,输出为“1024”,因为指向委托方法的函数指针调用了Method() 我的问题出现在尝试对带有参数的委托应用相同的方法时,即:delegate void MessageDelegate(int number
在C++中定义委托,然后在C++中创建委托实例,然后通过函数指针调用委托的实例。这一切都按预期进行
说明这一点的代码(首先是我的C#)下一步,我的托管C++文件(托管.CPP)
这段代码按预期工作,输出为“1024”,因为指向委托方法的函数指针调用了Method() 我的问题出现在尝试对带有参数的委托应用相同的方法时,即:delegate void MessageDelegate(int number) 我的代码如下(C#):托管的C++文件:
#include "Unmanaged.hpp"
#include <string>
namespace Library
{
using namespace System;
using namespace System::Runtime::InteropServices;
public ref class Test
{
public:
delegate void MessageDelegate(int number);
internal:
MessageDelegate^ Message;
void* delegatePointer;
public:
Test(MessageDelegate^ messageDelegate)
{
delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer();
}
void WriteMessage(int number)
{
Unmanaged::WriteMessage(delegatePointer, number);
}
};
}
#include "Unmanaged.hpp"
namespace Unmanaged
{
typedef void (*WriteMessageType)(int number);
WriteMessageType WriteMessageFunc;
void WriteMessage(void* Function, int number)
{
WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
WriteMessageFunc(number);
}
}
当我执行程序时,我得到以下错误:
非托管库Test.dll中发生类型为“System.AccessViolationException”的未处理异常
其他信息:尝试读取或写入受保护内存。这通常表示其他内存已损坏
顺便说一句,console窗口确实显示1024,但随后是一个随机整数(~1000000),然后我得到了错误
我可以开始想象我犯这个错误的一些原因,但我不确定,也很难找出原因。如果有人能告诉我为什么会出现这个错误,以及我能做些什么来修复它,我将不胜感激。从委托创建的函数指针对于垃圾收集器是不可见的,并且在可达性分析期间不被计算在内 发件人: 必须手动防止垃圾收集器从托管代码中收集委托。垃圾收集器不跟踪对非托管代码的引用[sic] 如果收集委托,函数指针将悬空,程序将表现不好。访问违规是更可能的结果之一,但不是唯一的可能性。如果用于包含本机/托管蹦床的内存被用于其他数据,CPU可以尝试将其解释为指令,这可能意味着任何事情 解决方案是保持委托的可访问性,例如通过C++/CLI
gcroot
类,它是.NETGCHandle
的薄包装
void WriteMessage(void* Function, int number)
将函数指针传递为void*是一个非常糟糕的主意。它可以防止编译器检查您是否做错了任何事情。虽然编译器在这种特定情况下无法检测到错误,但还是有问题。委托被封送为使用u stdcall调用约定的函数指针,实际函数指针使用本机代码的默认u cdecl调用约定。这会导致堆栈在调用时变得不平衡
您可以通过将应用于委托声明,指定CallingConvention::Cdecl来解决此问题。+1对于描述良好的问题,我无法使用GCHandle解决此问题。即使在使用GCHandle分配委托时,似乎也会发生相同的错误,因此我认为这不是垃圾收集器的问题。我还应该补充一点,当我使用/cli编译Unmanaged.cpp时,问题就消失了。非常感谢,为什么没有参数就不需要它?它仍然是必需的,它只是没有任何区别,因为没有任何东西被推到堆栈上。
using System;
namespace AddProgram
{
class Program
{
static void Main(string[] args)
{
Library.Test.MessageDelegate messageDelegate = new Library.Test.MessageDelegate(Message);
Library.Test test = new Library.Test(messageDelegate);
test.WriteMessage(1024);
Console.Read();
}
static void Message(int number)
{
Console.WriteLine(number);
}
}
}
#include "Unmanaged.hpp"
#include <string>
namespace Library
{
using namespace System;
using namespace System::Runtime::InteropServices;
public ref class Test
{
public:
delegate void MessageDelegate(int number);
internal:
MessageDelegate^ Message;
void* delegatePointer;
public:
Test(MessageDelegate^ messageDelegate)
{
delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer();
}
void WriteMessage(int number)
{
Unmanaged::WriteMessage(delegatePointer, number);
}
};
}
#include "Unmanaged.hpp"
namespace Unmanaged
{
typedef void (*WriteMessageType)(int number);
WriteMessageType WriteMessageFunc;
void WriteMessage(void* Function, int number)
{
WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
WriteMessageFunc(number);
}
}
void WriteMessage(void* Function, int number)