• unity3d进程通信利用WM_COPYDATE和HOOK


    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问我哦。里面非常多大神也能够问。转载注重原创哦。微笑




  • 相关阅读:
    前端部分框架
    Postman
    java intellij 写控制台程序 窗口程序
    postgresql 连接数
    CPU制造工艺 级选来决定cpu等级
    CPU 材料学才是最顶级的学科
    关于asp.net和iis的进程/线程问题,假如网站有1000个人访问,会产生多少个进程/线程啊
    io会消耗cpu吗?
    数据密集型 和 cpu密集型 event loop
    Javascript是一个事件驱动语言
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7071618.html
Copyright © 2020-2023  润新知