Android 平台C# 与C++之间的互相调用方法
2016-11-13 01:31
891 查看
Java与C++的互相调用很容易做到,有好几种方式实现,如 JNI , JNA 方式 ,而C# 与C++之间的相互调用就有点麻烦了,一般情况下是C#调用C++ ,C++却无法调用C# 。本人就是为了解决C++ 调用C#的问题,也就是可以实现C#调用C++,然后C++再回调C# 。本人搜索了大量的网络文章,却没有找到有效方法,偶然间在Steamwork.Net的源码里发现了
可行的方法,并经项目实际使用验证可行 。
具体实现例子请看下面的代码
C#端,回调实现:
实现调用 如下:
C++端代码如下:
编译可以用命令: g++ --std=c++11 InvokeTest.cpp -fPIC -shared -o libNativeTest.so
以上代码在linux下编译运行通过
Linux平台下安装 mono , 编译完成后,拷贝libNativeTest.so到C#编译后的exe文件目录下,然后命令运行 : mono
xxxx.exe
Windows还没测试。。。。。。
以上只是例子,实现使用还需要完善
可行的方法,并经项目实际使用验证可行 。
具体实现例子请看下面的代码
C#端,回调实现:
using System; using System.Runtime.InteropServices; using System.Collections.Generic; namespace IPInvoke { public class CallbackInvoke { static CallbackInvoke () { } internal const string NativeLibraryName = "NativeTest"; [DllImport(NativeLibraryName, EntryPoint = "RegisterCallback")] public static extern void RegCallback(IntPtr cbPtr); [DllImport(NativeLibraryName, EntryPoint = "UnregisterCallback")] public static extern void UnregisterCallback(); [DllImport(NativeLibraryName, EntryPoint = "GetUser")] public static extern void GetUser(int uid); [DllImport(NativeLibraryName, EntryPoint = "RequestGameInfo")] public static extern void RequestGameInfo (int gameId); private static Dictionary<Type,IDisposable> mDisposes = new Dictionary<Type,IDisposable>(); public delegate void DispatchDelegate<T>(T param); public static void RegisterCallback<T>(DispatchDelegate<T> callback){ Type t = typeof(T); IDisposable r=new Callback<T>(callback); if (mDisposes.ContainsKey (t)) { IDisposable d=mDisposes [t]; if(d!=null)d.Dispose(); } mDisposes [t] = r; } public sealed class Callback<T> :IDisposable { private CCallbackBaseVTable VTable; private IntPtr m_pVTable = IntPtr.Zero; private GCHandle m_pCCallbackBase; private CCallbackBase m_CCallbackBase; private event DispatchDelegate<T> m_Func; public Callback(DispatchDelegate<T> func) { if (func == null) { throw new Exception("Callback function must not be null."); } BuildCCallbackBase(); m_Func = func; RegCallback(m_pCCallbackBase.AddrOfPinnedObject()); //传递被“钉住”的地址到C++ } ~Callback() { Dispose(); } public void Dispose(){ if (m_pVTable != IntPtr.Zero) { Marshal.FreeHGlobal(m_pVTable); m_pVTable=IntPtr.Zero; } if (m_pCCallbackBase.IsAllocated) { m_pCCallbackBase.Free(); } } private void OnCallback( IntPtr thisptr, IntPtr pvParam) { try { m_Func((T)Marshal.PtrToStructure(pvParam, typeof(T))); } catch (Exception e) { } } private void BuildCCallbackBase() { VTable = new CCallbackBaseVTable() { m_RunCallback = OnCallback, }; m_pVTable = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CCallbackBaseVTable))); Marshal.StructureToPtr(VTable, m_pVTable, false); m_CCallbackBase = new CCallbackBase() { m_vfptr = m_pVTable, m_iCallback = CallbackIdentities.GetCallbackIdentity(typeof(T)) }; m_pCCallbackBase = GCHandle.Alloc(m_CCallbackBase, GCHandleType.Pinned); //手动进行内存管理,防止被GC ,不用的时候一定要进行释放 } } [StructLayout(LayoutKind.Sequential)] private class CCallbackBase { public IntPtr m_vfptr; //对应对C++回调类中的成员函数 public int m_iCallback; //对应于C++回调类中的成员,标识回调的ID }; [StructLayout(LayoutKind.Sequential)] internal class CCallbackBaseVTable { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void RunCBDel(IntPtr thisptr, IntPtr pvParam); //第一个参数thisptr 必须有,不然回调结果不对 ,不知为什么 [NonSerialized] [MarshalAs(UnmanagedType.FunctionPtr)] public RunCBDel m_RunCallback; } } internal class CallbackIdentities { public static int GetCallbackIdentity(Type callbackStruct) { foreach (CallbackIdentityAttribute attribute in callbackStruct.GetCustomAttributes(typeof(CallbackIdentityAttribute), false)) { return attribute.Identity; } throw new Exception("Callback number not found for struct " + callbackStruct); } } [AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)] internal class CallbackIdentityAttribute : System.Attribute { public int Identity { get; set; } public CallbackIdentityAttribute(int callbackNum) { Identity = callbackNum; } } }
实现调用 如下:
using System; using System.Runtime.InteropServices; namespace IPInvoke { public class MainClass { public const int CALLBACK_TYPE_USER=1; public const int CALLBACK_TYPE_GAME=2; [StructLayout(LayoutKind.Sequential)] [CallbackIdentity(CALLBACK_TYPE_USER)] public struct User_t { public uint userid; public uint gid; } [StructLayout(LayoutKind.Sequential)] [CallbackIdentity(CALLBACK_TYPE_GAME)] public struct Game_t { public uint id; public uint price; } public static void onReceive(User_t u){ Console.WriteLine ("onReceive user id " + u.userid+", gid : "+u.gid); } public static void onReceiveGame(Game_t u){ Console.WriteLine ("onReceive Game id " + u.id+", price : "+u.price); } public static void Main (string[] args) { CallbackInvoke.RegisterCallback<User_t>(onReceive); CallbackInvoke.RegisterCallback<Game_t>(onReceiveGame); Console.WriteLine ("Hello World!"); CallbackInvoke.RequestGameInfo (100); CallbackInvoke.GetUser (10000); CallbackInvoke.UnregisterCallback (); Console.WriteLine ("UnregisterCallback"); while (true) ; } } }
C++端代码如下:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <thread> #include <unistd.h> using namespace std; #define CALLBACK_MAX 20 #define CALLBACK_TYPE_USER 1 #define CALLBACK_TYPE_GAME 2 class ICallback { public: virtual void OnCallback(void* data)=0; int i_mCallback; }; typedef struct _User_t{ uint32_t uid; uint32_t gid; }User_t; typedef struct _Game_t{ uint32_t id; uint32_t price; }Game_t; class ICallback *mCallback[CALLBACK_MAX]; extern "C" void RegisterCallback(ICallback *intf) { printf("RegisterCallback i_mCallback %d \n",intf->i_mCallback); mCallback[intf->i_mCallback]=intf; } extern "C" void UnregisterCallback() { for(int i=0;i<CALLBACK_MAX;i++){ mCallback[i]=NULL; } } extern "C" void RunCallbacks(){ } extern "C" void GetUser(int uid){ printf("GetUser uid %d \n",uid); if(mCallback[CALLBACK_TYPE_USER]!=NULL){ User_t user ; user.uid=uid+1200; user.gid=16; mCallback[CALLBACK_TYPE_USER]->OnCallback(&user); } } extern "C" void RequestGameInfo(int gameId){ printf("RequestGameInfo uid %d \n",gameId); std::thread t= std::thread([=](){ sleep(1); if(mCallback[CALLBACK_TYPE_GAME]!=NULL){ Game_t game ; game.id=gameId; game.price=150; mCallback[CALLBACK_TYPE_GAME]->OnCallback(&game); } }); t.join(); }
编译可以用命令: g++ --std=c++11 InvokeTest.cpp -fPIC -shared -o libNativeTest.so
以上代码在linux下编译运行通过
Linux平台下安装 mono , 编译完成后,拷贝libNativeTest.so到C#编译后的exe文件目录下,然后命令运行 : mono
xxxx.exe
Windows还没测试。。。。。。
以上只是例子,实现使用还需要完善
相关文章推荐
- Android实现Activity、Service与Broadcaster三大组件之间互相调用的方法详解
- C++ 调用C#工程的 dll , 互相调用方法
- 老生常谈之C++和C#之间互相调用
- c#编程指南(九) 平台调用P-INVOKE完全掌握,C#和C++互相调用
- c#编程指南——平台调用P-INVOKE完全掌握,C#和C++互相调用
- C#调用C++dll方法,char*类型之间的传递
- 老生常谈之C++和C#之间互相调用
- 平台调用 4000 P-INVOKE完全掌握,C#和C++互相调用
- [总结]非托管C++代码调用C#编写的dll方法
- com调用的几种方法 及 C#调用C++编写的的COM DLL
- js与C#之间相互调用的一些方法
- C++与C#编写的DLL/COM的各种调用方法
- 转:使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法
- C/C++与Java之间的互相调用
- 在C#中调用C++Dll函数的方法
- javascript与asp.net(c#)互相调用方法
- C++与C#编写的DLL/COM的各种调用方法
- com调用的几种方法 及 C#调用C++编写的的COM DLL
- C#动态调用c++DLL的方法
- C# 调用C++, C++与C#互相调用