C# Pinvoke-使用指针参数调用函数

C# Pinvoke-使用指针参数调用函数,c#,pointers,struct,pinvoke,union,C#,Pointers,Struct,Pinvoke,Union,我在C中有一个函数,其签名如下: int addPos(int init_array_size, int *cnt, int *array_size, PosT ***posArray, char *infoMsg); 下面是PosT的外观: typedef union pu { struct dpos d; struct epo e; struct bpos

我在C中有一个函数,其签名如下:

int addPos(int init_array_size, 
           int *cnt, 
           int *array_size, 
           PosT ***posArray, 
           char *infoMsg);
下面是PosT的外观:

typedef union pu
{
    struct  dpos   d;
    struct  epo    e;
    struct  bpos   b;
    struct  spos   c;
} PosT ;

在C#中通过p/Invoke调用此方法的最佳方式是什么?我需要用C#定义一个类来表示PosT吗?如何将PosT***posArray参数从C#传递到C?

您已经描述了PosT的外观,但这还不够。首先,必须知道函数希望作为***Posits传递什么,然后才可以考虑从C++或C端调用它。 我知道这可能不符合你的愿望,但请看:

PosT p;
PosT* ptr = &p;
PosT** ptr2 = &ptr;
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!?


PosT* ptr = new PosT[123];
PosT** ptr2 = &ptr;
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!?


PosT** ptr2 = new PosT[5];
for(int i=0;i<5;++i) ptr2[i] = new PosT[123];
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!??
调用类似于:

func(...., new PosT[][] { 
         new PosT[] { new PosT{ d = ... }, new PosT{ d = ... }, ... },
         new PosT[] { new PosT{ d = ... }, new PosT{ d = ... }, ... },
         ... },
    .... );
但是,请先检查此函数的期望值。有了*真的有太多的可能性去猜测。你说它来自于某个API——首先检查它的文档!告诉我们这个函数到底需要什么,我/有人会告诉你如何在C#中构建这样的POD。相反,它不会起作用!:)

顺便说一句,很抱歉C++/C#代码太糟糕了,我很忙,只有几分钟的时间来写这篇文章:/

问题#1我需要在CSharp中定义一个代表PosT的类吗?
您应该在c#中将PosT定义为结构。由于这是一个联合结构,您需要应用StructLayout属性,并完全定义其他结构。它可能看起来像这样:

struct  dpos { };
struct  epo  { };
struct  bpos { };
struct  spos { };
[System.Runtime.InteropServices.StructLayout(
    System.Runtime.InteropServices.LayoutKind.Explicit, Size=99)]
struct PosT {
    [System.Runtime.InteropServices.FieldOffset(0)] dpos   d;
    [System.Runtime.InteropServices.FieldOffset(0)] epo    e;
    [System.Runtime.InteropServices.FieldOffset(0)] bpos   b;
    [System.Runtime.InteropServices.FieldOffset(0)] spos   c;
    };
**请注意,“Size=99”是不正确的。理想情况下,应该将此大小设置为最大封闭结构使用的字节数。

问题#2-如何通过frm CSharp将PosT***posArray参数传递给C?
在做这类事情时必须非常小心,特别是如果希望在C#下为posArray分配内存的话。您不希望向C传递.NET GC将要移动/更改的缓冲区。如果C返回缓冲区,您应该可以(但是如果没有C函数允许您释放内存,您将泄漏内存)。 你应该看看,www.pinvoke.net可能有一些例子。如果要将posArray缓冲区从C#发送到C,则必须求助于不安全的上下文(见下文)。我不确定如何处理该级别或重定向。您的cnt和数组大小可以使用'ref'关键字处理。

问题#3-如何指定所有数据的封送处理?
看看上面的链接,特别是数组的默认封送处理。您可能还需要处理一些测试代码,在调用后中断,并使用即时窗口来研究结构


记住

如果您使用“不安全”开关编译c#,则几乎可以直接执行(类似c的)调用。例如:

unsafe public MainWindow() {
    InitializeComponent();
    int abc = 4;
    int* abcPtr = &abc;
    *abcPtr = 8;

    fixed (PosT* gog = new PosT[30]) {
        PosT* gogPtr = (gog + 1);
        }
    }
你必须非常小心,因为C#管理着自己的内存,可以在你身上移动东西(见上面的“修复”)。我不推荐这个,但它对快速和肮脏的事情很有用

另外,如果API是在tlb(表库)中定义的,VisualStudio通常会提供通过存根dll为您创建绑定的功能(请参阅tlbimp命令)



希望有人能提供更具体的回应,但我认为这些信息至少可以让你开始前进

我知道这对回答这个问题没有帮助,但为什么C函数声明有这么多参数呢?这可以很容易地用一个简单的结构来包装。我相信这里的答案中有一些用于编组结构的示例代码:
hPtr
参数到底是什么。仅仅知道它的类型是不够的。卷起一张漂亮的胖报纸。我推荐《纽约时报》周日版。去找写那段代码的程序员,用纸狠狠地揍他一顿。当你试图让这个怪物继续运行时,这应该会让你保持一段时间的灵感。原始的post Eddite现在,参数更少,这是一个我需要调用的API,所以我不得不接受它。你需要回答我提出的问题,这是
quetzalcatl
详细阐述的。在你这么做之前,没有人能帮助你。谢谢quetza,我很感激,在我的C程序中,我这样称呼它:变量声明:PosT**posArray=NULL;对于调用:Addpos(…,&posArray,…)和Addpos()将为它分配内存,填充它并返回它。然后我有另一个做释放的函数。嗨,Quetzalcatl,我在这里添加了一个更清晰更详细的问题版本:谢谢你的帮助。
unsafe public MainWindow() {
    InitializeComponent();
    int abc = 4;
    int* abcPtr = &abc;
    *abcPtr = 8;

    fixed (PosT* gog = new PosT[30]) {
        PosT* gogPtr = (gog + 1);
        }
    }