C# 调用C/C++ DLL库的回调函数

时间:2023-01-25 18:59:17

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

一个可用作 C 样式函数指针的整数。 可将此成员用于 Delegate 数据类型或从 Delegate 继承的类型。

  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

COM 接口指针。 接口的 Guid 可从类元数据获得。 如果将此成员应用于类,则可以使用该成员指定确切的接口类型或默认的接口类型。 应用于 Object 数据类型时,此成员将产生与 UnmanagedType.IUnknown 相同的行为。

  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 能够更改非托管代码中的字符串,并使结果在托管代码中反映出来。 该值仅支持平台调用。

参考:http://blog.csdn.net/q339659207/article/details/48473211