all groups > dotnet interop > april 2008 >
You're in the

dotnet interop

group:

Struct w/ VARIANT Marshalling


Struct w/ VARIANT Marshalling Michael
4/23/2008 6:53:03 PM
dotnet interop:
Hi, I've been banging my head against this one and now I'm about to scream. Any suggestions appreciated. I've scoured the net too and for some reason all suggestions don't work.

I've got a C++ app that takes a function pointer from a C# application (it's for a callback). The callback signature looks like this.
void callbackSignature( SpecialType *st );

The SpecialType is a struct that looks like the following (in C++).
struct SpecialType{
VARIANT a;
VARIANT b;
}

Now, what I'm trying to do is fire the callback from C++ and catch it and process the SpecialType in C#.

I've implemented a struct in my C# application that mirrors the C++ one that looks like
public struct SpecialCSharpType{
Object a;
Object b;
}

The actual callback in C# that gets implemented has a signature that looks like the following.
static void CSharpCallback( IntPtr special );
When I get the special type, I know that it's an instance of my SpecialType, so I marshal it over using Marshal.PtrToStructure.
SpecialCSharpType scs = Marshal.PtrToStructure( special, typeof( SpecialCSharpType ) );

The funny thing is that when the previous line executes, the application just totally crashes. I can wrap it in exception handling but to no avail.
My question is, does the marshalling of a struct that contains VARIANTs require some sort of special handling?
Any help is appreciated. Thanks,
mj

From http://www.developmentnow.com/g/21_2003_9_8_0_0/dotnet-framework-interop.htm

Posted via DevelopmentNow.com Groups
Re: Struct w/ VARIANT Marshalling Willy Denoyette [MVP]
4/24/2008 12:00:00 AM
[quoted text, click to view]


The reason is that the PInvoke marshaler has no idea what object refers to,
you have to custom marshal the structure yourself.
Her is a complete sample to get you started.

// C# file using n1.dll
using System;
using System.Runtime.InteropServices;
using System.Security;

struct stn1
{
internal object a;
internal object b;
}

public class Test
{
static CallBackDelegate cb;
public static void Main(string[] args)
{
cb = new CallBackDelegate(Test.Target1);
NativeFunc(cb);
}
static void Target1(IntPtr pst)
{
stn1 st = new stn1();
st.a = Marshal.GetObjectForNativeVariant(Marshal.ReadIntPtr(pst));
st.b = Marshal.GetObjectForNativeVariant(Marshal.ReadIntPtr(new
IntPtr(pst.ToInt32() + offSet)));
Console.WriteLine("{0} {1}", st.a, st.b);
}

public delegate void CallBackDelegate(IntPtr pst);
[DllImport("n1.dll"), SuppressUnmanagedCodeSecurity]
internal static extern void NativeFunc(CallBackDelegate callback);
}

// file: n1.cpp
// Compile with cl /EHsc /LD n1.cpp
#include <windows.h>
#include <cstdio>
#include <comdef.h>
#include <comutil.h>
struct SpecialType{
VARIANT *a;
VARIANT *b;
};

typedef void (__stdcall *RunTest)(SpecialType *st);
extern "C" void __declspec(dllexport) __stdcall NativeFunc(RunTest test)
{
SpecialType *st = new SpecialType();
BSTR bstr1 = SysAllocString(L"This is a BSTR in a VARIANT.");
VARIANT v1;
v1.vt = VT_BSTR;
v1.bstrVal = bstr1;
int i = 42;
VARIANT v2;
v2.vt = VT_I4;
v2.lVal = i;
st->a = &v1;
st->b = &v2;
test(st);
}


Willy.
RE: Struct w/ VARIANT Marshalling Michael
4/24/2008 5:42:11 AM
A little bit more on this one. I'm looking at the address of the SpecialStruct in C++ and in C# and the addresses are identical.
At least the pointers are making it across okay. For some reason the marshalling from Ptr to Structure is bombing out.

From http://www.developmentnow.com/groups/viewthread.aspx?newsgroupid=21&threadid=1053880

Posted via DevelopmentNow.com Groups
RE: Struct w/ VARIANT Marshalling Michael
4/24/2008 12:54:55 PM
Another little tidbit. If I replace the VARIANTs in the struct, everything marshals over just fine.
mj

From http://www.developmentnow.com/groups/viewthread.aspx?newsgroupid=21&threadid=1053880

Posted via DevelopmentNow.com Groups
Re: Struct w/ VARIANT Marshalling Willy Denoyette [MVP]
4/24/2008 4:06:37 PM
[quoted text, click to view]



You'll to 'custom' marshal the variants, take a look at the
Marshal.GetObjectForNativeVariant method for this.

Willy.
RE: Struct w/ VARIANT Marshalling Michael
4/25/2008 8:36:37 AM
Hi Willy,
Question about your code snippet. You pass in the SpecialType into the C# callback and on the C# side, you do a GetObjectFromNativeVariant on the IntPtr that's passed into the callback.
Is this correct? Don't you need to unpackage the SpecialType first before you do any GetObjectFromNativeVariants first? Or are you assuming that the variant resides at the first memory location?
Also, what is the 'offset' in your code?

Thanks for your help,
mj

From http://www.developmentnow.com/groups/viewthread.aspx?newsgroupid=21&threadid=1053880

Posted via DevelopmentNow.com Groups
RE: Struct w/ VARIANT Marshalling Michael
4/25/2008 10:41:10 AM
I discovered one other significant weird thing.
If I don't populate my VARIANT with the BSTR, I don't see the callback firing.
mj

From http://www.developmentnow.com/groups/viewthread.aspx?newsgroupid=21&threadid=1053880

Posted via DevelopmentNow.com Groups
Re: Struct w/ VARIANT Marshalling Willy Denoyette [MVP]
4/25/2008 6:02:36 PM
[quoted text, click to view]

Actually, I'm reading the first pointer passed in the structure, using
Marshal.ReadIntPtr in:

st.a = Marshal.GetObjectForNativeVariant(Marshal.ReadIntPtr(pst));

and then I'm reading the next pointer, that's why I need to calculate the
offset, which is the size of a pointer which depending on the bit-ness
(32/64 bit) of the OS you are running on.
IntPtr size = 4 bytes on 32-bit while 8 bytes on 64-bit.
To resume, C++ passes a pointer to a structure containing variant pointers.
C# reads each pointer value from the structure and uses this pointer to
marshal the content of the VARIANT to an object type.

Willy.

RE: Struct w/ VARIANT Marshalling Adam Root
4/29/2008 11:37:01 AM
Michael,

I wrote a blog article about a PropVariant struct. You may find it useful:

http://blogs.msdn.com/adamroot/

Adam

[quoted text, click to view]
AddThis Social Bookmark Button