zoukankan      html  css  js  c++  java
  • 使用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 = 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;//最大缓冲长度  
    
            //数据包头配合使用  
            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(186, '/'));
                    IntPtr pData = Marshal.AllocHGlobal(2 * bytes.Length);
                    Marshal.Copy(bytes, 0, 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 > 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;
            }

    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 = 0; 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 = 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 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 - wParam); caches.Add(str); if (caches.Count > 16) caches.RemoveAt(0); } if (CallNextProc) { return CallNextHookEx(idHook, nCode, wParam, lParam); } else { return CallNextHookEx(idHook, nCode, wParam, lParam); } } catch (Exception ex) { Debug.Log(ex.Message); return 0; } } }

    直接将脚本挂在某个物体上,然后注意的是发布后程序的名字(运行exe在窗口标题栏显示的名字),因为发送端是通过这个名字来找到该窗口的。

     运行的效果如下:

    注意,由于程序中用到的unsafe,不安全代码,因此要讲工程设置为允许不安全代码,而unity中则需要在工程Assets的根目录创建文本文件,内容设置:-unsafe,注意不要有多余的空格什么的,然后文件复制4分,文件名分别为:us.rsp、smcs.rsp、gmcs.rsp

     、csc.rsp、boo.rsp,其实不是全部都要,每个针对一种语言的不安全代码,文件创建好了之后要重启一下unity。

  • 相关阅读:
    在Win7 x64环境中将World Wind Java SDK 2.1.0嵌入到Eclipse中的方法
    WW中文地名标注:输出*.wwp和*.wpl文件
    [转]Microsoft Robotics Studio:微软仿真机器人集成开发环境,简称MSRS
    C#中定义类时关于CLSCompliant属性的声明
    Android Studio中使用Java+OpenGL ES创建Android项目
    [转]使用Unity进行3D开发的思路和主要技术优势
    在C++中实现委托事件的方法
    VS2008新建MFC程序时提示:当前页面的脚本发送错误 不是有效的Win32应用程序的解决办法
    [Web 前端] mockjs让前端开发独立于后端
    [Web 前端] 如何构建React+Mobx+Superagent的完整框架
  • 原文地址:https://www.cnblogs.com/mr-yoatl/p/7523835.html
Copyright © 2011-2022 走看看