2

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

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

2 回答 2

4

来吧,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);
    }
}
于 2010-01-04T07:04:02.827 回答
1

我不是 C++/CLI 专家,但乍一看我认为这是不可能的。如果有可能,那将是非常不安全的。这里的基本问题是托管引用和本机指针不是一回事,不支持同一组操作。

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

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

我认为下面是一种更安全的方法。

  1. 将托管对象包装在本机对象中
  2. 在整个 API 中传递本机对象的地址
  3. 使用 reinterpret_cast 回到本机类型,然后安全地访问您的托管句柄​​。
于 2010-01-04T05:58:35.267 回答