在过去的几天里,我一直在努力用C#编组结构。希望有更多经验的人可以提供帮助(结构定义有所缩短,所以读数不多)。
C HBAAPI定义
HBA_STATUS HBA_GetFcpTargetMapping(
HBA_HANDLE handle,
HBA_FCPTARGETMAPPING *pmapping
);
typedef struct HBA_FCPTargetMapping {
HBA_UINT32 NumberOfEntries;
HBA_FCPSCSIENTRY entry[1]; /* Variable length array
* containing mappings */
} HBA_FCPTARGETMAPPING, *PHBA_FCPTARGETMAPPING;
typedef struct HBA_FcpScsiEntry {
HBA_SCSIID ScsiId;
} HBA_FCPSCSIENTRY, *PHBA_FCPSCSIENTRY;
typedef struct HBA_ScsiId {
char OSDeviceName[256];
HBA_UINT32 ScsiBusNumber;
} HBA_SCSIID, *PHBA_SCSIID;
我在C#中的定义是:
[DllImport("hbaapi.dll")]
static extern Uint32 HBA_GetFcpTargetMapping(
IntPtr handle,
IntPtr fcpmapping
);
[StructLayout(LayoutKind.Sequential)]
public struct HBA_FCPTARGETMAPPING
{
public Uint32_ NumberOfEntries,
public HBA_FCPSCSIENTRY SCSIEntry
}
[StructLayout(LayoutKind.Sequential)]
public struct HBA_FCPSCSIENTRY
{
public HBA_SCSIID ScsiId
}
[StructLayout(LayoutKind.Sequential)]
public struct HBA_SCSIID
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
byte[] OSDeviceName;
Uint32 ScsiBusNumber;
}
我可以获得第一个SCSIEntry,但不能获得后续的SCSIEntry。我理解这个定义是一个可变长度的数组,但是我无法弄清楚如何正确地声明它,或者将数据编组回Managed Structure。
以下作品,但显然只获得1个SCSIEntry
//Allocate only one, supposed to recall with the appropriate allocated size, using NumberOfEntries
IntPtr buffer = Marshal.AllocHglobal(Marshal.SizeOf(typeof(HBA_FCPTARGETMAPPING)));
Uint32 status = HBA_GetFcpTargetMapping(hbaHandle, buffer);
HBA_FCPTARGETMAPPING fcpTgtMapping = (HBA_FCPTARGETMAPPING)Marshal.PtrtoStructure(buffer, typeof(HBA_FCPTARGETMAPPING));
编辑 - 这看起来不错吗?我如何获得SCSIEntry数组?
[StructLayout(LayoutKind.Sequential)]
public struct HBA_FCPTARGETMAPPING
{
public UInt32 NumberOfEntries;
public IntPtr SCSIEntry; /* Variable length array containing mappings*/
}
//Alloc memory for 1 FCPTargetMapping to get the number of entries
int singleBufferSize = Marshal.SizeOf(typeof(HBA_FCPTARGETMAPPING));
IntPtr singleBuffer = Marshal.AllocHGlobal(singleBufferSize);
uint singleResult = HBA_GetFcpTargetMapping(hbaHandle, singleBuffer);
HBA_FCPTARGETMAPPING singleFCPTargetMapping = (HBA_FCPTARGETMAPPING)Marshal.PtrToStructure(singleBuffer, typeof(HBA_FCPTARGETMAPPING));
int numberOfEntries = int.Parse(singleFCPTargetMapping.NumberOfEntries.ToString());
//more memory required
if (singleResult == 7)
{
//Now get the full FCPMapping
int fullBufferSize = Marshal.SizeOf(typeof(HBA_FCPTARGETMAPPING)) + (Marshal.SizeOf(typeof(HBA_FCPSCSIENTRY)) * numberOfEntries);
IntPtr fullBuffer = Marshal.AllocHGlobal(fullBufferSize);
uint fullResult = HBA_GetFcpTargetMapping(hbaHandle, fullBuffer);
if (fullResult == 0)
{
HBA_FCPTARGETMAPPING fullFCPTargetMapping = (HBA_FCPTARGETMAPPING)Marshal.PtrToStructure(fullBuffer, typeof(HBA_FCPTARGETMAPPING));
//for (uint entryIndex = 0; entryIndex < numberOfEntries; entryIndex++)
//{
//}
}
}
答案 0 :(得分:0)
你无法让marshaller编组一个可变长度的结构。它根本无法做到这一点。这意味着您需要手动编组。
AllocHGlobal
或AllocCoTaskMem
PtrToStructure
和StructureToPtr
以及指针算法手动编组数组。 使用数组中单个元素的结构非常值得。就像你在问题中的代码中一样。您可以使用它来编组结构的主要部分,并让编组器处理布局和填充。然后使用OffsetOf
查找可变长度数组的偏移量,并按元素封送该元素。