Search code examples
c#c++dllimportdllexport

How to pass *& and **& parameter to C++ dll from C# code


I have C++ dll as par below

Function prototype and structure definition

extern "C" int  __declspec(dllexport) DoOPeration(DataStruct *&, DataStructInfo **&);

typedef struct
{
        int   count;
        float CountData;
        bool  flg;
        BYTE* data;
        char   info[100];
}DataStruct;

typedef struct
{
        int   count;
        bool  flg;
        BYTE* data; 
}DataStructInfo;


Implementation of DoOPeration function is as par below

int __declspec(dllexport) ImageAnalyze(DataStruct *&all, DataStructInfo **&part)
{
    int ret = 0;
    try
    {
          if(all->count == 0)
            return(ERR_PARAMERROR);

          for(cnt = 0 ; cnt < all->count  ; cnt++)
          {
             if(part[cnt]->data== NULL)
                return(ERR_NO_IMAGE);
          } 
    }
    catch(int err)
    {
        return(err);
    }
    catch(...)
    {
        return(-2);
    }
    return(ret);
}

Corresponding with the above I have added C# side code as par below

DLL import, structure(class) definition

[DllImport(@"C:\TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int DoOperation(ref DataStruct all, ref DataStructInfo[] part);

[StructLayout(LayoutKind.Sequential)]
public class DataStruct
{
        int   count = 0;
        float CountData = 0;
        bool  flg = 0;
        byte[] data = null;
        string   info = 0;
}

[StructLayout(LayoutKind.Sequential)]
public class DataStructInfo 
{
        int   count = 0;
        bool  flg = 0;
        byte[]  data;   
}

// DoOperation function calling

DataStruct alls = new DataStruct(); // set all required parameter
DataStructInfo[] part= new DataStructInfo[3]; // set all required parameter
int ret = DoOperation(ref alls, ref part);

After calling C++ dll function from c# code, I have observed the values of the function parameter inside c++ dll.

  1. For parameter[alls] values are passing correctly
  2. For parameter [part] values are not passing correctly (Showing some garbage values)

Please let me know information regarding passing of 2nd parameter i.e(**&) from c# code.

Also please let me know, if I have done any other mistakes so that I can correct it.

Note: I can not change the C++ dll code


Solution

  • I got the solution with below approach.

    C# side code

    DLL import, structure definition

    [DllImport(@"C:\TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int DoOperation(ref IntPtr all, ref IntPtr[] part);
    
    [StructLayout(LayoutKind.Sequential)]
    public struct DataStruct
    {
        public int   count { get; set; }
        public float CountData { get; set; }
        public bool  flg { get; set; }
        public IntPtr data { get; set; }
        public string   info { get; set; }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct DataStructInfo 
    {
        public int   count { get; set; }
        public bool  flg { get; set; }
        public IntPtr  data { get; set; }
    }
    
    // First parameter
    DataStruct alls = new DataStruct(); // set all required parameter
    IntPtr intPtrsAll = new IntPtr();
    intPtrsAll = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(DataStruct)));
                Marshal.StructureToPtr<DataStruct>(alls, intPtrsAll, false);
    
    // Second parameter
    DataStructInfo[] part= new DataStructInfo[3]; // set all required parameter
    IntPtr[] intPtrsParts= new IntPtr[part.Length];
    
    for (int i = 0; i < intPtrsParts.Length; i++)
    {
        intPtrsParts[i] = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(DataStructInfo)));
        Marshal.StructureToPtr<DataStructInfo>(part[i], intPtrsParts[i], false);
    }
    
    int ret = DoOperation(ref intPtrsAll, ref intPtrsParts);
    
    
    

    Note: To set byte[] data at C# side, I have used [IntPtr] with below approach

    byte[] rowData = GetRawBytes(dataHandler); // function to read byte[] data
    int size = Marshal.SizeOf(rowData[0]) * rowData.Length;
    data = Marshal.AllocHGlobal(size); // IntPtr property of struct's
    Marshal.Copy(rowData, 0, data, rowData.Length);