如何使用 c++/cli 将 InteropServices.ComTypes.IStream 传递给接受 IStream* 的本机方法
How to pass InteropServices.ComTypes.IStream to native method accepting IStream* using c++/cli
我有一个带有托管包装器的本机 dll,全部编写并使用 COM 互操作。我现在的工作是使用 c++/cli 重写包装器(和部分 dll)。
本机 dll 中的一种方法接受指针 IStream* output 作为其参数之一,这就是我被卡住的地方。每当我尝试使用指针 output 时,我都会得到一个 AccessViolationException.
这是我的代码的示例:
common.h
class INativeClass
{
public:
virtual int NativeMethod(IStream* output) = 0;
};
c++ 原生
#include "common.h"
public NativeClass : public INativeClass
{
public int NativeMethod(IStream* output)
{
outputStream->Write(...); //AccessViolationException happens here
}
}
c++ 托管
#include "common.h"
public ref class ManagedClass
{
private:
INativeClass* nativeObject;
public:
ManagedClass()
{
nativeObject = CreateNewNativeObject();
}
int ManagedMethod(IStream^ output)
{
NativeClass nativeObject = new
GCHandle streamHandle = GCHandle::Alloc(output);
IntPtr ipo = GCHandle::ToIntPtr(streamHandle);
nativeObject->NativeMethod(static_cast<IStream*>(ipo.ToPointer()));
}
}
c#
void main()
{
ManagedClass managedObject = new ManagedClass();
IStreamImplementation stream = new IStreamImplementation(filepath);
managedObject.ManagedMethod(stream);
}
我已经在互联网上搜索了几天,似乎找不到我做错了什么。我想我已经正确地转换为 IStream*,而且我不必担心 GC。我也试过使用 pin_ptr,但没有用。
如果这是重复的,我深表歉意,但正如我所说,几天来我一直在寻找解决方案。
编辑
用最小化的可编译代码更新了代码以重现问题(可能缺少一些包含)。
另外,当我说 IStream 时,我的意思是 InteropServices.ComTypes.IStream 或者它是 C++ 的对应物。我没有使用 std::istream
我按照 Hans Passant 所说的方法解决了这个问题:
在 ManagedClass 中,我有:
int ManagedMethod (IStream^ output)
{
IntPtr outputPtr = Marshal::GetIUnknownForObject(output);
IUnknown* outputNativePtr = static_cast<IUnknown*>(outputPtr.ToPointer());
nativeObject->NativeMethod(outputNativePtr);
}
在 NativeClass 中我有:
int NativeMethod(IUnknown* output)
{
IStream outputStream;
HRESULT hr = output->QueryInterface(IID_IStream, (void**)&outputStream);
if (FAILED(hr) || outputStream == nullptr)
{
//error
}
//do something
}
我有一个带有托管包装器的本机 dll,全部编写并使用 COM 互操作。我现在的工作是使用 c++/cli 重写包装器(和部分 dll)。
本机 dll 中的一种方法接受指针 IStream* output 作为其参数之一,这就是我被卡住的地方。每当我尝试使用指针 output 时,我都会得到一个 AccessViolationException.
这是我的代码的示例:
common.h
class INativeClass
{
public:
virtual int NativeMethod(IStream* output) = 0;
};
c++ 原生
#include "common.h"
public NativeClass : public INativeClass
{
public int NativeMethod(IStream* output)
{
outputStream->Write(...); //AccessViolationException happens here
}
}
c++ 托管
#include "common.h"
public ref class ManagedClass
{
private:
INativeClass* nativeObject;
public:
ManagedClass()
{
nativeObject = CreateNewNativeObject();
}
int ManagedMethod(IStream^ output)
{
NativeClass nativeObject = new
GCHandle streamHandle = GCHandle::Alloc(output);
IntPtr ipo = GCHandle::ToIntPtr(streamHandle);
nativeObject->NativeMethod(static_cast<IStream*>(ipo.ToPointer()));
}
}
c#
void main()
{
ManagedClass managedObject = new ManagedClass();
IStreamImplementation stream = new IStreamImplementation(filepath);
managedObject.ManagedMethod(stream);
}
我已经在互联网上搜索了几天,似乎找不到我做错了什么。我想我已经正确地转换为 IStream*,而且我不必担心 GC。我也试过使用 pin_ptr,但没有用。
如果这是重复的,我深表歉意,但正如我所说,几天来我一直在寻找解决方案。
编辑
用最小化的可编译代码更新了代码以重现问题(可能缺少一些包含)。
另外,当我说 IStream 时,我的意思是 InteropServices.ComTypes.IStream 或者它是 C++ 的对应物。我没有使用 std::istream
我按照 Hans Passant 所说的方法解决了这个问题:
在 ManagedClass 中,我有:
int ManagedMethod (IStream^ output)
{
IntPtr outputPtr = Marshal::GetIUnknownForObject(output);
IUnknown* outputNativePtr = static_cast<IUnknown*>(outputPtr.ToPointer());
nativeObject->NativeMethod(outputNativePtr);
}
在 NativeClass 中我有:
int NativeMethod(IUnknown* output)
{
IStream outputStream;
HRESULT hr = output->QueryInterface(IID_IStream, (void**)&outputStream);
if (FAILED(hr) || outputStream == nullptr)
{
//error
}
//do something
}