C# WPF 窗體傳遞消息


 對於存在窗體的WPF程序(或者說,起碼在任務欄上有個圖標,即ShowInTaskbar = true),互相傳遞消息是很容易的。

步驟:

1,尋找窗體的句柄

2,運用windows API: SendMessage或PostMessage

3,目標窗體收到消息

 

這里的代碼,展示了一個APP不希望多開所以在啟動時檢查是否存在一個已經運行的進程。如果進程已經存在,則給對方發送消息並結束自身。

1.判斷/獲取已經運行的實例

       /// <summary>
        /// 獲取當前exe文件的是否已經在電腦上運行了一個實例,如果是,則返回那個實例的Process;如果否,就返回null;
        /// 如果有窗體,可以通過process.MainWindowHandle獲取窗體的句柄,如果沒窗體(ShowInTaskbar = false),則句柄為空
        /// </summary>
        public static Process GetCurrentExeProcess()
        {
            Process targetProcess = null;

            Process currentProcess = Process.GetCurrentProcess();
            string exeName = string.Format("{0}.exe", currentProcess.ProcessName);
            //PTZ.Tracer.AppLog.Info("$$$$$Get Current Process Successfully, current process exe: {0}", exeName);

            try
            {
                Process[] aryProcess = Process.GetProcessesByName(currentProcess.ProcessName);

                //PTZ.Tracer.AppLog.Info("$$$$$Get aryProcess Successfully, aryProcess count: {0}", aryProcess.Count());
                foreach (Process process in aryProcess)
                {
                    if (process.Id != currentProcess.Id && process.ProcessName == currentProcess.ProcessName)
                    {
                        targetProcess = process;
                        //PTZ.Tracer.AppLog.Info("$$$$$Get MainWindowHandle Successfully, hWnd: {0}", hWnd);
                        break;
                    }
                }
            }
            catch (System.PlatformNotSupportedException pEx)
            {
                //PTZ.Tracer.AppLog.Error("$$$$$GetCurrentWindowsInstanceHandle exception:", pEx);
            }
            catch (System.InvalidOperationException iEx)
            {
                //PTZ.Tracer.AppLog.Error("$$$$$GetCurrentWindowsInstanceHandle exception:", iEx);
            }
            catch (System.ComponentModel.Win32Exception win32Ex)
            {
                //PTZ.Tracer.AppLog.Error("$$$$$GetCurrentWindowsInstanceHandle exception:", win32Ex);
            }

            return targetProcess;
        }

但是這個方法在某些奇怪權限設置的電腦上會遭遇UnauthorizedException,所以,如果只是想獲取窗體句柄的話,還可以將上述方法的Try & Catch部分換成下面的代碼:

            try
            {
                string wmiQueryString = string.Format("SELECT ProcessId, Handle,ExecutablePath,Name FROM Win32_Process WHERE ProcessId != {0} AND Name = '{1}'", currentProcess.Id, exeName);
                using (var searcher = new ManagementObjectSearcher(wmiQueryString))
                {
                    using (var results = searcher.Get())
                    {
                        ManagementObject mo = results.Cast<ManagementObject>().FirstOrDefault();
                        if (mo != null)
                        {
                            string s = (string)mo["ExecutablePath"];
                            string handleStr = (string)mo["Handle"];
                            string sss = (string)mo["Name"];
                            Tracing.Trace.Information("¥*¥ManagementObjectSearcher, name: {0} Handle: {1} Path: {2}", sss, handleStr, s);

                            int handle = int.Parse(handleStr);
                            Process p = Process.GetProcessById(handle);
                            hWnd = p.MainWindowHandle;
                            isRunExist = true;
                            Tracing.Trace.Information("¥*¥ManagementObjectSearcher, hWnd: {0}", hWnd);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Tracing.Trace.Error("ManagementObjectSearcher exception:", e);
            }

2.注冊WindowsAPI

        #region Dll Imports

        [DllImport("user32.dll")]
        static extern IntPtr PostMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);

        public const uint WM_APP = 0x9112;////0x8001~0xBFFF,隨意#endregion Dll Imports

3.修改App.OnStartup方法

當程序啟動,就需要檢測實例。如已有實例運行,則發送消息;如沒有,則繼續正常運行。所以我們需要修改Appxaml.cs的OnStartup方法:

 
         
protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            Process targetProcess = SingleExeHelper.GetCurrentExeProcess();

            if (targetProcess!=null)//Software has been running...
            {
//currentHandle通過targetProcess.MainWindowHandle得到
                PostMessage(currentHandle,WM_APP, IntPtr.Zero, IntPtr.Zero);
                Environment.Exit(0);//Software has been running, close this
 } else { //do nothing } }
 
         

 

 

 

4.主窗體監聽消息:

       protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            ((HwndSource)PresentationSource.FromVisual(this)).AddHook(myHook);

            //HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
            //source.AddHook(new HwndSourceHook(myHook));
        }

        private IntPtr myHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            int m = (int)App.WM_APP;
            if (msg == m)
            {
                System.Windows.MessageBox.Show("haha");
            }
            return IntPtr.Zero;
        }

 


免責聲明!

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



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