| Author |
Message |
jaskiewiczm
Joined: 24 Apr 2008 Posts: 5
|
Posted: Thu Apr 24, 2008 8:53 pm Post subject: Marshaling Struct w/ VARIANT from C++ to C# |
|
|
Hi,
I'm trying to marshal over a struct that contains 2 VARIANTs from C++ to C# and of course having some trouble.
I pass a pointer for my struct into a C# function and on the C# side handle it as a IntPtr. At that point, I use PtrToStructure to turn it into a C# struct that has 2 items of type "object" in it. The app crashes at this point.
My question is, are there special considerations necessary for marshaling over a struct that contains VARIANTs? I can do the marshaling over w/ 2 ints just fine. The moment the VARIANT comes into play everything starts crashing.
All suggestions are greatly appreciated.
mj |
|
| Back to top |
|
 |
Robert
Joined: 30 Oct 2006 Posts: 428 Location: Cambridge, UK
|
Posted: Thu Apr 24, 2008 10:52 pm Post subject: |
|
|
Hi,
I've not tried with VARIANTS myself, but I have had to do something similar with PROPVARIANTS, and the structure looks similar from MSDN.
Try creating a VARIANT structure in C# which mirrors the C++ struct shown on MSDN, specifically with the vt parameter in there as well. You'll probably need to use explicit layouts, at which point you can get something that sort of pretends to be the C# equivalent of a union (by having the field offset of multiple fields being set to the same value).
Hope that helps,
Robert _________________ Robert Chipperfield
Developer, Red Gate Software Ltd |
|
| Back to top |
|
 |
