Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Returning an Array of C# Structures

251 views
Skip to first unread message

hpw

unread,
Jun 14, 2007, 9:41:56 AM6/14/07
to
Hi all,

i'm trying to use COM Interop to return an array of c# structures to
Native code.
I tried to marshall the Array as SAFEARRAY.

The structure:

[StructLayout(LayoutKind.Sequential)]
[ComVisible(true)]
public struct teststruct{
[MarshalAs(UnmanagedType.LPStr)]
public string string1;

[MarshalAs(UnmanagedType.LPStr)]
public string string2;

[MarshalAs(UnmanagedType.LPStr)]
public string string3;

[MarshalAs(UnmanagedType.SafeArray)]
public string[] parameters;

};

is given back via a function

[return: MarshalAs(UnmanagedType.SafeArray)]
public teststruct[]
GetTestStruct([MarshalAs(UnmanagedType.LPStr)]string strParam, int
iParam) ;

I've generated the TLB via tlbexp.exe and used the Objects in a C++
Program.

Other calls with string-arrays and int-arrays work find. But for this
particular case i get the following _com_error:
0x80028019 - Old format or invalid type library

I also tried to specifiy the SafeArraySubType.
No Effect.

Any Help would be appreciated

HPW

herc

unread,
Jun 14, 2007, 11:53:29 AM6/14/07
to
On Jun 14, 9:41 am, hpw <h...@hp-weidinger.at> wrote:

> i'm trying to use COM Interop to return an array of c# structures to
> Native code. I tried to marshall the Array as SAFEARRAY.

Question: Does it HAVE to be an array or can you return a
collection?

Personally, I HATE passing arrays (SAFEARRAYS) around in COM, they are
a real pain. If a collection is an option, look into the IEnumVARIANT
interface. I would susspect that a C# ICollection interface is a
IEnumVARIANT. Google it and I think you will find much easier ways of
dealing with this issue;)

Cartoper

hpw

unread,
Jun 14, 2007, 12:14:23 PM6/14/07
to
> > i'm trying to use COM Interop to return an array of c# structures to
> > Native code. I tried to marshall the Array as SAFEARRAY.
>
> Question: Does it HAVE to be an array or can you return a
> collection?
>
> Personally, I HATE passing arrays (SAFEARRAYS) around in COM, they are
> a real pain. If a collection is an option, look into the IEnumVARIANT
> interface. I would susspect that a C# ICollection interface is a
> IEnumVARIANT. Google it and I think you will find much easier ways of
> dealing with this issue;)

Hi Cartoper,

thanks for your comments.

At the moment i did a similar workaround even though i do not like it:
i implemented an object with a dual-interface that allows me to read
the entires of the array.
I can pass back a reference to this Helper-Object that i can use to
read the structs.

If i pass back those things as Array (wich implements the ICollection
and IList interface) i get
an mscorlib::_Array that i can use. Unfortunately reading the items
using the IList interface always gives
me an Error "invalid argument type" if i try to read the arrays as
VARIANTs.

I havent tried using an IEnumVARIANT yet but i will also try this.

br
HPW

SteveR

unread,
Jul 9, 2007, 2:52:05 AM7/9/07
to
This is exactly the same problem I'm having. Have you got any code samples
you could post or url's I can refer to?
--
Steve

hpw

unread,
Jul 25, 2007, 7:50:18 AM7/25/07
to
Hi Steve,

sorry for the late answer.

I couldn't solve the problem - so i found a workaround for this.
I've used a wrapper for the list and returned this instead of the
array.

Alternatively you can also use one of the list-Classes provided by
System.Collections. ...

here is what i did:

