2010-01-04 107 views
2

我有一个通过委托调用的回调函数。在它里面,我需要处理从记录过程到达的缓冲区数据。通常在非托管环境中,我可以在dwParam1上执行reinterpret_cast以获取对象引用。 但在一个管理的上下文中,我怎样才能将一个DWORD_PTR转换为一个托管对象ref?将本机指针转换为C++ CLI托管对象引用?

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

回答

2

这里亚去,或多或少什么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); 
    } 
} 
+0

我决定做纯C++的音频类,但信息可以得心应手。 感谢您的帮助! – 2010-01-06 04:33:20

1

我不是C++/CLI专家,但一目了然我不认为这是可能的。如果可能的话,这将是非常不安全的。这里的基本问题是托管引用和本地指针是not the same thing,并且不支持相同的操作集。

是什么让我觉得这是不可能的是托管对象可以在内存中移动。垃圾收集操作例如compact和move memory相应地改变了对象的地址。因此,无法获得被管理对象的原始指针/地址值,因为任何给定的GC都可能使其失效。

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

我认为一个更安全的方法将是以下。

  1. 缠绕机对象
  2. 内部的管理对象传递的原生对象的整个API的
  3. 使用地址的reinterpret_cast要回本机类型,然后安全地访问您管理的手柄。
+0

你当然可以得到一个原始指针的管理对象,但它是不安全的。您在这里讨论的三步法已经由gcroot/auto_gcroot <>模板实现。实际上,你只是通过IntPtr值传递GCHandle。 – 2010-01-04 06:51:52