使用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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM