I have a Structure with a nested Structure. Now I need to pass this Structure to a C-Dll. But if I call Marshal.SizeOf(Person) I get an Exception which says that no meaningful size or offset can be compute.
Example:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure Person
<MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef:=GetType(OrganMarshaler))>
Public Organs as Organs
public Name as String
Public FirstName as String
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure Organs
Public Heart As Boolean
Public Stomach as Boolean
end Structure
Imports System.Runtime.InteropServices
Public Class OrganMarshaler
Implements ICustomMarshaler
Private _managedObjects As New Dictionary(Of IntPtr, Object)
' Singleton instance of the custom marshaler
Private Shared _instance As VBLObjectHeaderBaseMarshaler
Private Shared Function GetInstance(cookie As String) As OrganMarshaler
If _instance Is Nothing Then
_instance = New OrganMarshaler()
End If
Return _instance
End Function
Public Sub CleanUpManagedData(managedObj As Object) Implements ICustomMarshaler.CleanUpManagedData
'Nothing to do
End Sub
Public Sub CleanUpNativeData(pNativeData As IntPtr) Implements ICustomMarshaler.CleanUpNativeData
Marshal.FreeCoTaskMem(pNativeData)
pNativeData = IntPtr.Zero
End Sub
Public Function GetNativeDataSize() As Integer Implements ICustomMarshaler.GetNativeDataSize
Return Marshal.SizeOf(GetType(Organs))
End Function
''' <summary>
''' Marshal the managed object to native format and return the native pointer
''' </summary>
''' <param name="managedObj"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function MarshalManagedToNative(managedObj As Object) As IntPtr Implements ICustomMarshaler.MarshalManagedToNative
If managedObj Is Nothing Then
Return IntPtr.Zero
End If
If TypeOf managedObj Is Organs = False Then
Throw New ArgumentException("The input argument is not Organs.")
End If
Dim ptr As IntPtr = Marshal.AllocCoTaskMem(GetNativeDataSize)
Marshal.StructureToPtr(managedObj, ptr, False)
SyncLock _managedObjects
_managedObjects.Add(ptr, managedObj)
End SyncLock
Return ptr
End Function
Public Function MarshalNativeToManaged(pNativeData As IntPtr) As Object Implements ICustomMarshaler.MarshalNativeToManaged
SyncLock _managedObjects
Dim headerBase As Organs = CType(_managedObjects(pNativeData), Organs)
_managedObjects.Remove(pNativeData)
Marshal.PtrToStructure(Of Organs)(pNativeData, headerBase)
Return headerBase
End SyncLock
End Function
End Class
I do not know how to debug this Marshaler Class. I can set Breakpoints, but I never reach them.
Try to use a Custom Marshaler Class (implement ICustomMarshaler)