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

时间: 06-22

unity3d进程通信利用WM_COPYDATE和HOOK的相关文章

进程通信——匿名管道

有的时候在程序的开发过程中,两个进程之间会有数据的交互.信号的机制能够实现进程通信.它通过 “中断--响应” 的异步模式来工作.但作为通信来讲,信号还是远远不够的.因为它不能够携带任何其他的信息.只利用信号机制来实现进程通信显得捉襟见肘,并且信号的优势并不此.所以必须开发新的进程间通信的方法.本文所学习的 "匿名管道" 便是其中的一种最简单的方法. 基本概念 在讲管道的基本概念之前,首先提一个问题.如果让你来设计进程通信的方式,你会怎么做?最简单的方式莫过于两个进程打开同一个文件,这样

初始网络进程通信

可以这样说:我们在网络上只做一件事,利用各种软件没完没了的相互通信. 对于单机系统而言,进程在系统中有自己唯一的进程号.但在网络环境下,各主机独立分配的进程号不能唯一标识该进程.例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程”这句话就没有意义了.而且 操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同.因此,网间进程通信还要解决多重协议的识别问题. 为此,TCP/IP协议为网间进程通信问题建立了IP地址,端口,Socket(套接字)等概念.      (

进程通信(转)

1.定义: 进程通讯是指进程之间的信息交换. 在进程之间要传送大量数据时,就需要使用进程通讯. 进程互斥和同步需要交换一定的信息,它们也可归为进程通讯,属于低级的进程通讯.低级的原因在于 (1).效率低,生产者每次只能向缓冲池投放一个产品(消息),消费者每次只能从缓冲池中取得一个消息 (2).通讯对用户不透明,OS职位进程之间的通讯提供了共享存储其. 2.进程通讯特点: 使用方便.OS隐藏了实现进程通讯的具体细节,向用户提供了一组用于实现高级通信的命令(原语),用户可方便的直接利用它实现进程之间

Qt的内部进程通信机制 [转]

Qt 作为一种跨平台的基于 C++ 的 GUI系统,能够提供给用户构造图形用户界面的强大功能.自从 1996 年 Qt 被 Trolltech公司发布以来,该系统成为世界上很多成功的图形用户应用所使用的主要系统.更为重要的是,Linux 操作系统的桌面环境系统 KDE 也是基于 Qt构造的.目前,Qt 已经提供了对包括 MS/Windows.Unix/X11 和嵌入式平台的支持,得到了越来越广泛的应用. 在 Qt 系统中,不仅有着构造完善的系统结构,而且为了满足用户对编写图形用户界面应用的种种需

Linux间的进程通信;以及子进程的创建

1 "-----第六天-----------------------------------------------------------------------------" 2 3 1.版本控制:svn/git; 4 5 2.进程的概念: 6 1)程序和进程: 7 每个进程操作系统会为它分配 0-4G 的虚拟内存空间(32位操作系统): 其中0-3G为用户内存空间,进程可以对它进行读写操作: 3G - 4G 为系统内核空间,进程没有读写权限. 8 进程只能读写用户空间,没有权限读

messenger跨进程通信出现ClassNotFoundException...

利用messenger实现remote进程的service和主进程通信的时候报错com.xxx.xxx.xxx.bean.xxxbean on path: DexPathList[[directory .],nativeLibraryDirectories=[/vendor/lib, /data/cust/lib, /system/lib]] 看log发现错误处是在client解析从service发过来的message中的bundle对象, 网上搜了有人说是因为类加载器的问题,然后自己在   d

进程通信

1.定义: 进程通讯是指进程之间的信息交换. 在进程之间要传送大量数据时,就需要使用进程通讯. 进程互斥和同步需要交换一定的信息,它们也可归为进程通讯,属于低级的进程通讯.低级的原因在于 (1).效率低,生产者每次只能向缓冲池投放一个产品(消息),消费者每次只能从缓冲池中取得一个消息 (2).通讯对用户不透明,OS职位进程之间的通讯提供了共享存储其. 2.进程通讯特点: 使用方便.OS隐藏了实现进程通讯的具体细节,向用户提供了一组用于实现高级通信的命令(原语),用户可方便的直接利用它实现进程之间

linux 单机跨进程通信

一般来说通过网络通信(比如tcp,udp)或者共享内存的方式肯定可以实现跨进程通信,但现在这里要说的是比较偏但实用的几个方法:利用unix域通信(普通网络连接),利用unix域通信(socketpair通信),以及pipe方式. 一. 利用unix域通信(普通网络连接) socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.

Linux进程通信——管道

进程间通信(IPC:Inner Proceeding Communication) 进程是操作系统实现程序独占系统运行的假象的方法,是对处理器.主存.I/O设备的抽象表示.每个进程都是一个独立的资源管理单元,每个进程所看到的是自己独占使用系统的假象,因此各个进程之间是不能够直接的访问对方进程的资源的,不同的进程之间进行信息交互需要借助操作系统提供的特殊的进程通信机制. 进程之间的通信,从物理上分,可以分为同主机的进程之间的通信和不同主机间的进程之间的通信.从通信内容方式上分,可以分为数据交互.同