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问我哦。里面非常多大神也能够问。转载注重原创哦。
unity3d进程通信利用WM_COPYDATE和HOOK的更多相关文章
- MINIX3 进程通信分析
MINIX3 进程通信分析 6.1MINIX3 进程通信概要 MINIX3 的进程通信是 MINIX3 内核部分最重要的一个部件,我个人认为其实这 是内核中的“内核”,怎么来理解这个概念呢?其实 MI ...
- [转]WINDOW进程通信的几种方式
windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...
- Qt 的内部进程通信机制
Qt 的内部进程通信机制 续欣 (xxin76@hotmail.com), 博士.大学讲师 2004 年 4 月 01 日 Qt 作为一种跨平台的基于 C++ 的 GUI 系统,能够提供给用户构造图形 ...
- Linux进程通信学习总结
http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念 引用标识符:引用标识符是一个整数,表示每一个SYSV ...
- 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇
前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...
- python 守护进程、同步锁、信号量、事件、进程通信Queue
一.守护进程 1.主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes ...
- Android-Messenger跨进程通信
http://blog.csdn.net/lmj623565791/article/details/47017485 一.概述 我们可以在客户端发送一个Message给服务端,在服务端的handler ...
- 初识网络进程通信<Heart.X.Raid>
可以这样说:我们在网络上只做一件事,利用各种软件没完没了的相互通信. 对于单机系统而言,进程在系统中有自己唯一的进程号.但在网络环境下,各主机独立分配的进程号不能唯一标识该进程.例如,主机A赋于某进程 ...
- Linux之进程通信20160720
好久没更新了,今天主要说一下Linux的进程通信,后续Linux方面的更新应该会变缓,因为最近在看Java和安卓方面的知识,后续会根据学习成果不断分享更新Java和安卓的方面的知识~ Linux进程通 ...
随机推荐
- 在centOS6.5 上安装使用pipework
需求:镜像生成了2个含有tomcat的容器,用nginx进行负载均衡.但是容器重启后ip会自动改变...所以使用pipework进行分配静态ip pipework安装 OS:centos6.5 第一步 ...
- unity3d Pathfinding插件使用
Overview The central script of the A* Pathfinding Project is the script 'astarpath.cs', it acts as a ...
- Android SQLiteDatabase分析
Android中的数据存储使用的小巧的SQLite数据库. 为了方便java层使用SQLite,android做了大量的封装.提供了一些列的类和API.本文章就揭露这些封装背后的类图关系. 老规矩,首 ...
- WEBSERVICE之JDK开发webservice
转自:https://www.cnblogs.com/w-essay/p/7357262.html 一.开发工具与环境 1. jdk1.6版本以上(jdk1.6.0_21及以上版本) 2 .eclip ...
- Session会在浏览器关闭后消失吗?
转 http://blog.csdn.net/rongwenbin/article/details/51784310 Cookie的两种类型 在项目开发中我们时常将需要在客户端(浏览器)缓存的数 ...
- ROS集成开发环境RoboWare Studio安装教程
前言:很多人说vim是最快的,所以我选择用roboware. ROS 自带的编辑器vim增加插件,效果如下: RoboWare Studio,效果如下: 下面开始安装. 一.安装 去官网 http:/ ...
- 获取sqlserver数据字典的完整sql
SELECTsysobjects.name AS 表名称 , --------------as 的作用:为字段起一个别名 --sysproperties.[value] AS 表说明 , ------ ...
- LVS(Linux Viretual Server) 负载均衡器 + 后端服务器
##定义: LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统. ##结构: 一般来说,LVS集群采用三层结构,其主要组成部分为: A.负载调 ...
- 洛谷P4016 负载平衡问题(最小费用最大流)
题目描述 GG 公司有 nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 nn 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入输出格式 输入格 ...
- java中常用的转义字符
Day02_SHJavaTraing_4-3-2017 Java中允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量. 一.JAVA中常用的转义字符