Click here to Skip to main content
15,946,988 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am writing a .net wrapper for a C library. My problem is marshalling of non-blittable types.

The library uses structures with nested structures.
The C function requires a pointer as a parameter.

<DllImport(log.dll, CharSet:=CharSet.Ansi, EntryPoint:="Write", CallingConvention:=CallingConvention.StdCall)>
    Private Shared Function Write(fooPtr As IntPtr) As Int32
    End Function

<StructLayout(LayoutKind.Sequential, Pack:=1)>
Public Structure Foo
    Public AdditionalInformations As AdditionalInformations'Nested Structure
    Public Tick As Integer
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public Trick As Integer()
    Public Trick As Integer
    Public Truck As Integer

    Public Description As String ' name in MBCS
    Public Data As Byte() ' data as array with variable length
End Structure

<StructLayout(LayoutKind.Sequential, Pack:=1)>
   public Structure AdditionalInformations
   public Informations as Informations  'Nested Structure
   public Bar as integer
End Structure

<StructLayout(LayoutKind.Sequential, Pack:=1)>
public Structure Informations 
   public Size as Integer
   public Name as Integer
End Structure

If I try to pin the Memory of this Structure using GCHandle.Alloc(Foo, GCHandleType.Pinned) I got an Exception Object doesn't contains primitive data types.

Is it possible to use the MarshalAs-Attributes to tell the Compiler how this Structures should be interpreted ?

What I have tried:

Tried to use MarshalAs Attributes and Marshal.StructureToIntptr (allocate size of structure and call Marshal.StructureToPtr).

Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Foo))
     Marshal.StructureToPtr(Foo, pnt, False)
Updated 12-Jun-23 6:42am

1 solution

Well, you need to create an instance of class, as is described here: Marshalling Classes, Structures, and Unions - .NET Framework | Microsoft Learn[^]

MyPerson personName;
        personName.first = "Mark";
        personName.last = "Lee";

        IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(personName));
        Marshal.StructureToPtr(personName, buffer, false);

So, instead of:
Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Foo))
     Marshal.StructureToPtr(Foo, pnt, False)

You need something like that:
Dim f as Foo = ...
Dim pnt As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(f))
     Marshal.StructureToPtr(f, pnt, False)

Do you see the difference?
Share this answer

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900