[英].Net Compact Framework - Calling ActiveX Object that uses [out] SAFEARRAY(float) *
在Compact Framework 3.5中,我尝试调用具有IDL函数签名的ActiveX对象:
HRESULT MyFunc([out] SAFEARRAY(float) *var)
Interop一代创造了msil
[out] class [mscorlib]System.Array& marshal( safearray float32)
这似乎很合理,但是我不断收到“ NotSupportedException”。 根据一篇标题为“互操作:常见问题和调试技术”的文章(我不能发布多个超链接,这是该短语的第一个Google搜索结果),在紧凑框架“ Marshaling”标题下的第一个项目符号中没有正确地编组SAFEARRAY。
我试图通过处理此MSDN论坛帖子中的答案(最后一次介绍他的方法)来解决此问题: http : //social.msdn.microsoft.com/forums/en-US/clr/thread/6641abfc -3a9c-4976-a523-43890b2b79a2 /
因此,我创建了以下定义:
[StructLayout(LayoutKind.Sequential)]
struct SafeArray
{
public ushort dimensions; // Count of dimensions in the SAFEARRAY
public ushort features; // Flags to describe SAFEARRAY usage
public uint elementSize; // Size of an array element
public uint locks; // Number of times locked without unlocking
public IntPtr dataPtr; // Pointer to the array data
public uint elementCount; // Element count for first (only) dimension
public int lowerBound; // Lower bound for first (only) dimension
}
并将功能签名的IDL重新定义为:
HRESULT MyFunc([out] long *var)
然后发出以下代码:
IntPtr safeArrayPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(SafeArray)));
SafeArray safeArray;
safeArray.dimensions = 1;
safeArray.features = 0;
safeArray.elementSize = (uint)(Marshal.SizeOf(typeof(float)));
safeArray.locks = 0;
safeArray.elementCount = 6;
safeArray.lowerBound = 0;
safeArray.dataPtr = Marshal.AllocCoTaskMem((int)(safeArray.elementCount * safeArray.elementSize));
Marshal.StructureToPtr(safeArray, safeArrayPtr, false);
int iTmp = safeArrayPtr.ToInt32();
MyFunc(out iTmp)
虽然代码似乎成功,但是当我尝试使用Marshal.Copy(dataPtr,myFloatArr,false)函数读取数据值时,我得到的数据全为0,这告诉我该指针是ActiveX DLL获得可能完全是伪造的,这是写成遗忘的。
关于我可能将这些定义弄乱了的任何建议,或关于解决该问题的其他方式的建议?
提前致谢...
好吧,我已经解决了这个问题。
希望我的回答对遇到相同问题的其他人有所帮助。 我遇到的问题是COM tlb声明中的[out]标记意味着我传入的所有内容都将被COM库中创建的对象覆盖。 经典的(也是非常基本的问题)“通过引用与按值传递”的相当复杂的版本
因此,正确的封送处理方法是使用我上面发布的SafeArray的定义。
请勿触摸IDL签名本身-这不是一种很干净的方法。 相反,在生成的Interop库上使用ildasm可以从以下方式修改il:
[out] class [mscorlib]System.Array& marshal( safearray float32)
至
[out] native int&
然后用ilasm重新组装,这将产生C#函数签名
void MyFunc(out IntPtr var)
然后,调用代码变为:
IntPtr ip;
SafeArray safeArray;
float []arrFloats;
MyFunc(out ip);
//Marshal the structure itself
Marshal.StructureToPtr(safeArray, ip, false);
//Marshal the data over to .NET
float []arrFloats = new float[safeArray.elementCount];
Marshal.Copy(safeArray.dataPtr, arrFloats, 0, (int)safeArray.elementCount);
最后,我们需要释放内存(记住,我们更改了函数签名,所以我们没有给.NET足够的信息来实际释放内存。
//Don't forget to free both the structure and the object
Marshal.FreeCoTaskMem(safeArray.dataPtr);
Marshal.FreeCoTaskMem(ip);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.