我想在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 ;
};
答案 0 :(得分:0)
无论你之前是否使用过链表,都没关系......你所拥有的只是一个结构,其中一个字段指向它是“后继者”。当然,我不能保证我想建议的解决方案无需修改即可工作;但我和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;
}
如果你想/需要调用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
类型的不同声明进行播放;有时候,为阅读或写作量身定制的声明会更容易......