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

C# 包含结构的编组/Pinvoking函数指针,c#,struct,pinvoke,function-pointers,marshalling,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, i

我想在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 ;
} ;
[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 ;
};
我试着整理上面的代码。但是我无法为包含结构和结构中的结构的函数指针找到合适的解决方案

C#代码:


不管你以前是否使用过链表,这都无关紧要。。。这里的结构有一个字段指向它的“继任者”。当然,我不能保证我想建议的解决方案不经修改就能奏效;但是我已经使用了很多P/Invoke,所以我会尝试这样的方法。。。至少,它会给你一个想法,希望如此

为了简单起见(并使用一些编组魔法),我将
pinMode
next
声明为
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;
}
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);
如果您想/需要调用
pinMode
函数,您可以尝试类似的方法

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

    ...

    node = next;
}
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);
现在让我们创建一个结构;这当然是一个非常简单的例子。。。您可以创建一些助手实用程序,这些实用程序可以从可枚举数据源创建链表结构,还可以跟踪分配的内存,并在不再需要时正确释放非托管内存

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
类型的不同声明进行播放;有时更容易拥有为阅读或写作而定制的声明…

无论您以前是否使用过链表,这都无关紧要。。。这里的结构有一个字段指向它的“继任者”。当然,我不能保证我想建议的解决方案不经修改就能奏效;但是我已经使用了很多P/Invoke,所以我会尝试这样的方法。。。至少,它会给你一个想法,希望如此

为了简单起见(并使用一些编组魔法),我将
pinMode
next
声明为
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;
}
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);
如果您想/需要调用
pinMode
函数,您可以尝试类似的方法

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

    ...

    node = next;
}
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);
现在让我们创建一个结构;这当然是一个非常简单的例子。。。您可以创建一些助手实用程序,这些实用程序可以从可枚举数据源创建链表结构,还可以跟踪分配的内存,并在不再需要时正确释放非托管内存

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
类型的不同声明进行播放;有时,为阅读或书写而定制的声明更容易…

链表很棘手。在p/invoke中将是一个痛苦的世界。当然,我们完全不知道你的问题是什么。您正在从管理者编组到非管理者编组,或者以另一种方式编组。您不知道如何从托管代码填充此链表。或者,您不知道如何遍历这样一个在非托管代码中填充的列表。实际上,您会发现从C++/CLI执行此操作要容易得多。现在,我有个问题要问你。请不要忽视这个问题。你曾经在C或C++中用过链接列表吗?我这样问是因为如果你没有那么你就没有希望了。走路之前不要跑。我对C#很陌生。管理和编组这两个术语也是新的。我正在C#中为使用此结构的功能创建一个包装器类。我想在C#中使用上述结构。i、 我想在.net端重新创建结构,然后让编组处理在.net和c之间转换内存。不,我没有编写LinkedList,这将是相当艰巨的。我怀疑,考虑到你的经验水平,尝试这种先进的东西是不会有成效的。如果我是你的主管,我建议你写一些C++的例子代码来获得这个库的感觉,以及如何处理链接列表。如果你以前从未见过链表,那么链表是相当棘手的。在我看来,试图在p/invoke的复杂阻碍下学习它们是毫无成效的。这样做会浪费大量的时间。但是有没有一种方法可以让我在C#中重新创建一个类(类似于C中的结构)并映射它们?行得通吗?当然行。但这并不容易。如果你没有使用链表的经验,情况就更糟了。我在这里想说的都说了。接受我的建议,或者不要。由你决定。链表很棘手。在p/invoke中将是一个痛苦的世界。当然,我们完全不知道你的问题是什么。您正在从管理者编组到非管理者编组,或者以另一种方式编组。您不知道如何从托管代码填充此链表。或者,您不知道如何遍历这样一个在非托管代码中填充的列表。实际上,您会发现从C++/CLI执行此操作要容易得多