在C#中调用C++动态库导出的函数时,有时候需要封送一些复杂的数据结构,这时候不确定自己封送的数据的内存布局对不对,就想要弄个简单的C++项目模拟一下被调用的接口,检查一下C#的数据封送是否正确。

因为对C++项目基本上没任何了解,捣鼓了半天才搞定,所以这里简单记录一下过程,以加深记忆。

1. 首先用C++的动态链接库模板创建一个项目。然后在dllmain.cpp中定义一个名为PostMsg的C导出函数,该函数接收MsgData结构体并打印,代码如下:

typedef struct MsgData
{
int index;
char msg[32];
BYTE data[8];
} MsgData; static void dumpData(const MsgData* msg)
{
for (size_t i = 0; i < sizeof(msg->data); i++)
{
printf("%02x ", *(msg->data + i));
if ((i + 1) % 8 == 0)
{
printf("\n");
}
}
} extern "C"
__declspec(dllexport) void PostMsg(MsgData* msg)
{
printf("index=%d\nmsg=\"%s\"\n", msg->index, msg->msg);
dumpData(msg);
}

2. 然后创建一个C#的控制台程序来调用它。这里通过DllImport特性来导入C++项目的PostMsg函数,同样也定义了对应的MsgData结构体,代码如下:

var msg = new Msg.MsgData()
{
Index = 2025,
Msg = "custom msg",
Data = [1,2,3,4,5,6,7,8]
};
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf<Msg.MsgData>());
Marshal.StructureToPtr(msg, ptr, false);
Msg.PostMsg(ptr); internal class Msg
{
[DllImport("TestDll.dll", EntryPoint = "PostMsg")]
public static extern void PostMsg(IntPtr msg); [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct MsgData
{
public int Index;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst = 32)]
public string Msg;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Data;
}
}

3. 接着将C++项目添加为C#项目的项目引用。

这里存在一个问题,C#项目不支持添加C++的项目引用,所以这里标了黄色感叹号,虽然构建C#项目的时候会先构建C++项目,但不会自动把C++项目的输出拷贝到C#项目的输出目录。

网上有很多方法能够解决把C++输出拷贝到C#输出目录的问题,我这里采用添加项目文件的方式,在C#的项目文件里添加以下内容:

  <ItemGroup>
<None Include="../x64/$(Configuration)/*.dll;../x64/$(Configuration)/*.pdb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

4. 最后看一下结果:

index=2025
msg="custom msg"
01 02 03 04 05 06 07 08

结果正常,这样就可以简单验证一下自己往C函数里封送的数据是不是正确了

简单写一个C函数供C#代码调用的更多相关文章

  1. 请写一个php函数,可以接受任意数量的参数

    请写一个php函数,可以接受任意数量的参数 这是一道面试题.怎么写这个函数呢? function fun(......) { } ----------------------------------- ...

  2. 自己写一个strcmp函数(C++)

    题目说明: 写一个函数,实现两个字符串的比较.即自己写一个strcmp函数,函数原型为int strcmp( char * p1, char * p2); 设p1指向字符串s1,p2指向字符串s2.要 ...

  3. 写一个PHP函数,实现扫描并打印出指定目录下(含子目录)的所有jpg文件名

    写一个PHP函数,实现扫描并打印出指定目录下(含子目录)的所有jpg文件名 <?php $dir = "E:\照片\\";//打印文件夹中所有jpg文件 function p ...

  4. 034-PHP简单定义一个匿名函数

    <?php /* 简单定义一个匿名函数 */ # 把匿名函数赋值给一个变量,也叫临时函数 $demo = function ($txt) { echo $txt; }; # 调用测试下 $dem ...

  5. 五:用JAVA写一个阿里云VPC Open API调用程序

    用JAVA写一个阿里云VPC Open API调用程序 摘要:用JAVA拼出来Open API的URL 引言 VPC提供了丰富的API接口,让网络工程是可以通过API调用的方式管理网络资源.用程序和软 ...

  6. 一个实现单线程/多线程下代码调用链中传递数据的处理类: CallContext(LogicalSetData,LogicalGetData),含.net core的实现

    详情请参考原文:一个实现单线程/多线程下代码调用链中传递数据的处理类: CallContext

  7. 依据ECMA规范,手写一个bind函数

    Function.prototype.bind 函数,参见ECMA规范地址 如题,这次来实现一个boundFunction函数,不挂载在Function.prototype上,而是一个单独声明的函数. ...

  8. 写一个umi插件 自动生成代码 解放cv的双手

    引言 最近在写一个中台项目,使用的react的umi框架. 各种增删改查.基本是列表页 新建页 详情页这种页面 为了避免不必要的简单重复(主要是想偷懒) 于是想去实现自己的一个代码生成器 探索 首先, ...

  9. 为LoadRunner写一个lr_save_float函数

    LoadRunner中有lr_save_int() 和lr_save_string() 函数,但是没有保存浮点数到变量的lr_save_float函数.<lr_save_float() func ...

  10. JavaScript 自己写一个 replaceAll() 函数

    JavaScript 的  replace()  方法可以在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. 但是,只输入字符串的话,仅替换第一个字符,当然也可以用正则表达式来进行 ...

