C# 具有可变长度结构数组的PInvoke/编组

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;

在过去的几天里,我一直在努力用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#中的定义是:

我可以得到第一个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++)
            //{
    
             //}
        }
    }