[Guid("xxxxxxxxxxxxxxx")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ITeststructCollection {
void add(teststruct c);
int count();
teststruct get([MarshalAs(UnmanagedType.I4)] int i);
void Dispose();
};

and the implementation for this (TeststructCollection).
the call which returns the Interface looks like

TeststructCollection
GetCallEntries([MarshalAs(UnmanagedType.LPStr)]string smthing, int i);

Native code looks like this

...
_CallEntryCollectionPtr entries=engine-
>GetCallEntries(pszSmthing,i);

CoTaskMemFree(pszSmthing);

ICallEntryCollection *coll;
hResult=entries->QueryInterface(&coll);

if (FAILED(hResult)) {
char ch[255];
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,hResult,NULL,ch,
255,NULL);
char pszErr[1024];
sprintf(pszErr,"Reading COM-Entries Error: 0x%08x - %s
\n",hResult,ch);
fprintf(stderr,pszErr);
return ;
}

int count=coll->count();
...


hope this helps.

br
HPW

John xyz

unread,
Nov 27, 2011, 10:46:28 AM11/27/11
to
http://www.4microsoftsolutions.com/post/Understanding-Structures.aspx
>> On Thursday, June 14, 2007 11:53 AM herc wrote:

>> On Jun 14, 9:41 am, hpw <h...@hp-weidinger.at> wrote:
>>
>>
>> Question: Does it HAVE to be an array or can you return a
>> collection?
>>
>> Personally, I HATE passing arrays (SAFEARRAYS) around in COM, they are
>> a real pain. If a collection is an option, look into the IEnumVARIANT
>> interface. I would susspect that a C# ICollection interface is a
>> IEnumVARIANT. Google it and I think you will find much easier ways of
>> dealing with this issue;)
>>
>> Cartoper


>>> On Thursday, June 14, 2007 12:14 PM hpw wrote:

>>> Hi Cartoper,
>>>
>>> thanks for your comments.
>>>
>>> At the moment i did a similar workaround even though i do not like it:
>>> i implemented an object with a dual-interface that allows me to read
>>> the entires of the array.
>>> I can pass back a reference to this Helper-Object that i can use to
>>> read the structs.
>>>
>>> If i pass back those things as Array (wich implements the ICollection
>>> and IList interface) i get
>>> an mscorlib::_Array that i can use. Unfortunately reading the items
>>> using the IList interface always gives
>>> me an Error "invalid argument type" if i try to read the arrays as
>>> VARIANTs.
>>>
>>> I havent tried using an IEnumVARIANT yet but i will also try this.
>>>
>>> br
>>> HPW


>>>> On Monday, July 09, 2007 2:52 AM Steve wrote:

>>>> This is exactly the same problem I am having. Have you got any code samples
>>>> you could post or url's I can refer to?
>>>> --
>>>> Steve
>>>>
>>>>
>>>> "herc" wrote:


>>>>> On Wednesday, July 25, 2007 7:50 AM hpw wrote:

>>>>> Hi Steve,
>>>>>
>>>>> sorry for the late answer.
>>>>>
>>>>> I couldn't solve the problem - so i found a workaround for this.
>>>>> I've used a wrapper for the list and returned this instead of the
>>>>> array.
>>>>>
>>>>> Alternatively you can also use one of the list-Classes provided by
>>>>> System.Collections. ...
>>>>>
>>>>> here is what i did:
>>>>>
>>>>> [Guid("xxxxxxxxxxxxxxx")]
>>>>> [ComVisible(true)]
>>>>> [InterfaceType(ComInterfaceType.InterfaceIsDual)]
>>>>> public interface ITeststructCollection {
>>>>> void add(teststruct c);
>>>>> int count();
>>>>> teststruct get([MarshalAs(UnmanagedType.I4)] int i);
>>>>> void Dispose();
>>>>> };
>>>>>
>>>>> and the implementation for this (TeststructCollection).
>>>>> the call which returns the Interface looks like
>>>>>
>>>>> TeststructCollection
>>>>> GetCallEntries([MarshalAs(UnmanagedType.LPStr)]string smthing, int i);
>>>>>
>>>>> Native code looks like this
>>>>>
>>>>> ...
>>>>> _CallEntryCollectionPtr entries=engine-
>>>>>
0 new messages