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

Posted

技术标签:

【中文标题】如何将 void* 的引用从 C++/CLI 传递给本机 C 函数【英文标题】:How to pass a reference to a void* from C++/CLI to a native C function 【发布时间】:2019-04-03 00:07:31 【问题描述】:

我正在尝试从托管 C++/CLI 调用本机 Windows API。其中一个论点是无效**。这个想法是该函数将分配一个内存结构并向调用者返回一个 void 指针,该指针应在下一次调用时传递回 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);
        
    ;

【问题讨论】:

【参考方案1】:

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)

【讨论】:

哇!感谢这一切。非常感谢您的帮助。

以上是关于如何将 void* 的引用从 C++/CLI 传递给本机 C 函数的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#

如何使用 C++/CLI Wrapper 将变量参数从托管传递到非托管?

将 C++/CLI 类方法作为 C 函数指针传递

将c ++引用的地址传递给指针

如何通过引用从 c# 到 c++ 传递字节数组

将字符串从 C++/CLI 类库传递到 C#