我一直在谷歌上转来转去,我可以找到各种讨论,很多建议,但似乎没有任何效果。我有一个 ActiveX 组件,它将图像作为字节数组。当我进行 TLB 导入时,它带有以下签名:
int HandleImage([MarshalAs(UnmanagedType.Struct)] ref object Bitmap);
我如何将 byte[] 传递给它?
还有另一个函数可以返回具有类似签名的数据,它之所以有效,是因为我可以传入“null”。返回的类型是字节[1..size](非零有界字节[])。但即使我尝试传入返回的内容,它仍然会出现类型不匹配异常。
更多细节:
我一直在编辑 IDispatch 接口签名中的方法(使用 ILSpy 从自动生成的互操作程序集中提取接口)。我几乎尝试了以下每种组合,它总是得到类型不匹配异常:
- 添加和删除“参考”
- 将参数数据类型更改为“byte[]”或“Array”
- 编组为 [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]。在玩了一段时间 MarshalAs 之后,我开始确信 IDispatch 不使用这些属性。
还尝试按原样使用“ref object”接口,并传递不同的类型:byte[], Array.CreateInstance(typeof(byte) (我认为它们是相同的,但我发现有人建议它,所以它不能伤害尝试)。
下面是一个 Delphi 代码示例,它创建了一个适当的数组来传递:
var
image: OLEVariant;
buf: Pointer;
image := VarArrayCreate([0, Stream.Size], VarByte);
Buf := VarArrayLock(image);
Stream.ReadBuffer(Buf^, Stream.Size);
VarArrayUnlock(image);
这是执行相同操作的 C 代码。我想如果我不能让它在 C# 中工作,我可以通过托管 C++ 调用它,尽管我宁愿将所有东西都放在一个项目中:
long HandleImage(unsigned char* Bitmap, int Length)
{
VARIANT vBitmap;
VariantInit (&vBitmap);
VariantClear(&vBitmap);
SAFEARRAYBOUND bounds[1];
bounds[0].cElements = Length;
bounds[0].lLbound = 1;
SAFEARRAY* arr = SafeArrayCreate(VT_UI1, 1, bounds);
SafeArrayLock(arr);
memcpy(arr->pvData, Bitmap, Length);
SafeArrayUnlock(arr);
vBitmap.parray = arr;
vBitmap.vt = VT_ARRAY | VT_UI1;
long result;
static BYTE parms[] = VTS_PVARIANT;
InvokeHelper(0x5e, DISPATCH_METHOD, VT_I4, (void*)&result, parms,
&vBitmap);
SafeArrayDestroy(arr);
VariantClear(&vBitmap);
return result;
}