你要么需要分配不安全内存为@ KimKulling的回答暗示,或发送数组作为适当标记SafeArray
。下面摘录了演示三种不同方法的示例,并且available on github。
C#的界面看上去会是什么样子:
[ComVisible(true)]
[Guid("7FE927E1-79D3-42DB-BE7F-B830C7CD32AE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IImageProvider
{
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
byte[] GetImage(int foo);
IntPtr GetImageAsUnmanaged(int foo, out int cbBuff);
void GetImageAsUnmanagedPreallocated(int foo, ref int cbBuff, IntPtr pBuff);
}
对于C#服务器实现的:
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[Guid("D133B928-A98B-4006-8B00-4AA09BD042E7")]
[ProgId("CSByteArrayServer.ImageProvider")]
public class ImageProvider : IImageProvider
{
private const int E_INVALIDARG = unchecked((int)0x80070057);
RNGCryptoServiceProvider crng = new RNGCryptoServiceProvider();
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
public byte[] GetImage(int foo)
{
return GetBytes();
}
private byte[] GetBytes()
{
byte[] data = new byte[500];
crng.GetBytes(data);
return data;
}
public IntPtr GetImageAsUnmanaged(int foo, out int cbBuff)
{
var data = GetBytes();
var result = Marshal.AllocCoTaskMem(data.Length);
Marshal.Copy(data, 0, result, data.Length);
cbBuff = data.Length;
return result;
}
public void GetImageAsUnmanagedPreallocated(int foo, ref int cbBuff, IntPtr pBuff)
{
var data = GetBytes();
if (cbBuff < data.Length)
{
cbBuff = data.Length;
throw Marshal.GetExceptionForHR(E_INVALIDARG);
}
cbBuff = data.Length;
Marshal.Copy(data, 0, pBuff, data.Length);
}
}
和一个C++客户端:
int main()
{
CoInitialize(NULL);
IImageProvider *pImgProvider;
CoCreateInstance(__uuidof(ImageProvider), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IImageProvider), (LPVOID*)&pImgProvider);
int imageId = 0;
// with SafeArray
{
SAFEARRAY *pSafeArray;
auto hr = pImgProvider->GetImage(0, &pSafeArray);
assert(hr == S_OK);
CComSafeArray<BYTE> safeArray;
safeArray.Attach(pSafeArray);
ManipulateData(&safeArray);
// CComSafeArray will free the memory allocated by pSafeArray
}
// with CoTaskMemAlloc
{
char *pData;
int cbData;
auto hr = pImgProvider->GetImageAsUnmanaged(0, (long*)&cbData, (long*)&pData);
assert(hr == S_OK);
ManipulateData(pData, cbData);
CoTaskMemFree(pData);
}
// with caller allocate
{
int cbData;
auto hr = pImgProvider->GetImageAsUnmanagedPreallocated(imageId, (long*)&cbData, (long)nullptr);
assert(hr == E_INVALIDARG);
char *pData = new char[cbData];
hr = pImgProvider->GetImageAsUnmanagedPreallocated(imageId, (long*)&cbData, (long)pData);
assert(hr == S_OK);
ManipulateData(pData, cbData);
delete[] pData;
}
system("pause");
CoUninitialize();
return 0;
}
void ManipulateData(char* pBuff, int cbBuff)
{
char hash = 0;
for (int i = 0; i < cbBuff; i++)
{
hash ^= pBuff[i];
}
std::cout << "Hash is " << +hash << std::endl;
}
void ManipulateData(CComSafeArray<BYTE> *pSafeArray)
{
BYTE hash = 0;
for (ULONG i = 0; i < pSafeArray->GetCount(); i++)
{
hash ^= pSafeArray->GetAt(i);
}
std::cout << "Hash is " << +hash << std::endl;
}
哪一行代码获取错误?它显示在这里吗? – Baldrick
@Baldrick当我尝试将返回值分配给字节数组时,我从C++端得到错误 – CodeJam