您将无法通过 CLI 传递 Memorystream。您能做的最好的事情是将“指针”(IntPtr)传递给字节缓冲区。
详情请见How can I pass MemoryStream data to unmanaged C++ DLL using P/Invoke?
我能够根据这篇文章 (PInvoke and IStream) 获得一个工作示例。
基本上你需要在 C# 中实现 IStream 接口。然后,您可以在 C++ 端将自定义 MemoryStream 作为 LPSTREAM 传递。这是一个获取流并获取大小的代码示例(只是一个简单的示例来展示它是如何完成的):
C++ LpWin32Dll.h
#ifndef LPWINDLL_H
#define LPWINDLL_H
extern "C" {
__declspec(dllexport) int SizeOfLpStream(LPSTREAM lpStream);
}
#endif
C++ LpWin32Dll.cpp
#include "stdafx.h"
#include <ocidl.h>
#include "LpWin32Dll.h"
// Provides DllMain automatically
[module(dll, name = "LpWin32Dll")];
__declspec(dllexport) int SizeOfLpStream(LPSTREAM lpStream)
{
STATSTG stat_info;
lpStream->Stat(&stat_info, STATFLAG_NONAME);
return stat_info.cbSize.LowPart;
}
C# PInvoke 定义
[DllImport("LpWin32Dll.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int SizeOfLpStream(IStream iStream);
C# IStream 实现(必须实现 IStream 接口)。我刚刚为 MemoryStream 类创建了一个包装类。
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class IMemoryStream : MemoryStream, IStream {
public IMemoryStream() : base() { }
public IMemoryStream(byte[] data) : base(data) { }
#region IStream Members
public void Clone(out IStream ppstm) { ppstm = null; }
public void Commit(int grfCommitFlags) { }
public void CopyTo(
IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) { }
public void LockRegion(long libOffset, long cb, int dwLockType) { }
public void Read(byte[] pv, int cb, IntPtr pcbRead)
{
long bytes_read = base.Read(pv, 0, cb);
if (pcbRead != IntPtr.Zero)
Marshal.WriteInt64(pcbRead, bytes_read);
}
public void Revert() { }
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
long pos = base.Seek(dlibMove, (SeekOrigin)dwOrigin);
if (plibNewPosition != IntPtr.Zero)
Marshal.WriteInt64(plibNewPosition, pos);
}
public void SetSize(long libNewSize) { }
public void Stat(
out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
int grfStatFlag)
{
pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
pstatstg.cbSize = base.Length;
}
public void UnlockRegion(long libOffset, long cb, int dwLockType) { }
public void Write(byte[] pv, int cb, IntPtr pcbWritten)
{
base.Write(pv, 0, cb);
if (pcbWritten != IntPtr.Zero)
Marshal.WriteInt64(pcbWritten, (long)cb);
}
#endregion
}
C# 使用
IMemoryStream ms = new IMemoryStream(new byte[] { 0x45, 0x23, 0x67, 0x34 });
int size = LpTest.SizeOfLpStream(ms);