jaskiewiczm
Joined: 24 Apr 2008 Posts: 5
|
Posted: Fri Apr 25, 2008 4:04 pm Post subject: C# VARIANT Port |
|
|
Hi Robert,
I'm taking your advice regarding implementing the C# explicit struct that's a VARIANT. The VARIANT type has a struct in a struct in a struct (for a total of 3) so that's what I'm implementing as well.
My implementation has tagVariant containing __tagVariant containing __tagBRecord.
My question is, what is the length of a complete struct? Is it just the length of its parts? __tagBRecord has 2 IntPtrs in it so is __tagBRecord's length 8 bytes? I'm trying to get these offsets right.
Again, thanks for your help,
mj
[StructLayout(LayoutKind.Explicit)]
public struct tagVARIANT
{
__tagVARIANT tagVariant;
IntPtr decVal;
}
[StructLayout(LayoutKind.Explicit)]
public struct __tagVARIANT
{
[FieldOffset(0)] short vt; // VARTYPE vt;
[FieldOffset(2)] short wReserved1; // WORD wReserved1;
[FieldOffset(4)] short wReserved2; // WORD wReserved2;
[FieldOffset(6)] short wReserved3; // WORD wReserved3;
//union
//{
[FieldOffset( ] long llVal; // LONGLONG llVal;
[FieldOffset( ] int lVal; // LONG lVal;
[FieldOffset( ] byte bVal; // BYTE bVal;
[FieldOffset( ] short iVal; // SHORT iVal;
[FieldOffset( ] int fltVal; // FLOAT fltVal;
[FieldOffset( ] long dblVal; // DOUBLE dblVal;
[FieldOffset( ] short boolVal; // VARIANT_BOOL boolVal;
//shit! _VARIANT_BOOL bool;
[FieldOffset( ] int scode; // SCODE scode;
[FieldOffset( ] long cyVal; // CY cyVal;
[FieldOffset( ] long date; // DATE date;
[FieldOffset( ] IntPtr bstrVal; // BSTR bstrVal;
[FieldOffset( ] IntPtr punkVal; // IUnknown *punkVal;
[FieldOffset( ] IntPtr pdispVal; // IDispatch *pdispVal;
[FieldOffset( ] IntPtr parray; // SAFEARRAY *parray;
[FieldOffset( ] IntPtr pbVal; // BYTE *pbVal;
[FieldOffset( ] IntPtr piVal; // SHORT *piVal;
[FieldOffset( ] IntPtr plVal; // LONG *plVal;
[FieldOffset( ] IntPtr pllVal; // LONGLONG *pllVal;
[FieldOffset( ] IntPtr pfltVal; // FLOAT *pfltVal;
[FieldOffset( ] IntPtr pdblVal; // DOUBLE *pdblVal;
[FieldOffset( ] IntPtr pboolVal; // VARIANT_BOOL *pboolVal;
[FieldOffset( ] IntPtr pbool; // _VARIANT_BOOL *pbool;
[FieldOffset( ] IntPtr pscode; // SCODE *pscode;
[FieldOffset( ] IntPtr pcyVal; // CY *pcyVal;
[FieldOffset( ] IntPtr pdate; // DATE *pdate;
[FieldOffset( ] IntPtr pbstrVal; // BSTR *pbstrVal;
[FieldOffset( ] IntPtr ppunkVal; // IUnknown **ppunkVal;
[FieldOffset( ] IntPtr ppdispVal; // IDispatch **ppdispVal;
[FieldOffset( ] IntPtr pparray; // SAFEARRAY **pparray;
[FieldOffset( ] IntPtr pvarVal; // VARIANT *pvarVal;
[FieldOffset( ] int byref; // PVOID byref;
[FieldOffset( ] byte cVal; // CHAR cVal;
[FieldOffset( ] short uiVal; // USHORT uiVal;
[FieldOffset( ] int ulVal; // ULONG ulVal;
[FieldOffset( ] long ullVal; // ULONGLONG ullVal;
[FieldOffset( ] int intVal; // INT intVal;
[FieldOffset( ] int uintVal; // UINT uintVal;
[FieldOffset( ] IntPtr pdecVal; // DECIMAL* pdecVal;
[FieldOffset( ] IntPtr pcVal; // CHAR *pcVal;
[FieldOffset( ] IntPtr puiVal; // USHORT *puiVal;
[FieldOffset( ] IntPtr pulVal; // ULONG *pulVal;
[FieldOffset( ] IntPtr pullVal; // ULONGLONG *pullVal;
[FieldOffset( ] IntPtr pintVal; // INT *pintVal;
[FieldOffset( ] IntPtr puintVal; // UINT *puintVal;
[FieldOffset( ] __tagBRECORD tagBRecord;
//struct __tagBRECORD
// {
// PVOID pvRecord;
// IRecordInfo *pRecInfo;
// } __VARIANT_NAME_4;
} // __tagVariant
[StructLayout(LayoutKind.Explicit)]
public struct __tagBRECORD
{
[FieldOffset(0)] IntPtr pvRecord; // PVOID pvRecord;
[FieldOffset(4)] IntPtr pRecInfo; // IRecordInfo *pRecInfo;
} // __VARIANT_NAME_4; |
|
| Back to top |
|
 |
Robert
Joined: 30 Oct 2006 Posts: 428 Location: Cambridge, UK
|
Posted: Mon Apr 28, 2008 7:31 am Post subject: Re: C# VARIANT Port |
|
|
| jaskiewiczm wrote: |
Hi Robert,
My question is, what is the length of a complete struct? Is it just the length of its parts? __tagBRecord has 2 IntPtrs in it so is __tagBRecord's length 8 bytes? I'm trying to get these offsets right.
Again, thanks for your help,
mj
|
Hi,
If you're laying out it explicitly, the easiest way to calculate the length is to add the size of the final field to that field's offset - so in the case of your __tagBRecord, 4+4=8 as you suggested. In this case that's also equal to the sum of the components, and most of the time I think that's probably true, but if there's unused space in the struct somewhere, it might not be.
I think all that's true
Rob _________________ Robert Chipperfield
Developer, Red Gate Software Ltd |
|
| Back to top |
|
 |
jaskiewiczm
Joined: 24 Apr 2008 Posts: 5
|
Posted: Mon Apr 28, 2008 2:11 pm Post subject: |
|
|
Robert,
When I'm attempting my Variant marshal via PtrToStructure, it hits that line and then nothing! It doesn't execute any subsequent lines and no exception is thrown.
The question that comes to mind for me is, since my structure that contains the VARIANTs inside contains the actual VARIANTs and not pointers to VARIANTs, I can't quite do a PtrToStructure call. What should I do instead?
Thanks,
mj |
|
| Back to top |
|
 |
Robert
Joined: 30 Oct 2006 Posts: 428 Location: Cambridge, UK
|
Posted: Mon Apr 28, 2008 2:23 pm Post subject: |
|
|
Hi,
Hmm, not quite sure what's happening there then. You shouldn't need to do a PtrToStructure call on the variant within a variant; it should just happen I think. However, I'm now reaching the edge of my knowledge about C#'s interop... I live in managed land for the most part when I can!
Sorry I can't be more helpful - all I can suggest is to keep playing around with it and see where you get.
Rob _________________ Robert Chipperfield
Developer, Red Gate Software Ltd |
|
| Back to top |
|
 |
jaskiewiczm
Joined: 24 Apr 2008 Posts: 5
|
Posted: Mon Apr 28, 2008 2:29 pm Post subject: |
|
|
Robert,
Made a little breakthrough. My struct that I pass from C++ to C# looks like this.
struct foobar{
VARIANT X;
VARIANT Y;
}
I turned the VARIANT references into pointers and it works fine. I can exchange integers across the interface.
What do I have to do to do this w/ references?
mj |
|
| Back to top |
|
 |
Robert
Joined: 30 Oct 2006 Posts: 428 Location: Cambridge, UK
|
Posted: Mon Apr 28, 2008 2:37 pm Post subject: |
|
|
I assume by that you mean when the VARIANT's target is a reference?
I'd guess at that point you get an IntPtr out of the the VARIANT, then PtrToStructure or PtrToIUnknown or whatever it to get the ComObject that you want to get out. Haven't tried doing it though
Cheers,
Robert _________________ Robert Chipperfield
Developer, Red Gate Software Ltd |
|
| Back to top |
|
 |
jaskiewiczm
Joined: 24 Apr 2008 Posts: 5
|
Posted: Mon Apr 28, 2008 4:51 pm Post subject: |
|
|
Robert,
Yeah, it's a reference. I think what I'm going to finally settle on is expanding the C++ API to include 2 pointers to VARIANTs and then just access those pointers instead of the references.
I tried to create an IntPtr that would point to the references but I had no luck.
Thanks for all the advice.
mj |
|
| Back to top |
|
 |
|