user142350
user142350

Reputation: 222

Marshalling CodeElements to an IntPtr in C#

I am writing a Visual Studio add in and need to marshall a managed CodeElements object to it's unmananged form. I just need the pointer in memory, as I can cast it and treat it like a CodeElement on the unmanaged side.

    [DllImport("CodeMethodsToString.dll")]
    private static extern BSTR* CodeMethodsToString(void* functionObject);

    public static void CodeMethodsToXML(XmlElement parent, CodeElements elements)
    {
        //Call CodeMethodsToString: how do I marshall CodeElements to an IntPtr?
        //set XmlElement in here
    }

I know how to deal with the XML, and I have a working version of this in C#. I created the unmanaged DLL because calling all of the various member variables at the lowest level of recursion was killing the speed of the program. I simply need to know how to use System.Runtime.Interop.Marshal to convert the CodeElements object to a pointer to the COM object in memory.

Thanks.

Upvotes: 1

Views: 3281

Answers (4)

kaqkk
kaqkk

Reputation: 11

You can optionally check out the example at the end of the article: GCHandle MSDN

Upvotes: 1

scottm
scottm

Reputation: 28701

Looks like Jonathan was close. This is how I'd do it:

[DllImport("CodeMethodsToString.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string CodeMethodsToString(IntPtr functionObject);

public static void CodeMethodsToXML(XmlElement parent, CodeElements elements)
{
   GCHandle pin;
   try
   {
      pin = GcHandle.Alloc(elements, GCHandleType.Pinned);
      string methods = CodeMethodsToString(pin.AddrOfPinnedObject());
    }
    finally
    {
       pin.Free();
    }
}

Upvotes: 3

Jonathan C Dickinson
Jonathan C Dickinson

Reputation: 7285

As soon as you see a star or ampersand you should start by converting it to ref (safe version of a pointer). I have had reference types magically start working when I used the ref keyword in the past (which is highly contradictory - but I think it's one of those interop things):

[DllImport("example.dll")]
private static extern void DoStuff(ref CodeElements codeElements);

You could also try:

[DllImport("example.dll")]
private static extern void DoStuff([In, Out] ref CodeElements codeElements);

Or one of the permutations of those attributes.

One thing you might want to try is to use the MFC (I think, been a long time since C++) to make the COM library. Don't use a native call, export the thing as a type library and add it as a reference in Visual Studio (yes, it's that easy). Thus you will land up with something like:

myCoolClass.DoStuff(codeElements);

You might also want to pin it (if you need to pin it the error will be intermittent). I can't remember if the RCW will do that for you (I am almost certain it will), so here is the code to do it:

GCHandle handle = new GCHandle();
try
{
  handle = GCHandle.Alloc(fooz, GCHandleType.Pinned);
  // Use fooz.
}
finally
{
  if (handle.IsAllocated)
    handle.Free();
}

Upvotes: 1

dtb
dtb

Reputation: 217313

Is CodeElements a ComVisible interface and has a GuidAttribute?

Then C# will do the marshalling of COM objects for you, and you can simply use CodeElements as argument type:

[DllImport("example.dll")]
private static extern void DoStuff(CodeElements codeElements);

Upvotes: 1

Related Questions