views:

19

answers:

0

In the Compact Framework 3.5, I am attempting to call an ActiveX object that has an IDL function signature:

HRESULT MyFunc([out] SAFEARRAY(float) *var)

The Interop generation creates the msil

[out] class [mscorlib]System.Array&  marshal( safearray float32)

Which seems reasonable enough, but I keep getting a "NotSupportedException". According to an article entitled "Interop: Common issues and debugging techniques" (I can't post more than one hyperlink, it's the first google result for that phrase), in the first bullet point under the "Marshaling" heading, the compact framework doesn't properly marshal SAFEARRAYs.

I have attempted to get around this problem, by manipulating the answer described in this MSDN forum post (Last entry describes his method): http://social.msdn.microsoft.com/forums/en-US/clr/thread/6641abfc-3a9c-4976-a523-43890b2b79a2/

So, I have created the following definition:

[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
}

And redefined the IDL for the function signature to:

HRESULT MyFunc([out] long *var)

And then issuing the following code:

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)

While the code appears to succeed, when I try to read back the data values, using the Marshal.Copy(dataPtr, myFloatArr, false) function, I am getting all 0's for the data, which tells me that the pointer that the ActiveX DLL is getting is probably totally bogus and it's off writing into oblivion.

Any suggestions as to what I may have messed up in these definitions, or suggestions for other ways of approaching this problem?

Thanks In Advance...