我有一个C++ DLL与以下方法:
//C++ dll method (external)
GetServerInterface(ServerInterface* ppIF /*[OUT]*/)
{
//The method will set ppIF
}
//ServerInterface is defined as:
typedef void * ServerInterface;
Run Code Online (Sandbox Code Playgroud)
为了从C#项目访问dll,我创建了一个C++/CLI项目并声明了一个托管类,如下所示:
public ref class ComWrapperManager
{
//
//
ServerInterface _serverInterface;
void Connect();
//
//
}
Run Code Online (Sandbox Code Playgroud)
我使用Connect()方法调用GetServerInterface,如下所示.第一次通话有效,第二次通话无效.有人可以解释原因吗?我需要将该指针持久化为托管类中的成员变量.有更好的方法吗?
void Connect()
{
ServerInterface localServerInterface;
GetServerInterface(&localServerInterface); //THIS WORKS
GetServerInterface(&_serverInterface); //THIS DOESNT
//Error 1 error C2664: 'ServerInterface ' :
//cannot convert parameter 1 from //'cli::interior_ptr<Type>'
//to 'ServerInterface *'
}
Run Code Online (Sandbox Code Playgroud)
您正在将指针传递给托管对象的成员.这样的指针是特殊的,称为内部指针.它们由垃圾收集器跟踪,它将在GC压缩堆时移动托管对象时修改指针值.
问题是,您将该指针传递给非托管代码.GC无法修改本机代码正在使用的指针值的副本.现在,当另一个线程触发垃圾收集时,灾难就会发生,就像本机代码正在执行并取消引用指针一样.该对象不再存在于原始地址.非常非常糟糕.并且极难诊断,因为它不太可能发生.
编译器可以看到你犯了这个错误.并抱怨C2664.
解决方法是传递一个指针,该指针存储在一个不会被GC移动的内存位置.这样的位置很容易得到,本地变量有资格.它存储在堆栈中,不会被移动.所以让它看起来像这样:
void Connect()
{
ServerInterface temp;
GetServerInterface(&temp);
this->_serverInterface = temp;
// etc..
}
Run Code Online (Sandbox Code Playgroud)
您已经发现自己,只是不要忘记分配班级成员.