如何将对 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)
我正在尝试从托管 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)