Winapi 将本机指针强制转换为C++\CLI托管对象引用?

Winapi 将本机指针强制转换为C++\CLI托管对象引用?,winapi,pointers,c++-cli,managed-c++,Winapi,Pointers,C++ Cli,Managed C++,我有一个通过委托调用的回调。在它里面,我需要处理从记录过程到达的缓冲区数据。通常在非托管上下文中,我可以对dwParam1执行重新解释_转换以获取对象引用。 但在管理上下文中,如何将DWORD_PTR强制转换为托管对象ref static void WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { ControlLi

我有一个通过委托调用的回调。在它里面,我需要处理从记录过程到达的缓冲区数据。通常在非托管上下文中,我可以对dwParam1执行重新解释_转换以获取对象引用。 但在管理上下文中,如何将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);

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

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

严格来说,这不是真的,因为可以在内存中固定对象。但即使这样,我认为没有一种方法可以让C++把任意地址当作一个托管句柄来处理。p> 我认为一个更安全的方法是如下

  • 将托管对象包装在本机对象内
  • 在整个API中传递本机对象的地址
  • 使用reinterpret_cast返回本机类型,然后安全地访问托管句柄
    下面是gcroot(根据我上面的评论)的大致功能:

    使用名称空间系统;
    使用名称空间System::Runtime::InteropServices;
    //通过DWORD_PTR中编码的普通(非固定)控制柄跟踪对象
    DWORD_PTR ParamFromObject(对象^obj)
    {
    返回reinterpret_cast(GCHandle::ToIntPtr(GCHandle::Alloc(obj)).ToPointer();
    }
    静态无效波输入程序(PVOID hwi、UINT uMsg、DWORD_PTR DWARAMENT、DWORD_PTR DWARAM1、DWORD_PTR DWARAM2)
    {
    //打开编码句柄。。。
    GCHandle h=GCHandle::fromtptr(IntPtr(reinterpret_cast(dwParam1));
    尝试
    {
    //把你的东西扔出去
    SoundDevice ^x=安全施法(h.目标);
    }
    最后
    {
    //完成后请记住释放句柄,否则将永远无法收集对象
    GCHandle::Free(h);
    }
    }
    
    您当然可以获得指向托管对象的原始指针,但它是不安全的。这里讨论的三步方法已经由gcroot/autogcroot模板实现。实际上,你只是通过IntPtRualPaysApple传递GCHandle。我决定用纯C++制作音频类,但是信息很方便。谢谢你的帮助!
    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);
        }
    }