Unity 通過winAPI與Winform程序發消息(HoneyWell視頻)

需求:通過Unity啓動外部的一個winform程序,傳參數進行初始化。   程序啓動後,untiy通過winApi給啓動的程序發消息。

unity調用HoneyWellSDK顯示視頻,關閉的時候藏至後臺。(後續發現,honeywell能通過Rtsp的方式,直接調用視頻)

Untiy端:

    Process myprocess;//攝像頭程序進程
    public const int WM_COPYDATA = 0x004A; //進程發送信息標識,之前用別的不行,用這個winform才接收到消息

    public string HoneyWellWindowName = "HoneyWellVideoMonitor";

    /// <summary>
    /// 創建新進程
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="args"></param>
    private void CreateNewProcess(string args,string fileName="")
    {
        if(string.IsNullOrEmpty(fileName))
        {
            if (IsSDKInit) return;           
            fileName = Application.dataPath + "\\..\\release\\HUSSDKDemo.exe";
            if (!File.Exists(fileName))
            {
                UnityEngine.Debug.LogErrorFormat("path:{0} not exist!", fileName);
                return;
            }
            IsSDKInit = true;
        }       
        myprocess = new Process();
        ProcessStartInfo startInfo = new ProcessStartInfo(fileName, args);
        myprocess.StartInfo = startInfo;
        myprocess.StartInfo.UseShellExecute = false;
        myprocess.Start();
    }

    /// <summary>
    /// 開啓視屏程序
    /// </summary>
    /// <param name="args"></param>
    /// <returns></returns>
    private void StartProcess(string args)
    {
        try
        {
            string fileName = Application.dataPath + "\\..\\release\\HUSSDKDemo.exe";
            if (!File.Exists(fileName))
            {
                UnityEngine.Debug.LogErrorFormat("path:{0} not exist!", fileName);
            }
            if (myprocess == null)
            {
                UnityEngine.Debug.LogError("create myprocess.StartInfo");
                CreateNewProcess(args,fileName);
            }
            else if (myprocess.HasExited)
            {
                UnityEngine.Debug.LogError("Camera:myprocess.HasExited");
                CreateNewProcess(args,fileName);
            }
            else
            {

                //這一部分,好像沒有作用。根據名稱找窗口,還是爲0
                IntPtr hWnd = myprocess.MainWindowHandle; //獲取Form1.exe主窗口句柄
                int pId = -1;
                if (hWnd.ToInt32() == 0)
                {

                    //HoneyWellWindowName = "HoneyWellVideoMonitor"; 窗體名爲中文時,找不到。改成英文可以
                    pId = FindWindow(null, HoneyWellWindowName);                    
                }
                else
                {
                    pId = hWnd.ToInt32();
                }
                string sendString = args;
                byte[] sarr = System.Text.Encoding.Default.GetBytes(sendString);
                int len = sarr.Length;
                COPYDATASTRUCT cds;
                cds.dwData = (IntPtr)0;
                cds.cbData = len + 1;
                cds.lpData = sendString;
                ThreadManager.Run(()=> 
                {
                    //下方pid爲0的情況,所有程序的 DefWndProc方法,都能接收到Untiy發的信息,這也是需要優化的地方

                     SendMessage(pId, WM_COPYDATA, 0, ref cds); //SendMessage是同步的,考慮放在線程裏,防止卡住主線程

                     //想用PostMessage的方式,異步發送消息。但是測試沒成功,後續得再調整

                },()=> 
                {
                    UnityEngine.Debug.LogError("Show camera:" + args);
                },"");             
            }           
        }
        catch (Exception ex)
        {
            UnityEngine.Debug.LogError("Error : CameraVideoManage.StartProcess:" + ex.Message);
        }
    }
    private void OnDestroy()
    {

        //winform關閉時,攔截了關閉消息。默認讓它隱藏在後臺,所以關閉untiy時,通過進程把程序關了。
        if (myprocess != null) myprocess.CloseMainWindow();  //程序關閉識,把進程關閉。不然再打開程序,會有多個視頻進程
    }
    #region WinAPI

    [DllImport("User32.dll", EntryPoint = "FindWindow")]
    private static extern int FindWindow(string lpClassName, string lpWindowName);

    /// <summary>
    /// 根據句柄查找進程ID
    /// </summary>
    /// <param name="hwnd"></param>
    /// <param name="ID"></param>
    /// <returns></returns>
    [System.Runtime.InteropServices.DllImport("User32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);


    /// <summary>
    /// 使用COPYDATASTRUCT來傳遞字符串
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct COPYDATASTRUCT
    {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;
    }

    //消息發送API
    [DllImport("User32.dll", EntryPoint = "SendMessage")]
    public static extern int SendMessage(
        IntPtr hWnd,        // 信息發往的窗口的句柄
        int Msg,            // 消息ID
        int wParam,         // 參數1
        int lParam          //參數2
    );

    //消息發送API
    [DllImport("User32.dll", EntryPoint = "SendMessage")]
    public static extern int SendMessage(
        int hWnd,        // 信息發往的窗口的句柄
        int Msg,            // 消息ID
        int wParam,         // 參數1
        ref COPYDATASTRUCT lParam  //參數2
    );

    //消息發送API
    [DllImport("User32.dll", EntryPoint = "PostMessage")]
    public static extern int PostMessage(
        IntPtr hWnd,        // 信息發往的窗口的句柄
        int Msg,            // 消息ID
        int wParam,         // 參數1
        int lParam            // 參數2
    );


    //異步消息發送API
    [DllImport("User32.dll", EntryPoint = "PostMessage")]
    public static extern int PostMessage(
        int hWnd,        // 信息發往的窗口的句柄
        int Msg,            // 消息ID
        int wParam,         // 參數1
        ref COPYDATASTRUCT lParam  // 參數2
    );


    #endregion

 

 

WinFrom端:

程序啓動入口,通過unity打開程序,能夠收到傳遞的參數:

static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            ShowLog(args);
        }
        static void ShowLog(string[] args)
        {
            args = new string[] {"192.168.1.1|admin|admin|dddddd" };
            if (args.Length <= 0)
            {
                Application.Run(new Form_SDKDemo());
            }
            if (args.Length == 1)
            {
                //MessageBox.Show("成功啓動,參數爲" + args.ToString());
                SingleLiveForm form = new SingleLiveForm(args);
                Application.Run(form);
            }
        }
    }

功能界面:SingleLiveForm  只放部分用到的代碼

 /// <summary>
        /// 使用COPYDATASTRUCT來傳遞字符串
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

 

        private static int WMA_InterPro = 0x004A;
        protected override void DefWndProc(ref Message m)
        {
            if (m.Msg == WMA_InterPro)
            {
                COPYDATASTRUCT cds = new COPYDATASTRUCT();
                Type t = cds.GetType();
                cds = (COPYDATASTRUCT)m.GetLParam(t);
                string receiveInfo = cds.lpData;
                this.Show();
                this.ShowInTaskbar = true;
                string[] values = receiveInfo.Split('|');
                if (values.Length < 4)
                {
                    return;
                }
                string devGuid = values[3];
                ShowVideo(devGuid);
            }
            else
            {
                base.DefWndProc(ref m);
            }
        }

 

 private void SingleLiveForm_FormClosing(object sender, FormClosingEventArgs e)
        {

            //取消關閉窗口 ,隱藏至後臺
            e.Cancel = true; 
            this.Hide();   
            this.ShowInTaskbar = false;
        }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章