首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >C# P/Invoke和包含字节数组的结构数组

C# P/Invoke和包含字节数组的结构数组
EN

Stack Overflow用户
提问于 2013-04-24 23:15:53
回答 3查看 1.8K关注 0票数 0

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

c++头文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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#声明:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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客户机中,我发现参数不仅仅是一个缓冲区,而是一个缓冲区数组。在C#中,它看起来如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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方法确实有一个指向缓冲区结构( Buffer *)的指针,而不是一个指向缓冲区数组(Buffer[]*)的指针。如何在C#中定义结构和extern方法的参数类型?

任何帮助都很感谢,谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-24 23:34:35

首先,您的结构以错误的顺序获得参数。需要将字节数组声明为IntPtr,并手动编组:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct Buffer
{
    public IntPtr Data;
    public uint Length;
}

p/invoke应是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[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,这样结构才是可闪烁的。这是必需的,这样数组参数就可以声明为Buffer[]

做字节数组的编组工作会有点痛苦。您将希望使用GCHandle来插入托管字节数组,并调用AddrOfPinnedObject()来获取结构数组中每个结构的固定数组的地址。编写一些帮助函数以减轻任务的痛苦是值得的。

票数 2
EN

Stack Overflow用户

发布于 2013-04-24 23:28:49

c#中的方法签名应该如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[DllImport("MyNativeDll.dll")]
public static extern RES SendReceive (uint32 deviceIndex, ref Buffer pReq, ref Buffer pResp, ref uint pReceivedLen, ref uint pStatus);

请参阅此项目,将来您可能会从.net http://clrinterop.codeplex.com/releases/view/14120生成本机调用。

票数 0
EN

Stack Overflow用户

发布于 2013-04-24 23:52:20

基于C++头,但不进行测试,请查看以下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace WindowsFormsApplication1
{
    public class Class1
    {
        public struct Buffer
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public StringBuilder pData;

            public uint length;
        }

        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        static extern int LoadLibrary(string lpLibFileName);

        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
        static extern IntPtr GetProcAddress(int hModule, string lpProcName);

        [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
        static extern bool FreeLibrary(int hModule);

        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        internal delegate IntPtr SendReceive(
            uint deviceIndex,
            ref Buffer pReq,
            ref Buffer pResp,
            uint pReceivedLen,
            uint pStatus);

        public void ExecuteExternalDllFunction()
        {
            int dll = 0;

            try
            {
                dll = LoadLibrary(@"somemodule.dll");
                IntPtr address = GetProcAddress(dll, "SendReceive");

                uint deviceIndex = 0;
                Buffer pReq = new Buffer() { length = 0, pData = new StringBuilder() };
                Buffer pResp = new Buffer() { length = 0, pData = new StringBuilder() };
                uint pReceivedLen = 0;
                uint pStatus = 0;

                if (address != IntPtr.Zero)
                {
                    SendReceive sendReceive = (SendReceive)Marshal.GetDelegateForFunctionPointer(address, typeof(SendReceive));

                    IntPtr ret = sendReceive(deviceIndex, ref pReq, ref pResp, pReceivedLen, pStatus);
                }
            }
            catch (Exception Ex)
            {
                //handle exception...
            }
            finally
            {
                if (dll > 0)
                {
                    FreeLibrary(dll);
                }
            }
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16208592

复制
相关文章
C# 字节数组截取
C# 字节数组截取 如: byte[] bt = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 方法一 截取位数规则 1)截取2位长度的字节数组 用BitConverter.ToInt16 例如,从第2位开始截取2个字节则 BitConverter.ToInt16(bt,2);
全栈程序员站长
2022/08/12
3.5K0
[C#]结构体和字节数组的相互转化
public static class StructCopyer { // 相当于序列化与反序列化,但是不用借助外部文件 //1、struct转换为Byte[] public static Byte[] StructToBytes(Object structure) { Int32 size = Marshal.SizeOf(structure); IntPtr buffe
静默虚空
2022/05/07
8030
C#中的多维数组和交错数组
C#中有多维数组和交错数组,两者有什么区别呢! 直白些,多维数组每一行都是固定的,交错数组的每一行可以有不同的大小。 以二维的举例,二维数组就是m×n的矩阵,m行n列;而交错数组(又叫锯齿数组
卡尔曼和玻尔兹曼谁曼
2019/01/22
2.9K0
C#中的多维数组和交错数组
C#数组
这样就声明了一个数组(声明数组,而非定义)。接着就该给声明好的数组分配内存了,由于C#里数组是引用类型,因此应当使用new运算符来分配内存,这个时候应当指出数组含有的元素个数。
zy010101
2019/05/25
6810
封装数组之包含、搜索和删除元素
前言:在上一小节中我们已经会了如何获取和如何修改数组中的元素,在本小节中我们将继续学习如何判断某个元素是否在数组中存在、查询出某个元素在数组中的位置、以及删除数组中元素等方法的编写。
wfaceboss
2019/04/08
7890
C++结构体数组 | 结构体数组的使用
C++结构体数组与以前介绍过的数值型数组的不同之处在于:每个数组元素都是一个结构体类 型的数据,它们都分别包括各个成员项。
小林C语言
2020/12/30
4.6K0
C++结构体数组 | 结构体数组的使用
连续存储数组的算法(包含数组倒置、冒泡排序……)
线性结构【把所有的结点用一根直线穿起来】   连续存储【数组】、离散存储【链表】(不连续的,可分隔开来) 4 #include<stdio.h> 5 #include<malloc.h>//包含malloc函数 6 #include<stdlib.h>//包含exit函数 7 //定义了一个(复合)数据类型,名字叫struct Arr,该数据类型有三个成员: 8 struct Arr{ 9 int * pBase; //存储的是数组第一个元素的地址 10 int l
孙晨c
2019/09/10
8200
java字符串的字节数组_Java字节数组到字符串到字节数组
我正在尝试将byte []转换为字符串,将byte []的字符串表示形式转换为byte []的转换...我将byte []转换为要发送的字符串,然后我期望我的Web服务(用python编写)将数据直接回显给客户端。
用户7886150
2021/04/29
5.2K0
数据结构:数组和链表的区别(数组和链表的优缺点 & 数组和链表的适用场景)
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/147966.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/07
2.6K0
js 实现扁平数组转为树形结构数组及树形结构数组转为扁平数组
转载请注明出处:https://www.cnblogs.com/beileixinqing/p/16666662.html
蓓蕾心晴
2022/09/24
1.9K0
数组(ArrayPool数组池、Span<T>结构)
  如果需要使用相同的类型的多个对象,就可以使用集合和数组,这一节主要讲解数组,其中会重点涉及到Span<T>结构和ArrayPool数组池。我们也会先涉及到简单的数组、多维数组、锯齿数组、Array类。
小世界的野孩子
2019/07/30
1.5K0
数组(ArrayPool数组池、Span<T>结构)
js判断数组中是否包含某个指定元素的个数_js 数组包含某个元素
indexOf()完整语法: array.indexOf(item,start)
全栈程序员站长
2022/11/02
11.3K0
invoke和begininvoke 区别——c#
      https://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html
vv彭
2020/12/16
2.7K0
invoke和begininvoke 区别——c#
8.2 结构体数组和指针
指向结构体对象的指针变量既可以指向结构体变量,也可指向结构体数组中的元素。指针变量的基类型必须与结构体变量的类型相同
小林C语言
2019/08/09
9330
其他流---字节流数组
字节流数组读入 建立字节流读取,参数为字节数组读入流 InputStream bi = new BufferedInputStream(new ByteArrayInputStream(c)); 建立读取字节数组,数组长度变量len int len = 0; byte[] flush = new byte[1024]; 读取到需要操作的变量 String s = ""; while (-1 != (len = bi.read(flush))) { s += new String(flush,
shimeath
2020/07/30
6450
c#数组赋初值_C#数组初始化
C#的数组初始化是在声明数组时将初始值放在大括号({})之内。如果没有指定初始值,则数组成员将自动初始化为该数组类型的默认初始值。请阅读数组的属性。如果将数组声明为某类型的字段,则当实例化该类型时它将被设置为默认值null。
全栈程序员站长
2022/09/09
1.6K0
C# 数组(Array)
初始化数组: 声明一个数组不会在内存中初始化数组。当初始化数组变量时,您可以赋值给数组。 数组是一个引用类型,所以您需要使用 new 关键字来创建数组的实例。 例如:
acc8226
2022/05/17
1.1K0
C# 数组基础
一、数组的基础知识 1、数组有什么用? 如果需要同一个类型的多个对象,就可以使用数组。数组是一种数组结构,它可以包含同一个类型的多个元素. 2、数组的初始化方式 第一种:先声明后赋值 int[] ar
郑小超.
2018/01/26
1.2K0
C#中数组、ArrayList和List的区别
在C#中,数组、ArrayList、List都能够存储一组对象,那么他们的区别是什么呢?
Karl Du
2023/10/20
3070
C#字符串、字节数组和内存流间的相互转换
定义string变量为str,内存流变量为ms,比特数组为bt 1.字符串=>比特数组 (1)byte[] bt=System.Text.Encoding.Default.GetBytes("字符串"); (2)byte[] bt=Convert.FromBase64String("字符串"); 补充: System.Text.Encoding.Unicode.GetBytes(str); System.Text.Encoding.UTF8.GetBytes(str); System.Text.Encod
跟着阿笨一起玩NET
2018/09/20
2K0

相似问题

C# P/Invoke封送变长结构数组

19

C#如何在结构中使用结构数组进行P/Invoke?

15

C# P/Invoke:包含函数指针的编组结构

32

C# P/Invoke结构问题

42

C# P/invoke结构对齐

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文