tags:

views:

747

answers:

2

I have an ATL COM Server, where the method for the interface is

STDMETHODIMP CWrapper::RUN(long iDataSize, SAFEARRAY** iData)

and the MIDL for this function looks like

[id(1), helpstring("method RUN")] HRESULT RUN([in] long nSize, [in, size_is(nSize)] SAFEARRAY(_MyDataType*)* iData);

I import the tlb from this project using tlbimp, so I can use native arrays. I then call it from C# as follows

 m_ServerWrapper.RUN(iInputs.Length,ref iInputs)

where Inputs is already allocated and filled with another COM object from inside my C# program. Now, when I call into the C++ wrapper, I have a Bad Ptr for my safearray and the call into a subsequent COM object from CWrapper::RUN fails with the array not making it to the final dll. It shows up as unallocated. Does anyone have any clue what I'm doing wrong? Thanks

EDIT: I should have stated that the array looks just fine in C#.

EDIT2: The debugger shows iData safearray of IDispatch* = 0x0000000 , 5, 0x0000000 ({lpvtbl = 0xblahblah},.... So it looks like some of my information is getting there.

A: 

A normal C# array is not the same as a SAFEARRAY. I think you have to make your own:

[StructLayout(LayoutKind.Sequential)]
struct SafeArray
{
    public ushort   dimensions;  
    public ushort   features;    
    public uint     elementSize; 
    public uint     locks;       
    public IntPtr   dataPtr;     
    public uint     elementCount;
    public int      lowerBound;  
}

Then use Marshal.AllocCoTaskMem() to create the memory. Fill in all the data and then pass it.

jeffamaphone
All of the docs I can find seem to indicate the interop layer should marshal the array to a safearray
Steve
A: 

I had the same problem a couple of months ago, and I found this MSDN newsgroup link.

Shay Erlichmen