5

我正在创建一个依赖于众多 C++ 静态库的 C++/CLI 包装 DLL。一些函数调用期望传入非托管指针。如何正确传递它们?

此外,其他函数期望“this 指针”作为 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> with 1> [ 1> Type=CIsmaClient * 1> ]

1>.\VBLoadSimulatorDll.cpp(40):错误 C2664:“CIsmaClient::Create”:无法将参数 5 从“VBLoadSimulator::RTPClient ^const”转换为“VOID *”

4

2 回答 2

9

如果您将指针传递给托管类,那么很容易将 ^ 引用转换为指针,但您必须固定托管对象,以便 GC 不会在内存中移动它(从而使指针无效)

这很简单pin_ptr

但是,您的代码正在做两件不起作用的事情

RTPClient::RTPClient():
        mClient(NULL)
{
    CIsmaClient::Create(
        &mClient,          // 1
        NULL, 
        &AllocBuffer, 
        &GetDataPointer, 
        this);            //2
}

1)您试图获取托管堆上某些东西的地址(指向指针 mClient 的指针的位置在托管堆上。

因此它可以在内存中移动,因此编译器供应商内部指针(其值通过 GC 操作维护)。这需要固定,并且仅当 Create 函数不希望在其范围结束后使用指针时才有效(如果它将它传递到其他任何地方来存储它,这将导致错误)。

2)您传递的是句柄(有趣的帽子符号)而不是指针。(阅读关于这些的维基百科部分,它们是一个很好的概述)非托管代​​码不能(也不能)理解这一点。

在这种情况下,我能想到这个参数的唯一原因是作为传递给后续函数回调的显式状态变量(如果我错了,请纠正我)。在这种情况下,'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
}

如果您提供有关最后一个参数的用途的更多信息,我可以建议可能的解决方案

于 2009-02-20T14:34:41.110 回答
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;
}
于 2010-11-12T09:50:55.813 回答