转换为C ++ \ CLI托管对象引用的本机指针?

时间:2010-01-04 04:56:22

标签: winapi pointers c++-cli managed-c++

我有一个通过委托调用的回调。在其中我将需要处理从记录过程到达的缓冲区数据。通常在非托管上下文中,我可以在dwParam1上执行reinterpret_cast来获取对象引用。 但是在manged上下文中,如何将DWORD_PTR转换为托管对象ref?

    static void WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 
    {
        ControlLib::SoundDevice^ soudDevice = ?cast_native2managed?(dwParam1);

2 个答案:

答案 0 :(得分:3)

在这里,或多或少gcroot(根据我上面的评论):

using namespace System;
using namespace System::Runtime::InteropServices;

// track an object by a normal (not pinned) handle, encoded in a DWORD_PTR
DWORD_PTR ParamFromObject(Object^ obj)
{
    return reinterpret_cast<DWORD_PTR>(GCHandle::ToIntPtr(GCHandle::Alloc(obj)).ToPointer());
}

static void WaveInProc(PVOID hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 
{
    // unwrap the encoded handle...
    GCHandle h = GCHandle::FromIntPtr(IntPtr(reinterpret_cast<void*>(dwParam1)));
    try
    {
        // and cast your object back out
        SoundDevice^ x = safe_cast<SoundDevice^>(h.Target);
    }
    finally
    {
        // remember to free the handle when you're done, otherwise your object will never be collected
        GCHandle::Free(h);
    }
}

答案 1 :(得分:1)

我不是C ++ / CLI专家,但我一眼就认为这不可行。如果有可能,那将是非常不安全的。这里的基本问题是托管引用和本机指针是not the same thing,并且不支持同一组操作。

让我觉得这是不可能的是托管对象可以在内存中移动。例如,垃圾收集操作紧凑并移动内存,相应地改变对象的地址。因此,不可能拥有托管对象的原始指针/地址值,因为任何给定的GC都可能使其无效。

这不是严格意义上的,因为您可以将对象固定在内存中。但即便如此,我也不认为有办法让C ++将任意地址视为托管句柄。

我认为更安全的方法如下。

  1. 将托管对象包装在本机对象中
  2. 在整个API中传递本机对象的地址
  3. 使用reinterpret_cast返回本机类型,然后安全地访问托管句柄。