随机推荐

  1. 史上最全EffectiveJava总结(二)

    方法 49.检查参数的有效性 每次编写方法或构造函数时,都应该考虑参数存在哪些限制,并在文档中记录下来,然后在方法的开头显式地检查. 如果没有在方法开头就验证参数,可能会违反故障原子性.因为方法可能会 ...

  2. 标准javabean

    1.javabean介绍 javabean,名为实体类,封装数据的类 前面我们写的类都是实体类,但我们写的不是标准的实体类 . 2.标准的javabean写法 如图 3.快捷键 一个成员变量就要写两个 ...

  3. Linux下more命令高级用法

    我们在 Linux 环境下工作时,每天肯定会跟各种各样的文本文件打交道.这些文件,有时候会非常长,无法在一屏的空间内显示完全.所以,在查看这种文件时,我们需要分页显示.这时,我们就可以使用 more ...

  4. 从DeepSeek看算法备案&大模型备案

    一.deepseek的备案情况 (一)算法备案情况 在算法备案系统网站上,北京深度求索人工智能基础技术研究有限公司和杭州深度求索人工智能基础技术研究有限公司分别进行了两个算法备案.从公司名称来看,正如 ...

  5. 一文带你深度剖析什么叫Transformer

    Transformer概述 Transformer是基于自注意机制(self-attention)的神经网络模型.其经常用于来处理时序数据.我们知道还有另外的常用的两类深度神经网络模型循环神经网络(R ...

  6. dubbo源码解析-服务暴露与发现

    一.概述 dubbo是一个简单易用的RPC框架,通过简单的提供者,消费者配置就能完成无感的网络调用.那么在dubbo中是如何将提供者的服务暴露出去,消费者又是如何获取到提供者相关信息的呢? 二.dub ...

  7. git版本管理库运用

    一.git 删除本地创建的仓库连接 //删除文件夹下的所有 .git 文件 find . -name ".git" | xargs rm -Rf 二.git命令:全局设置用户名邮箱 ...

  8. 加减法计算在RB中的应用(比如计算库存)(should be equal as integers指令的使用)

    订单测试过程中,对库存的校验是很关键的步骤 下面这个案例即实现对订单前后库存检查.公式计算.结果匹配,输出测试结果.具体脚本如下图 步骤如下: 1.获取订单前的库存 2.订单流程 3.获取订单后的库存 ...

  9. sonarqube+gitlab+jenkins+maven集成搭建(四)

    安装Gitlab 关闭firewalld防火墙和selinux防火墙,如图1-2:[root@localhost ~]# systemctl stop firewalld[root@localhost ...

  10. Java编程--可变参数、foreach循环

    /** * 可变参数与foreach循环 * 可变参数:方法可以接受任意多个参数 * 方法格式(参数类型...变量) * 使用方法传入的该变量时当作数组对待 * foreach循环:快速对数组进行操作 ...