我正在创建一个依赖于众多C ++静态库的C ++ / CLI包装器DLL。一些函数调用期望传入非托管指针。如何正确传递它们?
此外,其他函数期望“this pointer”作为void *传入。传递“这个”的正确方法是什么?
这是我的班级定义......
public ref class RTPClient
{
public:
RTPClient();
~RTPClient();
bool Connect();
void Disconnect();
private:
CIsmaClient* mClient;
};
这是我使用指针的用法......
RTPClient::RTPClient():
mClient(NULL)
{
CIsmaClient::Create(&mClient, NULL, &AllocBuffer, &GetDataPointer, this);
}
使用& mClient和“this”会导致以下编译错误...... 1>。\ VBLoadSimulatorDll.cpp(40):错误C2664:'CIsmaClient :: Create':无法将参数1从'cli :: interior_ptr'转换为'CIsmaClient **' 1 GT;同 1 GT; [ 1 GT; Type = CIsmaClient * 1 GT; ]
1>。\ VBLoadSimulatorDll.cpp(40):错误C2664:'CIsmaClient :: Create':无法将参数5从'VBLoadSimulator :: RTPClient ^ const'转换为'VOID *'
答案 0 :(得分:9)
如果要将指针传递给托管类,则很容易将^引用转换为指针但是必须固定托管对象,以便GC不会在内存中移动它(从而使指针无效)
使用pin_ptr
这很简单然而,您的代码正在做两件无法正常工作的事情
RTPClient::RTPClient():
mClient(NULL)
{
CIsmaClient::Create(
&mClient, // 1
NULL,
&AllocBuffer,
&GetDataPointer,
this); //2
}
1)您正在尝试获取托管堆上某些内容的地址(指针的位置到指针mClient位于托管堆上。
因此它可以在内存中移动,因此编译器供应商内部指针(其值通过GC操作维护)。这需要是pinned,这只有在Create函数不希望在它的作用域结束后使用指针时才会起作用(如果它将它传递到其他地方以存储它,这将导致错误)。
2)你传递的是handle(滑稽的帽子符号),而不是指针。 (阅读关于这些的维基百科部分,他们是一个很好的概述)这不是(也不能)被非托管代码理解。
我在这个上下文中想到这个参数的唯一原因是作为传递给后续函数回调的显式状态变量(如果我错了,请纠正我)。在这种情况下,'this'永远不会正常工作,因为一旦pin_ptr超出范围,这可以在内存中移动。
考虑到这一点,这是一个(部分)纠正的实现,明确了什么可以修复和不可修复。
RTPClient::RTPClient():
mClient(NULL)
{
// make it clear you want the address of the instance variable
pin_ptr<CIsmaClient*> pinnedClient = &this->mClient;
CIsmaClient::Create(
pinnedClient, // fixed
NULL,
&AllocBuffer,
&GetDataPointer,
x /* pass something else in */); //2
}
如果您提供有关最后一个参数用途的更多信息,我可以建议可能的解决方案
答案 1 :(得分:2)
我想你会发现这是通过void指针传递托管引用的最简单方法:
void SomeFunction(void* input)
{
gcroot<ManagedClass^>* pointer = (gcroot<ManagedClass^>*)(input);
(*pointer)->ManagedFunction();
}
void Example()
{
ManagedClass^ handle = gcnew ManagedClass();
gcroot<ManagedClass^>* pointer = new gcroot<ManagedClass^>(handle);
SomeFunction((void*)pointer);
delete pointer;
}