I'm writing a wrapper library in c# for c++ using the dll's header file, but can't figure out how to convert types.

StackOverflow https://stackoverflow.com/questions/22103963

  •  18-10-2022
  •  | 
  •  

Question

I have a struct in the c++ header file that looks like:

typedef struct sFrameOfData
{
    int            iFrame;                  
    float          fDelay;                 
    int            nBodies;                 
    sBodyData      BodyData[MAX_N_BODIES]; 

    int            nUnidentifiedMarkers;    
    tMarkerData*   UnidentifiedMarkers;    

    sAnalogData    AnalogData;              

    sRecordingStatus RecordingStatus;      

}

where sAnalogData,tMarkerData, and sRecordingStatus are custom c++ structs. The c# method being called is:

[DllImport("Cortex_SDK.dll")]
    public static extern unsafe sFrameOfData* Cortex_GetCurrentFrame();

and I rewrote the structs as:

 [StructLayout(LayoutKind.Sequential)]
    public unsafe struct sFrameOfData
    {
        private readonly int iFrame; //!< Cortex's frame number
        private readonly float fDelay; //!< Total time (seconds) from Camera to the Host sending the data

        private readonly int nBodies; //!< The bodies should match the descriptions

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] private readonly sBodyData BodyData;
        //!< The data for each body

        private readonly int nUnidentifiedMarkers; //!< Number of unrecognized markers
        private readonly tMarkerData* UnidentifiedMarkers; //!< The unrecognized markers

        private readonly sAnalogData AnalogData; //!< The analog data packaged

        private readonly sRecordingStatus RecordingStatus; //!< Info about name and frames being recorded
    }

but I get cannot marshal 'return value'. Pointers cannot reference marshaled structures.

No correct solution

OTHER TIPS

You can probably start with the following skeleton.

Create a managed class to hold the data:

public class FrameOfData
{
    public int iFrame { get; set; }
    //...
}

Mark the return value of the p/invoke import with MarshalAs indicating a class that will do the custom marshal (i.e. FrameMarshaler class):

[DllImport("Cortex_SDK.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FrameMarshaler))]
public static extern FrameOfData Cortex_GetCurrentFrame();

The FrameMarshaler class is responsible of doing the custom marshaling, receiving a pointer to the unmanaged struct and returning a managed object, this can be done in the MarshalNativeToManaged method:

public class FrameMarshaler : ICustomMarshaler
{
        public void CleanUpManagedData(object ManagedObj)
        {
        }
        public void CleanUpNativeData(IntPtr pNativeData)
        {
        }
        public int GetNativeDataSize()
        {
            return -1;
        }
        public IntPtr MarshalManagedToNative(object ManagedObj)
        {
            throw new NotImplementedException();
        }
        public object MarshalNativeToManaged(IntPtr pNativeData)
        {
            // Here, we call C++/CLI code
            FrameOfData frame = Marshaler.MarshalFrame(pNativeData);    
            return frame;
        }   
}

The method Marshaler.MarshalFrame will be on a C++/CLI assembly. The following code is an example of a C++/CLI marshaler for the struct:

#include "Cortex_SDK.h"
#pragma once

using namespace System;

public ref class Marshaler
{
    public:
        static FrameOfData^ MarshalFrame(IntPtr dispo)
        {
            // Cast the IntPtr to the unmanaged pointer
            sFrameOfData* unmanaged = static_cast<sFrameOfData*>(dispo.ToPointer());
            // Transform unmnaged pointer to a managed object
            FrameOfData^ managed = gcnew FrameOfData();
            managed->iFrame = unmanaged.iFrame;
            // ...
        }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top