構造体の配列を渡すことはできませんが、1 つを渡すことはできます。
このサイトで、正しいと示されているいくつかの回答を見てきました。しかし、それらのどれも私のために働きません。答えが PInvoke 署名の「out IntPtr someName」として IntPtr を持っているすべての場合で、私が常に取得する値はゼロです。IntPtr が戻り値の場合、構造体ポインターの配列として解決できません。
IntPtr を戻りコードとして使用した私の試みは次のとおりです。 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 署名:
[DllImport("PInvokeBridge.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr CallStartDiscovery(IntPtr pZbTransportObject, ref int length, ref int result);
C# 実装
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;
}
}
C# で定義された DeviceEndPoint 構造体のレイアウトが正しいことはわかっています。これは、DeviceEndPoint 構造体へのポインターを 1 つだけ渡すように C++ コードを変更すると、その単一の構造体がコレクションに正しく読み込まれるためです。
もう 1 つの試みは、値を out パラメータとして渡すことです。そのため、C++ コードでは代わりにパラメータ sDeviceEndPoint **devs を使用しています。
私のC#署名は
[DllImport("PInvokeBridge.dll", CharSet = CharSet.Unicode)]
public static extern void CallStartDiscovery(IntPtr pZbTransportObject, out IntPtr devs, ref int length, ref int result);
また、IntPtr[] devs、out の代わりに 'ref' を試しましたが、それらはすべて同じ方法で失敗します。問題は C# の実装にあります
int result = 0;
IntPtr arrayValue = IntPTr.Zero;
CallStartDiscovery(_pZbTransportObject, out arrayValue, ref length, ref result);
arrayValue の値は常に null (0) です。したがって、この時点以降に行うことは関係ありません。少なくとも戻り値を使用すると、null 以外の値が得られます。
私が言うことができる限り、私は他のすべての人がしていることをやっています. 私は自分が間違っていることを見ることができません。それ以外の場合、これはこのフォーラムで何度も「回答」された質問の繰り返しです。