使用C#进行应用程序间通信(WPF与Unity通信)
首先程序主体来自网络,我只是应用在我自己的项目中,其中出现了一系列的问题,有些已经解决,有些使用了折中的方案,如果有大神能够给予知道,感激不尽!
首先是发送端程序:
这是我的程序任务执行主界面,此处已经显示了每个消防队员的空呼数据;
消防员在着火的大楼内部的具体方位采用Unity3d进行开发,因此我wpf程序需要将队员的位置信息传输到三维场景中;
发送数据的程序如下:
/// <summary>
/// 查找窗口
/// </summary>
[DllImport("user32.dll")]
public static extern IntPtr FindWindowA(string lpClassName, string lpWindowName); //user32.dll中的SendMessage
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, ref COPYDATASTRUCT lParam); //本窗口句柄
public IntPtr m_hWnd; //接收方窗口句柄
private IntPtr hWndPalaz; /// <summary>
/// 发送windows消息方便user32.dll中的SendMessage函数使用
/// </summary>
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
} //宏定义
private const ushort IPC_VER = ;
private const int IDT_ASYNCHRONISM = 0x0201;
private const uint WM_COPYDATA = 0x004A;
private const ushort IPC_CMD_GF_SOCKET = ;
private const ushort IPC_SUB_GF_SOCKET_SEND = ;
private const int IPC_SUB_GF_CLIENT_READY = ;
private const int IPC_CMD_GF_CONTROL = ;
private const int IPC_BUFFER = ;//最大缓冲长度 //数据包头配合使用
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]; //指针 存放数据 利用byte[]接收存放
} /// <summary>
/// 将字符串转换为指针用于发送
/// </summary>
public void SendData(string data)
{
hWndPalaz = FindWindowA(null, "Navigation2.0");//获取接收窗口句柄 if (hWndPalaz != null)
{
//获得当前窗口句柄
m_hWnd = FindWindowA("Mission", null); byte[] bytes = Encoding.UTF8.GetBytes(data.PadRight(, '/'));
IntPtr pData = Marshal.AllocHGlobal( * bytes.Length);
Marshal.Copy(bytes, , pData, bytes.Length);
SendData(hWndPalaz, 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 > ) return false;
//拷贝数据
IPCBuffer.Head.wPacketSize += wDataSize; byte[] bytes = new byte[IPC_BUFFER];
Marshal.Copy(pData, bytes, , wDataSize); for (int i = ; 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;
}
SendData函数重载了,只要调用void SendData(string args)即可。
接下来是接收端,接收端比较特殊,因为是Unity程序发布的exe,不是普通的窗口程序;
首先是我的三维程序界面:
地面是直接加载的百度地图或高德地图,手动绘制建筑物的轮廓,再通过设置层数、层高等参数即可生成楼层;
数据接收的代码:
using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices; public class DataClient : MonoBehaviour
{
List<string> caches = new List<string>();
void Start()
{
//安装钩子
HookLoad();
}void OnGUI()
{
GUI.contentColor = Color.red; GUILayout.Label(caches.Count.ToString());
for (int i = ; i < caches.Count; i++)
GUILayout.Label(caches[i].Length + ":" + caches[i]);
} void OnApplicationQuit()
{
//关闭钩子
HookClosing();
} //钩子接收消息的结构
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 = ;
//是否安装了钩子
bool isHook = false;
GCHandle gc;
private const int WH_CALLWNDPROC = ; //钩子类型 全局钩子 //定义结构和发送的结构对应
public unsafe struct IPC_Head
{
public int wVersion;
public int wPacketSize;
public int wMainCmdID;
public int wSubCmdID;
}
private const int IPC_BUFFER = ;//最大缓冲长度
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 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 > )
{
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 == )
{
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 - wParam);
caches.Add(str);
if (caches.Count > )
caches.RemoveAt();
} if (CallNextProc)
{
return CallNextHookEx(idHook, nCode, wParam, lParam);
}
else
{
return CallNextHookEx(idHook, nCode, wParam, lParam);
}
}
catch (Exception ex)
{
Debug.Log(ex.Message);
return ;
}
}
}
直接将脚本挂在某个物体上,然后注意的是发布后程序的名字(运行exe在窗口标题栏显示的名字),因为发送端是通过这个名字来找到该窗口的。
运行的效果如下:
注意,由于程序中用到的unsafe,不安全代码,因此要讲工程设置为允许不安全代码,而unity中则需要在工程Assets的根目录创建文本文件,内容设置:-unsafe,注意不要有多余的空格什么的,然后文件复制4分,文件名分别为:us.rsp、smcs.rsp、gmcs.rsp
、csc.rsp、boo.rsp,其实不是全部都要,每个针对一种语言的不安全代码,文件创建好了之后要重启一下unity。
使用C#进行应用程序间通信(WPF与Unity通信)的更多相关文章
- wpf集成unity
定义一个帮助类 实际上就是为了设置以下这两种属性 安全性信任和从html中可见的属性 即: 在html的javaScript中可用 window.external.方法名来调用C#方法 [Pe ...
- Wpf Prism.Unity 7
Prism.Unity 中UnityBootStrapper已经不用了,可以继承PrismApplication 1.Install-package Prism.Unity -v 7.2.0.1367 ...
- MVVM在WPF中应用(1)
在软件行业浸润了这么多年,第一次在MES的工厂里从事软件开发. 在这里的感觉就是安静.宽松,比在那些专门以软件为主的企业中轻松自在.在这里的第一个项目是关于数据的导入和导出,还有数据的比较这些功能. ...
- 2: 使用Prism初始化程序 Initializing Applications Using the Prism Library 5.0 for WPF(英汉对照版)
This topic addresses what needs to happen to get a Prism for WPF application up and running. A Prism ...
- 如何实现Windows Phone代码与Unity相互通信(事件方式)
源地址:http://www.cnblogs.com/petto/p/3909063.html 一些废话 昨天写一篇今天写一篇.不是我闲的蛋疼,是今天一天碰到了好几个恼人的问题,浪费一天时间搞定.本文 ...
- Unity 命令行参数
通常情况下,Unity可以通过双击桌面上的图标启动,也可以通过输入命令行启动(例如,MacOS终端或者Windows的CMD窗口),通过这种方式在启动时会接受命令和信息.我们可以制作一些小工具跟Uni ...
- Unity接第三方SDK时遇到的坑
1.大部分SDK的方法需要在线程中执行,一般会放在主线程里执行,安卓中主线程一般用于UI渲染. this.runOnUiThread(new Runnable() { @Override public ...
- Unity Web前端研究
原地址:http://blog.csdn.net/libeifs/article/details/7200630 开发环境 Window7 Unity3D 3.4.1 MB525defy Andro ...
- Unity之SDK接入(Unity与Android通信)
首先介绍一点关于Android与unity通信的知识: 完成通信主要靠unity中的class.jar包(在unity的安装目录下). 在unity中调用android的方法: jo.call(&qu ...
随机推荐
- 【转】【JLINK下载失败,STLINK下载失败万能解决方案】JLINK和STLINK都无法下载时的解决办法,此时芯片并没有报废
很多时候都会认为这个板子无法下载了,其实不是的,有解决办法. 原因如下: 由于客户设置的晶振频率和PLL配置错误时,就会出现这种问题,下载一次程序锁住一次板子,搞的人痛不欲生. 还有错误的外设配置,S ...
- 洛谷 P2466 Sue的小球 解题报告
P2466 [SDOI2008]Sue的小球 题目描述 Sue和Sandy最近迷上了一个电脑游戏,这个游戏的故事发在美丽神秘并且充满刺激的大海上,Sue有一支轻便小巧的小船.然而,Sue的目标并不是当 ...
- luogu2577/bzoj1899 午餐 (贪心+dp)
首先,应该尽量让吃饭慢的排在前面,先按这个排个序 然后再来决定每个人到底去哪边 设f[i][j]是做到了第i个人,然后1号窗口目前的总排队时间是j,目前的最大总时间 有这个i和j的话,再预处理出前i个 ...
- luogu2312 [NOIp2015]解方程 (秦九韶)
秦九韶算法:多项式$a_0+a_1x+a_2x^2+...+a_nx^n=a_0+x(a_1+x(a_2+...+(xa_n))..)$,这样对于一个x,可以在O(n)求出结果 为了避免高精度,我们同 ...
- Hadoop HDFS命令
hadoop fs -mkdir 创建HDFS目录 # hadoop fs -mkdir /data Hadoop fs -ls 列出HDFS目录 # hadoop fs -ls /data ha ...
- Elasticsearch 常见问题的解决思路
本文为es性能监控基础的扩展,大家可以先看下性能监控基础,熟悉下es的基本原理.为翻译性质文档,感谢原作者,原始文档地址 类似于汽车的运行方式,Elasticsearch旨在让用户快速上手和运行,而无 ...
- activity中访问内部fragment的函数
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCod ...
- Raspbian开启root账户
启用root账户 使用默认用户pi,密码raspberry登录树莓派 sudo passwd root #给root账户设置密码 sudo passws --unlock root #解除root账户 ...
- Scala进阶之路-并发编程模型Akka入门篇
Scala进阶之路-并发编程模型Akka入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Akka Actor介绍 1>.Akka介绍 写并发程序很难.程序员不得不处 ...
- LightOJ - 1246 Colorful Board(DP+组合数)
http://lightoj.com/volume_showproblem.php?problem=1246 题意 有个(M+1)*(N+1)的棋盘,用k种颜色给它涂色,要求曼哈顿距离为奇数的格子之间 ...