Search code examples
c#c++arraylistdllunmanagedexports

Return List/Array from unmanaged C# DLL


I have Unmanaged C# DLL:

[DllExport(ExportName = "GetStudentsList", CallingConvention = CallingConvention.StdCall)]
static public List<StudentsStruct>GetStudentsList() {  return List<StudentsStruct>;   }


[DllExport(ExportName = "maxElement", CallingConvention = CallingConvention.StdCall)]
static public int maxElement(int a, int b) { return c; }

I want to return List<StudentsStruct> from the function.

And I want to run above function in a C++ Application:

using GetStudentsListFn = List<StudentsStruct> (__stdcall *) (void);
GetStudentsListFn  GetStudentsList = reinterpret_cast<GetStudentsListFn> (GetProcAddress(mod, "GetStudentsList"));
List<StudentsStruct> myList = GetStudentsList();

using MaxElementFn = int(__stdcall *) (int a, int b);
MaxElementFn maxElement = reinterpret_cast<MaxElementFn> (GetProcAddress(mod, "maxElement"));
std::printf("max: %d\n", maxElement(1, 2));

MaxElement( ) function is working perfectly because it return an int. But i want to return List/Array of "StudentsStruct", from C# to C++.


Solution

  • I would do this with out array parameter and return the size, like this:

    using ExportDllAttribute.DllExport;
    using System.Runtime.InteropServices;
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct StudentsStruct
    {
        public string Name;
        public int SomeInt;
        public double SomeDouble;
    
        [DllExport]
        public static int GetStudentsList([Out] out StudentsStruct[] students)
        {
            students = new StudentsStruct[] { new StudentsStruct { Name = "Satan", SomeInt = 666, SomeDouble = 666 },
                    new StudentsStruct { Name = "Techno", SomeInt = 777, SomeDouble = 777 } };
            return students.Length;
        }
    }
    

    and the C++ code:

    #include<Windows.h>
    
    struct StudentsStruct
    {
    public:
        LPWSTR Name;
        int SomeInt;
        double SomeDouble;
    };
    
    using GetStudentsListFn = int (__stdcall*) (StudentsStruct **);
    
    int main()
    {
        HMODULE hModule = LoadLibraryA("DllExportArrayTest.dll");
        if (hModule)
        {
            GetStudentsListFn GetStudentsList = reinterpret_cast<GetStudentsListFn>(GetProcAddress(hModule, "GetStudentsList"));
            StudentsStruct* students = NULL;
            auto size = GetStudentsList(&students);
            for (int i = 0; i < size; i++)
                auto student = students[i];
            FreeLibrary(hModule);
        }
    }