如何将对 void* 的引用从 C++/CLI 传递到本机 C 函数

How to pass a reference to a void* from C++/CLI to a native C function

我正在尝试从托管 C++/CLI 调用本机 Windows API。其中一个参数是 void**。这个想法是该函数将分配一个内存结构和 return 一个指向调用者的空指针,该指针应在下一次调用时传回给 API。所以我需要在托管端为指针分配存储空间,并传递对 C API 的引用。我不知道该怎么做。

我试过在调用者中声明一个 void * 并通过各种运算符传递引用:&、internal_ptr<>、pin_ptr<>。我对 IntPtr 做了同样的事情。我收到错误消息,提示编译器无法将其转换为 void**。

这是使用 IntPtr 和 pin_ptr 的一次尝试。我在第 28 行(声明 pin_ptr 的行)收到以下编译错误:

E0144 类型“interior_ptr<System::IntPtr>”的值不能用于初始化类型“cli::pin_ptr<void *>”的实体

#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System;

namespace CLRStorage
{
    public ref class CompoundFile
    {
    private:
        String ^ pathname;
        IntPtr pRootStorage;
    public:
        CompoundFile CompoundFile::Create(String^ path)
        {
            STGOPTIONS stgOptions;
            stgOptions.usVersion = 1;
            stgOptions.reserved = 0;
            stgOptions.ulSectorSize = 4096;
            stgOptions.pwcsTemplateFile = NULL;

            auto cf = gcnew CompoundFile();
            cf->pathname = path;
            marshal_context^ context = gcnew marshal_context();
            pin_ptr<void*> ppRootStorage = &cf->pRootStorage;
            StgCreateStorageEx(
                context->marshal_as<WCHAR*>(path),
                STGM_READWRITE & STGM_CREATE,
                STGFMT_DOCFILE,
                0,
                &stgOptions,
                NULL,
                IID_IStorage,
                ppRootStorage);
        }
    };
}

IntPtr 可以与 void* 相互转换,但不是同一类型。

由于参数是out-only,简单的解决方法就是临时使用:

void* pRootStorage;
StgCreateStorageEx(
            context->marshal_as<WCHAR*>(path),
            STGM_READWRITE & STGM_CREATE,
            STGFMT_DOCFILE,
            0,
            &stgOptions,
            NULL,
            IID_IStorage,
            &pRootStorage);
cf->pRootStorage = IntPtr(pRootStorage);

这实际上也会快一点,因为不需要固定。

您还有一个单独的问题,即错误的成员函数语法。你要

static CompoundFile^ Create(String^ path)

而不是

CompoundFile CompoundFile::Create(String^ path)

别忘了

return cf;

那么,marshal_context不是ref class,所以这一行是错误的:

marshal_context^ context = gcnew marshal_context();

改为使用

marshal_context context;

并且由于它不是指针,

context.marshal_as<WCHAR*>(path)