c# - 使用 CLI 数组分配的内存作为非托管类的存储

标签 c# .net c++-cli mixed-mode pin-ptr

我有一个非托管类,它接受一个指向内存的指针作为它的存储空间。

例如

class MemBlock
{
    void* mpMemoryBlock;

    // Various other variables that manipulate the memory block goes here.
public:
    MemBlock( void* pMemoryBlock ) :
        mpMemoryBlock( pMemoryBlock )
    {
    }

    // A load of code that does operation on the memory block goes here.
};

现在我正在尝试包装此类以便在 C# 中使用。显然,我希望能够将类似 float[] 的内容传递给类(class)。显而易见的事情是使用包装类中的 cli::pin_ptr

public ref class MemBlockWrapper
{
    MemBlock* mpMemBlock;
public:
    MemBlockWrapper( array< float >^ fltArray )
    {
        cli::pin_ptr< float > pFltArray = &fltArray[0];

        // Brilliant we can now pass this pinned array to the C++ code.
        mpMemBlock  = new MemBlock( (void*)pFltArray );

        // Now the pin_ptr goes out of scope ...
    }
}

然而,固定的 ptr 仅在 cli::pin_ptr 在范围内时才有效。构造函数退出的那一刻,我不能再保证 C++ 类拥有的内存块是真实的。

有没有办法在类的生命周期内固定一个指针?我做了很多搜索,只找到了一种使用“GCHandle”的方法,它似乎纯粹用于托管 C++(即不是 C++/CLI)。有人能指出我确定性地固定和取消固定指针的方法吗?

最佳答案

Warning: This directly answers the question, but before you try this, first read Hans' answer and make sure you really understand what's going on and still want to do it this way.

一个固定的 GCHandle 将完成这项工作,它可以从 C++/CLI 中使用。显然,只需确保 handle 是 Pinned 类型即可。

这是一个例子:

public ref class MemBlockWrapper
{
    MemBlock* mpMemBlock;
    System::Runtime::InteropServices::GCHandle hFltArray;
public:
    MemBlockWrapper(array< float >^ fltArray)
    {
        hFltArray = System::Runtime::InteropServices::GCHandle::Alloc(
            fltArray,
            System::Runtime::InteropServices::GCHandleType::Pinned);

        mpMemBlock = new MemBlock(hFltArray.AddrOfPinnedObject().ToPointer());
    }

    ~MemBlockWrapper()
    {
        this->!MemBlockWrapper();
    }

    !MemBlockWrapper()
    {
        if (mpMemBlock)
        {
            delete mpMemBlock;
            mpMemBlock = nullptr;
            hFltArray.Free();
        }
    }
};

我添加了一个析构函数和一个终结器,这样即使您忘记处置包装器,您也可以获得 Disposable 模式以及安全清理。

关于c# - 使用 CLI 数组分配的内存作为非托管类的存储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34277565/

相关文章:

c# - .NET中进行事后分析的可能性有哪些(例如,程序崩溃后)?

.net - 使用 Deleporter 进行跨进程模拟

c# - 将引用 C++/CLI 包装器的 UserControl 添加到表单的非托管 dll 时出现问题

c# - 在 c++/cli 中创建命名空间?

c++ - 如何导出类函数,而不是 DLL 中的整个类

c# - 方括号在C#中的作用是什么

c# - 无法使用 Mono Soft Debugger 远程调试,因为 'debugger-agent: DWP handshake failed' 错误

c# - LINQ distinct 与基于 List 属性的相应计数

c# - 给定一个整数数组。找到具有最大总和的最大子数组

c# - 获取当前正在执行的Azure Function应用程序的名称