C#P/Invoke和包含字节数组的结构数组 [英] C# P/Invoke and array of structs containing byte arrays

查看:91
本文介绍了C#P/Invoke和包含字节数组的结构数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从C#代码调用本机DLL.因为我对C/C ++不太熟悉,所以我无法弄清楚应该如何在C#中声明C中定义的结构以便可以调用它.问题在于,两个参数似乎是一个结构数组,我不知道如何在C#中声明它(请参见最后一个代码块):

I need to invoke a native DLL from C# code. As I am not very familiar with C/C++, I can't figure out how a structure defined in C should be declared in C# so it can be invoked. The problem is that two parameters seems to be an array of structs, which I don't know how to declare this in C# (see last code block):

c ++头文件:

typedef enum
{   
    OK = 0,
    //others
} RES

typedef struct
{
    unsigned char* pData;
    unsigned int length;
} Buffer;

RES SendReceive(uint32 deviceIndex
    Buffer* pReq,
    Buffer* pResp,
    unsigned int* pReceivedLen,
    unsigned int* pStatus);

c#声明:

enum
{   
    OK = 0,
    //others
} RES

struct Buffer
{
    public uint Length;
    public ??? Data; // <-- I guess it's byte[]
}

[DllImport("somemodule.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint SendReceive(
    uint hsmIndex,
    uint originatorId,
    ushort fmNumber,
    ??? pReq,  // <-- should this be ref Buffer[] ?
    uint reserved,
    ??? pResp, // <-- should this be ref Buffer[] ?
    ref uint pReceivedLen,
    ref uint pFmStatus);

在等效的Java客户端中,我发现参数不仅是一个Buffer,而且是一个Buffers数组.在C#中看起来像这样:

in an equivalent java client, i found that the parameter is not just one Buffer but an array of Buffers. In C# it would look like this:

 var pReq = new Buffer[] 
{
    new Buffer { Data = new byte[] { 1, 0 }, Length = (uint)2 }, 
    new Buffer {Data = requestStream.ToArray(), Length = (uint)requestStream.ToArray().Length },
    //according to the header file, the last item must be {NULL, 0}
    new Buffer { Data = null, Length = 0 }
};

var pResp = new Buffer[] 
{
    new Buffer { Data = new byte[0x1000], Length = 0x1000 }, 
    //according to the header file, the last item must be {NULL, 0}
    new Buffer { Data = null, Length = 0x0 }
};

这对我来说很奇怪,因为extern C方法确实有一个指向Buffer结构的指针(Buffer *),而不是指向Buffer数组的指针(Buffer [] *). 我该如何在C#中定义Struct和extern方法的参数类型?

This seems strange to me because the extern C method does have a pointer to a Buffer struct (Buffer*) and not a pointer to a Buffer array (Buffer[]*). How do I need to define the Struct in C# and the parameter types of the extern method?

感谢任何帮助,谢谢.

推荐答案

首先,您的结构具有错误顺序的参数.并需要通过手动编组将字节数组声明为IntPtr:

Firstly your struct has the parameters in the wrong order. And the byte array needs to be declared as IntPtr with manual marshalling:

struct Buffer
{
    public IntPtr Data;
    public uint Length;
}

p/调用应为:

[DllImport("MyNativeDll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern RES SendReceive(
    uint deviceIndex, 
    [In] Buffer[] pReq, 
    [In, Out] Buffer[] pResp, 
    out uint pReceivedLen, 
    out uint pStatus
);

字节数组必须为IntPtr,以便该结构可被Blittable使用.这是必需的,以便可以将数组参数声明为Buffer[].

The byte array needs to be IntPtr so that the struct is blittable. And that's needed so that the array parameters can be declared as Buffer[].

将字节数组编组起来会有些痛苦.您将要使用GCHandle固定托管字节数组,并调用AddrOfPinnedObject()获取结构数组中每个结构的固定数组的地址.编写一些辅助函数以减轻任务负担是值得的.

It's going to be a bit of a pain doing the marshalling of the byte arrays. You'll want to use GCHandle to pin the managed byte arrays, and call AddrOfPinnedObject() to get the address of the pinned array for each struct in your arrays of structs. It will be worth your while writing some helper functions to make that task less painful.

这篇关于C#P/Invoke和包含字节数组的结构数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