如何在C#中编组这个嵌套和指针使用的C结构

时间:2014-11-28 12:47:34

标签: pinvoke

typedef struct pt_input_bir 
{    
PT_BYTE byForm; 

    union {
    PT_BIR *pBIR; ///< Used when byForm = PT_FULLBIR_INPUT */
    PT_LONG lSlotNr; ///< Used when byForm = PT_SLOT_INPUT */
    PT_BYTE abyReserved[20]; /** For future use */
         } InputBIR;
} PT_INPUT_BIR

typedef struct pt_bir {
PT_BIR_HEADER Header; 
PT_BYTE Data[1]; 
} PT_BIR

typedef struct pt_bir_header {
PT_DWORD Length; 
PT_BYTE HeaderVersion; 
PT_BYTE Type; 
PT_WORD FormatOwner; 
PT_WORD FormatID; 
PT_CHAR Quality; 
PT_BYTE Purpose; 
PT_DWORD FactorsMask; 
} PT_BIR_HEADER

,C函数是

PT_STATUS StoreFinger (
IN PT_CONNECTION hConnection,
IN PT_INPUT_BIR *pTemplate,
OUT PT_LONG *plSlotNr
)

现在我需要在C#中为上面的C函数做包装。

我应如何编组PT_INPUT_BIR *结构,以及在返回此函数后如何解组?

请帮我解决这个问题。

/ **********************关于这个问题的更多细节****************** ******** /

  1. C结构和功能在上面定义。请参考那里。

  2. C#Struct:

  3. 对于C#struct声明,我为一个C结构提供了两个结构。 bcz one用于设置值,另一个id用于传递给c函数。

    C# app struct:
    
    [StructLayout(LayoutKind.Sequential)]//for app
        public struct FPINPUTBIR
        {
            public byte byForm;
            public InputBIRType InputBIR;       
        }
        [StructLayout(LayoutKind.Sequential)] // here when i use explicit it throws exception so i         removed it.
        public struct InputBIRType
        {
           // [FieldOffset(0)]
            public FPBIR pBIR;
            //[FieldOffset(0)]
            public int lSlotNr;
            //[FieldOffset(0)]
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] abyReserved;
        }
    
         C# wrapper struct:
    
    [StructLayout(LayoutKind.Sequential)]
        public struct FP_INPUTBIR
        {
            public byte byForm;
            public IntPtr mIPBIR;
        }
    
        [StructLayout(LayoutKind.Explicit, Size = 20, CharSet = CharSet.Ansi)]
        public struct Input_BIRType
        {
            [FieldOffset(0)]
            public IntPtr mBIR;
            [FieldOffset(0)]
            public int lSlotNr;
            //[FieldOffset(8)]
            //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            //public byte[] abyReserved;
        }
    

    最后我会在调用C fun()

    之前将C#app结构中的值复制到包装结构中

    2a)C#App Side Code是:

     //here mAppMemory is already known value
    
     FPINPUTBIR lfipdata = new FPINPUTBIR();
                FPDATA lfpdata = new FPDATA();    
    
                    lfipdata.byForm = (byte)eFPVerifyBy.FULLBIR_INPUT;
                    lfipdata.InputBIR = new InputBIRType();
                    lfipdata.InputBIR.abyReserved = new byte[20];
                    lfipdata.InputBIR.pBIR.Data = new        byte[mAppMemory[listBox2.SelectedIndex].Header.Length];
                    Array.Copy(mAppMemory[listBox2.SelectedIndex].Data, lfipdata.InputBIR.pBIR.Data, mAppMemory[listBox2.SelectedIndex].Header.Length);
                    lfipdata.InputBIR.pBIR.Header = mAppMemory[listBox2.SelectedIndex].Header;
    
                     Verify(ref lfipdata); //calling from C# APP side to C# wrapper
    

    C#包装方:

    public int Verify(ref FPINPUTBIR apStoredTemplate )
            {
               // i passed the args (apStoredTemplate ) but throws exception struct mismatch with C struct.
    
                //here i don't know what should i do. 
    
               CDLL.StoreFinger(..,ref apStoredTemplate,.. );  //pls refer the C function above
            }
    

    问题:

    1. 我真的需要两个C#结构。
    2. 我应该在C#包装函数中做什么。请记住我有两个带有差异成员的C#结构。
    3. 感谢。

1 个答案:

答案 0 :(得分:0)

您只需要对PT_BIR上一个问题中使用的内容进行一点扩展。在那里,我们将可变长度结构编组为byte[]。您可以使用相同的代码生成字节数组,但我不会重新访问它。

接下来你需要工会。那就是:

[StructLayout(LayoutKind.Explicit, Size = 20)]
public struct PT_INPUT_BIR_UNION
{
    [FieldOffset(0)]
    public IntPtr pBIR; 
    [FieldOffset(0)]
    public int lSlotNr; // I'm guessing what PT_LONG is
}

无需声明联盟的保留部分。尺寸照顾到这一点。

然后PT_INPUT_BIR

[StructLayout(LayoutKind.Sequential)]
public struct PT_INPUT_BIR
{
    Byte byForm;
    PT_INPUT_BIR_UNION InputBirUnion;
}

然后,您需要使用GCHandle来固定PT_BIR字节数组。让我们保持与该问题相同的命名,并假设PT_BIR保存在名为byte[]的{​​{1}}变量中。

data

当您声明GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { PT_INPUT_BIR inputBir; inputBir.byForm := ...; inputBir.InputBirUnion.pBIR = handle.AddrOfPinnedObject(); // now call StoreFinger passing ref inputBir } finally { handle.Free(); } 时,StoreFinger参数应声明为PT_BIR*