包含结构的编组/ Pinvoking函数指针

时间:2016-08-10 08:54:51

标签: c# struct pinvoke function-pointers marshalling

我想在C#的包装类中使用这个C代码。我有一个包含各种参数的结构,包括结构和函数指针。

C代码:

struct wiringPiNodeStruct
{
  int     pinBase ;
  int     pinMax ;

  int          fd ; // Node specific
  unsigned int data0 ;  //  ditto

  void   (*pinMode)         (struct wiringPiNodeStruct *node, int pin, int mode) ;

  struct wiringPiNodeStruct *next ;
} ;

我试过编组上面的代码。但我无法找到包含结构和结构中的结构的函数指针的正确解决方案。

C#代码:

[StructLayout(LayoutKind.Sequential)]
public struct wiringPiNodeStruct
{
    public int pinBase;
    public int pinMax;

    public int fd; // Node specific
    public uint data0; //  ditto


    public delegate void pinMode (struct wiringPiNodeStruct IntPtr node, int pin, int mode) ;

    public struct wiringPiNodeStruct *next ;
};

1 个答案:

答案 0 :(得分:0)

无论你之前是否使用过链表,都没关系......你所拥有的只是一个结构,其中一个字段指向它是“后继者”。当然,我不能保证我想建议的解决方案无需修改即可工作;但我和P / Invoke的合作非常多,所以我会尝试类似的东西......至少,它会给你一个想法,希望如此。

为了简单起见(以及取出一些编组魔法),我会将pinModenext声明为IntPtr字段;请记住,IntPtr在32位和64位中具有不同的大小。确保托管和非托管部分使用相同的位数...

delegate void pinMode (IntPtr node, int pin, int mode);

[StructLayout(LayoutKind.Sequential)]
internal struct wiringPiNodeStruct
{
    public int pinBase;
    public int pinMax;
    public int fd;
    public uint data0;
    public IntPtr pinMode;
    public IntPtr next
};

您可能面临两种情况;您只需要阅读和处理结构,或者您想要创建并将其传递给非托管代码。我们来看看阅读部分;迭代列表可能看起来像......

wiringPiNodeStruct node = ...
while (node.next != IntPtr.Zero) 
{
    wiringPiNodeStruct next;
    next = (wiringPiNodeStruct) Marshal.PtrToStructure(
        node.next, 
        typeof(wiringPiNodeStruct));

    ...

    node = next;
}

如果你想/需要调用pinMode函数,你可以尝试类似的东西......

wiringPiNodeStruct node = ...
wiringPiNodeStruct next = (wiringPiNodeStruct) Marshal.PtrToStructure(
    node.next, 
    typeof(wiringPiNodeStruct));

pinMode func = (pinMode) Marshal.GetDelegateForFunctionPointer(
    next.pinMode, 
    typeof(pinMode));

func(node.next, 0, 0);

现在让我们创建一个结构;这当然是一个非常重要的例子......你可以创建一些辅助工具,可以从可枚举的数据源创建链表结构 - 并且还可以跟踪已分配的内存,并在不再需要时正确释放非托管内存。 p>

var second = new wiringPiNodeStruct { };

int size = Marshal.SizeOf(typeof(wiringPiNodeStruct));
IntPtr pSecond = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(second, pSecond, true);

pinMode func = new pinMode((ptr, pin, mode) => { });

var first = new wiringPiNodeStruct { };
first.pinMode = Marshal.GetFunctionPointerForDelegate(func);
first.next = pSecond;

如果pinMode被非托管部分用作回调,请确保func的生命周期与pinMode字段中存储的指针的生命周期相同。

您还可以使用wiringPiNodeStruct类型的不同声明进行播放;有时候,为阅读或写作量身定制的声明会更容易......