文章目录
前言
- 视频资源:B站:C#与C/C++动态链接库
- 本篇对C#与C/C++动态链接库做一个小结。
一、基础知识
1. 结构体对齐
1. 内存对齐
- 定义: 计算机系统对基本数据类型合法地址做出一些限制,要求某些类型地址必须是某个值K的倍数;
- 目的: 简化处理器喝存储器系统之间的接口硬件设计,方便存储器操作读取或写入;
- 规则:
- 结构体的数据成员,第一个成员的偏移量为0,后面每个数据成员存储的起始位置要从自己大小的整数倍开始;
- 子结构体中的第一个成员偏移量应当是子结构体中最大成员的整数倍;
- 结构体总大小必须是其内部最大成员的整数倍。
#include <iostream>
#define FIELDOFFSET(TYPE,MEMBER)(int)(&(((TYPE*)0)->MEMBER))
//定义判断字符的字节方法
#pragma pack(push) //入栈 (先进后出)
#pragma pack(1) //设置字节对齐方式,1字节对齐(一个接一个,紧挨着)
struct Info
{
char username[10]; //24-34
double userdata; //40-48(8的倍数)
};
#pragma pack(pop) //出栈
struct Frame
{
//字节:
unsigned char id; //0-1
int width; //4-8
long long height; //8-16
unsigned char* data; //16-20
Info info; //24-
};
int main()
{
int len = sizeof(Frame);//result:48
int len2 = sizeof(Info);//result:24; 设置出入栈后字节为18
int offset_width = FIELDOFFSET(Frame, width);//result:4; FIELDOFFSET用来判断字符所占字节
int offset_longlong = FIELDOFFSET(Frame, height); //result:8;
return 0;
}
- 查看结构体偏移量方法:#define FIELDOFFSET(TYPE,MEMBER)(int)(&(((TYPE*)0)->MEMBER))
2. 调用约定
- _cdecl: C调用约定,参数从 右至左的方式入栈,函数本身不清理栈,由调用者负责,故,允许可变参数函数存在;
- _stdcall: 标准调用约定,参数按照从 右至左的方式入栈,函数本身清理栈。
3. C#与C/C++类型对应关系
- 说明:ubyte<—>char;byte<—>unsigned char
2. 创建并调用动态链接库
-
新建文件夹,存放项目(src 源码文件夹)
-
创建C# 项目(.Framework)
- 设置输出目录、目标平台(x64)
- 启用本地代码调试(方便调试跳转dll文件):
- 链接Dll示例:
- 创建C++项目
- 设置输出/调试目录
- 链接Dll示例:
- 创建Dll动态链接库
-
取消预编译头
-
输出目录
-
配置预编译、宏定义
- 配置项目依赖项
- 重新生成解决方案:
3. Dllimport常用参数
二、实例调用
1. C#与Dll链接库的数据交换
- C/C++基本数据字节:
1. 基本数据类型
- 值传递(C# ----> C/C++)
- Dll代码(.h / .cpp)
#pragma once
//预编译
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif // __cplusplus
//宏定义
#ifdef DLL_IMPORT
#define HEAD EXTERNC __declspec(dllimport)
#else
#define HEAD EXTERNC __declspec(dllexport)
#endif // DLL_IMPORT
#define CallingConvention _cdecl
//示例方法
HEAD void CallingConvention Test_BasicData(char d1,short d2,int d3,long long d4,float d5,double d6);
#include "Native.h"
#include <iostream>
HEAD void CallingConvention Test_BasicData(char d1, short d2, int d3, long long d4, float d5, double d6)
{
d1, d2, d3, d4, d5, d6;
}
- C#代码
using System;
using System.Runtime.InteropServices;
namespace CallNativeDllCSharp
{
class Program
{
[DllImport("NativeDll.dll",CallingConvention = CallingConvention.Cdecl)]
public static extern void Test_BasicData(sbyte d1, short d2, int d3, long d4, float d5, double d6);
static void Main(string