C# 具有可变长度结构数组的PInvoke/编组
在过去的几天里,我一直在努力用C#来组织一个结构。希望有更多经验的人能帮上忙(结构定义被缩短了一点,所以没有那么多阅读) HBAAPI定义C# 具有可变长度结构数组的PInvoke/编组,c#,pinvoke,marshalling,C#,Pinvoke,Marshalling,在过去的几天里,我一直在努力用C#来组织一个结构。希望有更多经验的人能帮上忙(结构定义被缩短了一点,所以没有那么多阅读) HBAAPI定义 HBA_STATUS HBA_GetFcpTargetMapping( HBA_HANDLE handle, HBA_FCPTARGETMAPPING *pmapping ); typedef struct HBA_FCPTargetMapping { HBA_UINT32 NumberOfEntries;
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#中的定义是:
我可以得到第一个SCSIEntry,但不能得到后续的SCSIEntry。我知道该定义是一个可变长度数组,但我不知道如何正确声明它,或将数据封送回托管结构
下面的方法有效,但显然只获得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++)
//{
//}
}
}
[StructLayout(LayoutKind.Sequential)]
公共结构HBA_FCPTARGETMAPPING
{
公共UInt32个条目;
public IntPtr SCSIEntry;/*包含映射的可变长度数组*/
}
//为1 FCPTargetMapping分配内存以获取条目数
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());
//需要更多内存
if(singleResult==7)
{
//现在获取完整的FCP映射
int fullBufferSize=Marshal.SizeOf(typeof(HBA_FCPTARGETMAPPING))+(Marshal.SizeOf(typeof(HBA_fcpscsicentry))*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));
//对于(uint entryIndex=0;entryIndex
您无法让封送器封送可变长度结构。它根本无法做到这一点。这意味着您需要手动封送它
AllocHGlobal
或AllocTaskMem
分配结构PtrToStructure
和StructureToPtr
和指针算法手动封送数组李>
拥有一个带有单个数组元素的结构是非常值得的。正如你在问题代码中所说的那样。您可以使用它来封送结构的主要部分,并让封送器处理布局和填充。然后使用
OffsetOf
查找可变长度数组的偏移量,并逐个元素封送该元素 变更来源:分录[1];收件人:条目[];。您有一个指针数组,指针的数量由变量NumberOfEntries决定。分配的大小为sizeOf(Uint32)+sizeOf(NumberOfEntries*sizeOf(HBA_FCPSCSIENTRY)。第一个条目是指向数组的指针加上Uint32的偏移量。然后获取下一个条目add sizeOf HBA_FCPSCSIENTRY)。SCSIEntry成员应键入HBA_FCPSCSIENTRY。它不是指针。这是一个内联数组。
[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++)
//{
//}
}
}