1、在 C/C++端
定义一个函数指针
Typedef void (*TESTBACK)(int a, int b);
定义一个带函数指针的函数
__declspec(dllexport int add(TESTBACK ptsTestBack, int a, int b)
{
return ptsTestBack(a, b);
}
2、C# 端
声明回调函数的委托
[System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate int TESTCALLBACK(int a, int b);
[DLLImport("testDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extion int add([MarshalAs(UnmanagedType.FunctionPtr)]TESTCALLBACK testCallBack, int a, int b);
定义回调函数的实现函数
void addCallBack(int a, int b)
{
int c;
c = a+b;
Console.WriteLine({0},c);
}
int main(string[] args)
{
//函数指针实例化
TESTCALLBACK testCallBack = new TESTCALLBACK(addCallBack);
add(addCallBack, 1,2);
}
输出3
说明:
[System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.Cdecl)]
如果在声明回调函数时,不加上这句,则出现程序自动退出,错误码为:0x4000001f。主要原因为:不加上这句,会导致C#在调用完C函数
后,释放testCallBack的内容,导致C程序奔溃。所以在声明代理的时候,说明是C回调,不回收里面的资源。
[MarshalAs(UnmanagedType.FunctionPtr)] :说明是非托管函数指针,一个可用作C样式函数指针的整数。可将此成员用于Delegate数据类型或从Delegate
继承的类型。
下面为:UnmanagedType 的枚举:
成员名称 | ||
---|---|---|
AnsiBStr |
ANSI 字符串是一个带有长度前缀的单字节字符串。 可以在 String 数据类型上使用此成员。 |
|
AsAny |
一个动态类型,将在运行时确定对象的类型,并将该对象作为所确定的类型进行封送处理。 该成员仅对平台调用方法有效。 |
|
Bool |
4 字节布尔值 (true != 0, false = 0)。 这是 Win32 BOOL 类型。 |
|
BStr |
长度前缀为双字节的 Unicode 字符串。 可以在 String 数据类型上使用此成员(它是 COM 中的默认字符串)。 |
|
ByValArray |
当 MarshalAsAttribute.Value 属性被设置为 ByValArray 时,必须设置 SizeConst 字段以指示该数组中的元素数。 当需要区分字符串类型时,ArraySubType 字段可以选择包含数组元素的 UnmanagedType。 此 UnmanagedType 只可用于结构中其元素作为字段出现的数组。 |
|
ByValTStr |
用于在结构中出现的内联定长字符数组。 与 ByValTStr 一起使用的字符类型由应用于包含结构的 System.Runtime.InteropServices.StructLayoutAttribute 属性的 System.Runtime.InteropServices.CharSet参数确定。 应始终使用 MarshalAsAttribute.SizeConst 字段来指示数组的大小。 |
|
Currency |
货币类型。 在 System.Decimal 上使用,以将十进制数值作为 COM 货币类型而不是 Decimal 封送。 |
|
CustomMarshaler |
当与 MarshalAsAttribute.MarshalType 或 MarshalAsAttribute.MarshalTypeRef 字段一起使用时,指定自定义封送拆收器类。 MarshalAsAttribute.MarshalCookie 字段可用于将附加信息传递给自定义封送拆收器。 可以在任何引用类型上使用此成员。 |
|
Error |
一个本机类型,此类型与 I4 或 U4 关联且将导致参数作为导出类型库中的 HRESULT 导出。 |
|
FunctionPtr | ||
HString |
Windows 运行时 字符串。 可以在 System.String 数据类型上使用此成员。 |
|
I1 |
1 字节有符号整数。 可使用此成员将布尔值转换为 1 字节、C 样式的 bool (true = 1, false = 0)。 |
|
I2 |
2 字节有符号整数。 |
|
I4 |
4 字节有符号整数。 |
|
I8 |
8 字节有符号整数。 |
|
IDispatch |
COM IDispatch 指针(Microsoft Visual Basic 6.0 中的 Object)。 |
|
IInspectable |
Windows 运行时 接口指针。 可以在 Object 数据类型上使用此成员。 |
|
Interface | ||
IUnknown |
COM IUnknown 指针。 可以在 Object 数据类型上使用此成员。 |
|
LPArray |
指向 C 样式数组的第一个元素的指针。 当从托管到非托管代码进行封送处理时,该数组的长度由托管数组的长度确定。 从非托管到托管代码进行封送处理时,将根据 MarshalAsAttribute.SizeConst 和 MarshalAsAttribute.SizeParamIndex 字段确定该数组的长度,当需要区分字符串类型时,还可以后跟数组中元素的非托管类型。 |
|
LPStr |
单字节、以 null 结尾的 ANSI 字符串。 可以在 System.String 和 System.Text.StringBuilder 数据类型上使用此成员。 |
|
LPStruct |
一个指针,它指向用于封送托管格式化类的 C 样式结构。 该成员仅对平台调用方法有效。 |
|
LPTStr |
与平台相关的字符串:在 Windows 98 上为 ANSI,在 Windows NT 和 Windows XP 上为 Unicode。 该值仅支持平台调用而不支持 COM 互操作,因为不支持导出 LPTStr 类型的字符串。 |
|
LPUTF8Str |
指向 UTF-8 编码字符串的指针。 |
|
LPWStr |
一个 2 字节、以 null 结尾的 Unicode 字符串。 |
|
R4 |
4 字节浮点数。 |
|
R8 |
8 字节浮点数。 |
|
SafeArray |
SafeArray 是自我描述的数组,它带有关联数组数据的类型、秩和界限。 可将此成员与 MarshalAsAttribute.SafeArraySubType 字段一起使用,以替代默认元素类型。 |
|
Struct |
一个用于封送托管格式化类和值类型的 VARIANT。 |
|
SysInt |
与平台相关的有符号整数:在 32 位 Windows 上为 4 个字节,在 64 位 Windows 上为 8 个字节。 |
|
SysUInt |
与平台相关的无符号整数:在 32 位 Windows 上为 4 个字节,在 64 位 Windows 上为 8 个字节。 |
|
TBStr |
一个有长度前缀的与平台相关的 char 字符串:在 Windows 98 上为 ANSI,在 Windows NT 上为 Unicode。很少用到这个类似于 BSTR 的成员。 |
|
U1 |
1 字节无符号整数。 |
|
U2 |
2 字节无符号整数。 |
|
U4 |
4 字节无符号整数。 |
|
U8 |
8 字节无符号整数。 |
|
VariantBool |
2 字节、OLE 定义的 VARIANT_BOOL 类型 (true = -1, false = 0)。 |
|
VBByRefStr |
一个值,该值使 Visual Basic 能够更改非托管代码中的字符串,并使结果在托管代码中反映出来。 该值仅支持平台调用。 |