hello,近期用unity做了进程通信,应该是和c++的PC端实现通信,才開始一头雾水,后来实现了才知道好繁杂......先感谢对我提供帮助的百度,谷歌以及游戏圈的大大们。
在进程通信中非常多方法,可是wm_copydate绝对要比别的什么内存共享好了很多。
unity大部分用c#语言,c#本身Forms这个dll里面也提供了对windows消息的接收可是在unity中无法非常好地使用System.Windows.Forms,所以在以下我的代码我用unity发送进程消息的是 user32.dll 中的sendMessage。对于接收则是用的hook(钩子)。
以下代码是unity打包出来的exe的通信。就不和c++通信了。原理都一样。
整个过程要导入user32.dll ,所以在须要using System.Runtime.InteropServices;剩下须要引用什么加入什么,里面还有发送json数据以及很多细节的c#取地址读取地址,我也一并分享大家乐,以后也要帮我哦.
发送端(利用sendMessage),test1.cs挂载在unity场景中
using System; using UnityEngine; using System.Collections; using System.Runtime.InteropServices; using System.Text; public class test15 : MonoBehaviour { #region public IntPtr m_hWnd; /// <summary> /// 发送windows消息方便user32.dll中的SendMessage函数使用 /// </summary> public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } //user32.dll中的SendMessage [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, ref COPYDATASTRUCT lParam); //user32.dll中的获得窗口句柄 [DllImport("user32.dll")] public static extern IntPtr FindWindow(string strClassName, string strWindowName); //宏定义 private const ushort IPC_VER = 1; private const int IDT_ASYNCHRONISM = 0x0201; private const uint WM_COPYDATA = 0x004A; private const ushort IPC_CMD_GF_SOCKET = 1; private const ushort IPC_SUB_GF_SOCKET_SEND = 1; private const int IPC_SUB_GF_CLIENT_READY = 1; private const int IPC_CMD_GF_CONTROL = 2; private const int IPC_BUFFER = 10240;//最大缓冲长度 //查找的窗口 private IntPtr hWndPalaz; //数据包头配合使用 public unsafe struct IPC_Head { public ushort wVersion; public ushort wPacketSize; public ushort wMainCmdID; public ushort wSubCmdID; } public unsafe struct IPC_Buffer { public IPC_Head Head; //IPC_Head结构 public fixed byte cbBuffer[IPC_BUFFER]; //指针 存放json数据 利用byte[]接收存放 } #endregion /// <summary> /// 发送把json转换为指针传到SendData()方法 /// </summary> private void sendJson() { IntPtr hWndPalaz = FindWindow(null, "你们要查找的窗口名字");//就是窗口的的标题 Debug.Log(hWndPalaz); if (hWndPalaz != null) { //获得游戏本身句柄 m_hWnd = FindWindow("UnityWndClass", null); //发送用户准备好消息(这个是个json插件我就不提供了你们自己搞自己的json new一个实例这里不改会报错) JSONObject jsStart = new JSONObject(); jsStart.AddField("六六", "是我"); jsStart.AddField("sya", "学习游戏为了装逼小组"); jsStart.AddField("doing", "this is your time"); string uRstr = jsStart.ToString(); byte[] bytes = Encoding.UTF8.GetBytes(uRstr); IntPtr pData = Marshal.AllocHGlobal(2 * bytes.Length); Marshal.Copy(bytes, 0, pData, bytes.Length); SendData(m_hWnd, IPC_CMD_GF_SOCKET, IPC_SUB_GF_SOCKET_SEND, pData, (ushort)bytes.Length); } } /// <summary> /// SendMessage发送 /// </summary> /// <param name="hWndServer">指针</param> /// <param name="wMainCmdID">主命令</param> /// <param name="wSubCmdID">次命令</param> /// <param name="pData">json转换的指针</param> /// <param name="wDataSize">数据大小</param> /// <returns></returns> public unsafe bool SendData(IntPtr hWndServer, ushort wMainCmdID, ushort wSubCmdID, IntPtr pData, ushort wDataSize) { //给IPCBuffer结构赋值 IPC_Buffer IPCBuffer; IPCBuffer.Head.wVersion = IPC_VER; IPCBuffer.Head.wSubCmdID = wSubCmdID; IPCBuffer.Head.wMainCmdID = wMainCmdID; IPCBuffer.Head.wPacketSize = (ushort)Marshal.SizeOf(typeof(IPC_Head)); //内存操作 if (pData != null) { //效验长度 if (wDataSize > 1024) return false; //拷贝数据 IPCBuffer.Head.wPacketSize += wDataSize; byte[] bytes = new byte[IPC_BUFFER]; Marshal.Copy(pData, bytes, 0, wDataSize); for (int i = 0; i < IPC_BUFFER; i++) { IPCBuffer.cbBuffer[i] = bytes[i]; } } //发送数据 COPYDATASTRUCT CopyDataStruct; IPC_Buffer* pPCBuffer = &IPCBuffer; CopyDataStruct.lpData = (IntPtr)pPCBuffer; CopyDataStruct.dwData = (IntPtr)IDT_ASYNCHRONISM; CopyDataStruct.cbData = IPCBuffer.Head.wPacketSize; SendMessage(hWndServer, 0x004A, (int)m_hWnd, ref CopyDataStruct); return true; } void Update() { sendJson();//一直发送方便測试 } }
接收端 test2.cs 随便建场景保存将这个脚本挂载场景的物体上面 。然后用unity打包pc端的exe 接收利用windows的hook钩子(这里我就不做具体的凝视了,自己体会hook的妙用了,不懂能够给我留言)
using UnityEngine; using System; using System.Diagnostics; using System.Runtime.InteropServices; using Debug = UnityEngine.Debug; public class test2: MonoBehaviour { //钩子接收消息的结构 public struct CWPSTRUCT { public int lparam; public int wparam; public uint message; public IntPtr hwnd; } //建立钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, uint dwThreadId); //移除钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern bool UnhookWindowsHookEx(int idHook); //把信息传递到下一个监听 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int CallNextHookEx(int idHook, int nCode, int wParam, int lParam); //回调托付 private delegate int HookProc(int nCode, int wParam, int lParam); //钩子 int idHook = 0; //是否安装了钩子 bool isHook = false; GCHandle gc; private const int WH_CALLWNDPROC = 4; //钩子类型 全局钩子 //定义结构和发送的结构相应 public unsafe struct IPC_Head { public int wVersion; public int wPacketSize; public int wMainCmdID; public int wSubCmdID; } private const int IPC_BUFFER = 10240;//最大缓冲长度 public unsafe struct IPC_Buffer { public IPC_Head Head; public fixed byte cbBuffer[IPC_BUFFER]; //json数据存的地方 } public struct COPYDATASTRUCT { public int dwData; public int cbData; public IntPtr lpData; } void Start() { //安装钩子 HookLoad(); } void OnDestroy() { //关闭钩子 HookClosing(); } private void HookLoad() { Debug.Log("開始执行"); //安装钩子 { //钩子托付 HookProc lpfn = new HookProc(Hook); //关联进程的主模块 IntPtr hInstance = IntPtr.Zero;// GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName); idHook = SetWindowsHookEx(WH_CALLWNDPROC, lpfn, hInstance, (uint)AppDomain.GetCurrentThreadId()); if (idHook > 0) { Debug.Log("钩子[" + idHook + "]成功安装"); isHook = true; //保持活动 避免 回调过程 被垃圾回收 gc = GCHandle.Alloc(lpfn); } else { Debug.Log("钩子安装失败"); isHook = false; UnhookWindowsHookEx(idHook); } } } //卸载钩子 private void HookClosing() { if (isHook) { UnhookWindowsHookEx(idHook); } } private bool _bCallNext; public bool CallNextProc { get { return _bCallNext; } set { _bCallNext = value; } } //钩子回调 private unsafe int Hook(int nCode, int wParam, int lParam) { try { IntPtr p = new IntPtr(lParam); CWPSTRUCT m = (CWPSTRUCT)Marshal.PtrToStructure(p, typeof(CWPSTRUCT)); if (m.message == 74) { COPYDATASTRUCT entries = (COPYDATASTRUCT)Marshal.PtrToStructure((IntPtr)m.lparam, typeof(COPYDATASTRUCT)); IPC_Buffer entries1 = (IPC_Buffer)Marshal.PtrToStructure((IntPtr)entries.lpData, typeof(IPC_Buffer)); IntPtr intp = new IntPtr(entries1.cbBuffer); string str = new string((sbyte*)intp); Debug.Log("json数据:" + str); } if (CallNextProc) { return CallNextHookEx(idHook, nCode, wParam, lParam); } else { //return 1; return CallNextHookEx(idHook, nCode, wParam, lParam); } } catch (Exception ex) { Debug.Log(ex.Message); return 0; } } }
OK,全部代码最终特么的完成了。把test2.cs的场景打包。把test1.cs的代码放在unity执行即可了。最终看test2.cs的exe中的这些代码花了我好长时间,非常值钱的我就这么分享给大家了,希望大家有好的东西也不要吝啬啊。嘿嘿,最后有不懂的能够加我的Q群479853988问我哦。里面非常多大神也能够问。转载注重原创哦。