I am unable to pass up an array of structs, but I can pass up ONE.
I have looked at several answers on this site which are indicated as correct. But none of them work for me. In all cases where the answer has the IntPtr as an 'out IntPtr someName' in the PInvoke signature, the value I always get is zero. If the IntPtr is a return value, I cannot resolve it as an array of struct pointers.
Here is my attempt with the IntPtr as a return code: Unamanged C++
extern "C" EXPORTDLL_API sDeviceEndPoint **CallStartDiscovery(ZBTransport *zbTransport, int *length, int *result)
{
if(zbTransport != NULL)
{
std::list<sDeviceEndPoint *> deviceEndPoints;
sDeviceEndPoint **devEndPoints;
zbTransport->StartDiscovery(&deviceEndPoints, result);
*length = deviceEndPoints.size();
if(*length > 0)
{
devEndPoints = zbTransport->getDiscoveredEndPointPtrs();
devEndPoints[*length] = devEndPoints[0]; // Test duplicate
*length = *length + 1;
return &devEndPoints[0];
}
}
return NULL;
}
C# PInvoke signature:
[DllImport("PInvokeBridge.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr CallStartDiscovery(IntPtr pZbTransportObject, ref int length, ref int result);
C# implementation
public Collection<DeviceEndPoint> DiscoverHCSensors()
{
Collection<DeviceEndPoint> discoveredZigBeeDevices = new Collection<DeviceEndPoint>();
int length = 0;
int result = 0;
IntPtr arrayValue = CallStartDiscovery(_pZbTransportObject, ref length, ref result);
if (ErrorCodes.ConvertResultCode(result) == ResultCode.rc_SUCCESS)
{
var deviceEndPointSize = Marshal.SizeOf(typeof(DeviceEndPoint));
for (var i = 0; i < length; i++)
{
discoveredZigBeeDevices.Add((DeviceEndPoint)Marshal.PtrToStructure(arrayValue, typeof(DeviceEndPoint)));
arrayValue = new IntPtr(arrayValue.ToInt32() + deviceEndPointSize);
}
return discoveredZigBeeDevices;
}
else
{
String error = "Error"; // Put something helpful in here
TransportException transEx = new TransportException(error);
transEx.Method = "DiscoverHCSensors";
transEx.ErrorCode = result;
transEx.TransportType = _transportString;
throw transEx;
}
}
I know the layout of my DeviceEndPoint struct defined in C# is correct because if I change the C++ code to pass up just a single pointer to the DeviceEndPoint struct, I correctly load the single struct in the Collection.
The other attempt is to pass the value as an out parameter so in the C++ code I have a parameter sDeviceEndPoint **devs instead.
My C# signature is
[DllImport("PInvokeBridge.dll", CharSet = CharSet.Unicode)]
public static extern void CallStartDiscovery(IntPtr pZbTransportObject, out IntPtr devs, ref int length, ref int result);
I have also tried IntPtr[] devs, 'ref' instead of out and they all fail in the same way. The problem is in the C# implementation
int result = 0;
IntPtr arrayValue = IntPTr.Zero;
CallStartDiscovery(_pZbTransportObject, out arrayValue, ref length, ref result);
The value of arrayValue is always null (0). So what I do after this point is not relevant. At least using a return value I get a non null value.
As far as I can tell I am doing what all others are doing. I cannot see what I am doing wrong. Otherwise this is a repeat of a question that has been 'answered' many times in this forum.