Discussion:
Returning an Array of C# Structures
(too old to reply)
hpw
2007-06-14 13:41:56 UTC
Permalink
Raw Message
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
2007-06-14 15:53:29 UTC
Permalink
Raw Message
Post by hpw
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
2007-06-14 16:14:23 UTC
Permalink
Raw Message
Post by herc
Post by hpw
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
2007-07-09 06:52:05 UTC
Permalink
Raw Message
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
Post by herc
Post by hpw
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
2007-07-25 11:50:18 UTC
Permalink
Raw Message
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
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
Post by herc
Post by hpw
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
John xyz
2011-11-27 15:46:28 UTC
Permalink
Raw Message
http://www.4microsoftsolutions.com/post/Understanding-Structures.aspx
Post by hpw
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.
[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
0x80028019 - Old format or invalid type library
I also tried to specifiy the SafeArraySubType.
No Effect.
Any Help would be appreciated
HPW
Post by herc
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
Post by hpw
Hi Cartoper,
thanks for your comments.
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
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
Post by hpw
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. ...
[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-
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
Loading...