如何使用 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
}