繁体   English   中英

.Net Compact Framework-调用使用[out] SAFEARRAY(float)的ActiveX对象*

[英].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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM