Reputation: 25
the c++ function know size of array and have to create it.
the c++ code:
__declspec(dllexport) int getlog(int* &data)
{
data = new int[5];
for (int i = 0; i < 5; i++)
{
data[i] = i;
}
return 0;
}
and c#:
[DllImport(@"myDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int getlog(int[] data);
and
int[] arr = null;
getlog(arr);
i see this but it not helped
Upvotes: 2
Views: 361
Reputation: 6427
On C# side:
[DllImport(@"myDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int getlog([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out int[] data,
out int length);
On C++ side:
#include <Objbase.h>
extern "C" __declspec(dllexport) int getlog(int** data, int * length)
{
*length = 5;
int sizeInBytes = sizeof(int) * (*length);
*data = static_cast<int*>(CoTaskMemAlloc(sizeInBytes ));
for (int i = 0; i < 5; i++)
{
(*data)[i] = i;
}
return 0;
}
CoTaskMemAlloc
will give CLR ability to take care of freeing the memory once it's no longer reachable. More about it in "Memory Management with the Interop Marshaler":
The runtime always uses the
CoTaskMemFree
method to free memory. If the memory you are working with was not allocated with theCoTaskMemAlloc
method, you must use anIntPtr
and free the memory manually using the appropriate method.
Method above works for .NET 4.0 and above. For .NET 3.5 it fails due to the limited support of unmanaged arrays:
The array being controlled cannot be passed as ref or out parameters. Likewise, the parameter containing the size of the array must be passed by value (the SizeParamIndex field cannot refer to a ref or out parameter)
To overcome this problem and get the array on the C# side use the following signature:
[DllImport(@"MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int getlog(out IntPtr data, out int length);
When you have IntPtr
to the data it's possible to copy content to the managed array:
int length;
IntPtr data;
getlog(out data, out length);
int[] managedArr = new int[length];
Marshal.Copy(data, managedArr, 0, length);
Also you could process the content of such array without coping. To use this method enable "Allow unsafe code" in project settings:
int length;
IntPtr data;
getlog(out data, out length);
unsafe
{
int* intArray = (int*)data.ToPointer();
for (int i = 0; i < length; i++)
{
Console.WriteLine(intArray[i]);
}
}
Upvotes: 3