关于C#调用C++动态链接库

1. char*(const char*)与string类型对应

1)C#传到C++
C++ :char*
C#: [MarshalAs(UnmanagedType.LPStr)] string
2)c# 传中文字符给c++ 出现乱码问题
解决办法:把string转为byte[] 再放到内存指针即可

byte[] encodedBytes=Encoding.UTF8.GetBytes("string");
IntPtr wordPtr = Marshal.AllocHGlobal(encodedBytes.Length);
Marshal.Copy(encodedBytes, 0, wordPtr, encodedBytes.Length);

3)C#接收C++返回的中文乱码
解决方法:收到的字符编码格式是Ansi,转成utf-8再转string

//C++返回IntPtr data
byte[] byte_copy = new byte[len];
Marshal.Copy(data, byte_copy, 0, (int)len);
string str = System.Text.Encoding.UTF8.GetString(byte_copy);

2. 数组传递注意事项

public static extern bool Render([MarshalAs(UnmanagedType.LPArray, SizeConst =23)]double[] data, [MarshalAs(UnmanagedType.LPArray, SizeConst = 23)]int[] colors);
千万注意,传递数组一定要加上MarshalAs标记,标记为传递数组,而且必须指定传递的数量,如果不标记数量,则每次只传递一个数值!

3.结构体传参

注意事项:1)不能忘记[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct msg_MsgNList
        {
            public UInt32 n;
            public IntPtr item;
        }
2)变量对应
//C++
struct Msgpublic MsgHeader
{
	uint 32 id;
}
//C#
struct Msg
{
	public uint 32 id;
	public MsgHeader msg_header;//一定要注意这两个变量的顺序,写错了是不行的,真是个大坑!!!!!
}

3)C++与C#传递的struct的Pack要设置

//C++
#pragma pack(push, 1)
typedef struct
{
	 MsgHeader header;
     ID_t n;
} Msg;
//C#
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Msg
{
    public MsgHeader header;
    public UInt32 n;
}

4.C#调用C++DLL二级指针处理方式

参考

//C++
const char** MGetAudioDevice()
{
	const char **AudioDevices =new const char*[2];
	for (int i = 0; i<2; i++) {
		AudioDevices[i] = new char[128];
	}
	AudioDevices[0] = "hello";
        AudioDevices[0] = "world";
	return AudioDevices;
}
//C#
[DllImport("./Voip/VoipDLL/LIBTODLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr MGetAudioDevice();
//c#用结构体接受双指针的内容
 public struct Node
 {
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
      public string[] vs;
 }
 private void btn_login_Click(object sender, EventArgs e)
{
      IntPtr ssss = VoIP.MGetAudioDevice();
      Node node = (Node)Marshal.PtrToStructure(ssss,typeof(Node));
      Console.WriteLine(node.vs[0] + node.vs[1]);
      //最后释放掉
      Marshal.FreeHGlobal(ssss);
}

5.C++调用C#回调函数–C#侧

参考

//C++
// 传入函数指针
typedef void (*FUNC)(int,char*);
JNAAPI bool processCallback(int a,FUNC func);
//C#
public delegate void CallbackDelegate(int a,string param); //声明委托
 
// 接口定义
[DllImport("jnalib.dll", EntryPoint = "processCallback")]
public static extern bool processCallback(int a, CallbackDelegate call);
 
//调用示例
CallbackDelegate myDelegate = new CallbackDelegate(CallbackFunc); //需要传入回调函数名
processCallback(25, myDelegate); //最好声明委托实例为static,防止垃圾回收器的回收

然后我们就可以在CallbackFunc里面编写回调逻辑了,而JNA回调以interface作为参数,两者相差不大.

//C#
// 回调函数
public static void CallbackFunc(int a,string param)
{
Console.WriteLine("参数1: {0}", a);
Console.WriteLine("参数2:{0}", param);
}

6.对“xxx”类型的已垃圾回收委托进行了回调

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。

解决方法:keepAlive和设置为static,具体看代码
//出问题的代码
public class Node
{
	public void run()
	{
		IntPtr param = IntPtr.Zero;
        Init_callBack init_CallBack = new Init_callBack(node_init);
        this._node.setInitCallback(init_CallBack, param);
	}
}
//修正后的代码
public class Node
{
	static Init_callBack init_CallBack;//关键的一句
	public void run()
	{
		IntPtr param = IntPtr.Zero;
        init_CallBack = new Init_callBack(node_init);
        this._node.setInitCallback(init_CallBack, param);
        GC.KeepAlive(init_CallBack);//关键的一句
	}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Android 平台上,可以通过使用 JNI(Java Native Interface)来调用 C++ 动态(DLL)。JNI 是一个 Java 虚拟机规范,用于实现 Java 代码与本地代码的交互。通过 JNI,可以在 Java 中声明本地方法,并将其实现委托给本地代码,以便在 Java 中调用本地方法。 要在 Android 中调用 C++ DLL,需要先将 DLL 编译为适用于 Android 平台的共享(.so 文件),然后在 Java 代码中使用 JNI 调用该共享。具体步骤如下: 1. 在 C++ 中编写动态,并将其编译为适用于 Android 平台的共享(.so 文件)。 2. 在 Java 中声明 native 方法,以便在 Java 中调用 C++ 方法。例如: ```java public class MyNativeClass { public native int myNativeMethod(int arg); } ``` 3. 在 C++ 中实现该方法,并将其封装为静态(.a 文件)或共享(.so 文件)。 4. 将 C++ 与 Java 代码链,并打包为 Android 应用程序。 5. 在 Java 代码中,使用 System.loadLibrary() 方法加载 C++ ,并调用 native 方法。例如: ```java public class MyJavaClass { static { System.loadLibrary("MyNativeLibrary"); } public static void main(String[] args) { MyNativeClass myNativeClass = new MyNativeClass(); int result = myNativeClass.myNativeMethod(42); System.out.println("Result: " + result); } } ``` 需要注意的是,JNI 调用 C++ 方法的过程中,需要进行参数类型转换和内存管理等操作,因此需要谨慎处理。另外,由于 Android 平台涉及多种架构,需要针对不同的架构编译对应的共享

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值