Marshling structure with a pointer to another structure

  .net-core, c++, marshalling

I’m writing DLL in C++ for json parsing to use it in .NET app.
So there are several structures in C++ part:

struct Person
{
  Person(uint32_t id = 0, wchar_t* name = nullptr, wchar_t* phone = nullptr,
         wchar_t* email = nullptr, wchar_t* postal = nullptr);

  uint32_t id;
  wchar_t* name;
  wchar_t* phone;
  wchar_t* email;
  wchar_t* postal;
};

struct Locale {
  Locale(uint32_t id = 0, wchar_t* iso = nullptr, wchar_t* description = nullptr);

  uint32_t id;
  wchar_t* iso;
  wchar_t* description;
};

struct Organization
{
  Organization(uint32_t id = 0, wchar_t* inn = nullptr, wchar_t* officialName = nullptr,
               wchar_t* shortName = nullptr, wchar_t* kpp = nullptr,
               wchar_t* ogrn = nullptr, wchar_t* address = nullptr,
               Person* contact = nullptr, Locale* locale = nullptr);

  uint32_t id;           
  wchar_t* inn;          
  wchar_t* officialName; 
  wchar_t* shortName;    
  wchar_t* kpp;          
  wchar_t* ogrn;         
  wchar_t* address;      
  Person* contact;       
  Locale* locale;        
};

struct Domain
{
  Domain(uint32_t id = 0, wchar_t* name = nullptr, Organization* organization = nullptr,
         Locale* locale = nullptr);

  uint32_t id;                
  wchar_t* name;              
  Organization* organization; 
  Locale* locale;             
};

And corresponding structures in C#:

[StructLayout(LayoutKind.Sequential)]
[ComVisible(true)]
public struct PersonStruct
{
    [MarshalAs(UnmanagedType.U4)]
    public uint id;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string name;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string phone;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string email;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string postal;
}

[StructLayout(LayoutKind.Sequential)]
[ComVisible(true)]
public struct LocaleStruct
{
    [MarshalAs(UnmanagedType.U4)] 
    public uint id;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string iso;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string description;
}

[StructLayout(LayoutKind.Sequential)]
[ComVisible(true)]
public struct OrganizationStruct
{
    [MarshalAs(UnmanagedType.U4)]
    public uint id;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string inn;          

    [MarshalAs(UnmanagedType.LPWStr)]
    public string officialName;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string shortName;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string kpp;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string ogrn;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string address;  

    public IntPtr contactPtr;

    public IntPtr localePtr;    
}

[StructLayout(LayoutKind.Sequential)]
[ComVisible(true)]
public struct DomainStruct
{
    [MarshalAs(UnmanagedType.U4)]
    public uint id;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string name;

    public IntPtr organizationPtr;

    public IntPtr localePtr;            
}

DLL interface functions in C look like this

CACHELIB_API Result getDomain(Domain** domain, uint32_t domainId);

And a method to import it to .NET app

[DllImport(LIB_PATH, CallingConvention = CallingConvention.Cdecl, EntryPoint = "getDomain")]
internal static extern Result DoGetDomain(out IntPtr domain, uint domainId);

All unmanaged memory is allocated by DLL with CoTaskMemAlloc.

To get value of organizationPtr in DomainStruct I used

var organization = Marshal.PtrToStructure<Structures.OrganizationStruct>(domain.organizationPtr);

So my question is, do I have to use Marshal.FreeCoTaskMem(organization.contactPtr) to free unmanaged memory?

Do I need to use Marshal.DestroyStructure<PersonStruct>(organization.contactPtr) before it?

How to do all this marshaling in a proper way?

Best regards,
Georgy

Source: Windows Questions C++

LEAVE A COMMENT