[C#] Winform 同一支App裡面不同的視窗有不同的Process (2)

2017-06-14

接續上篇 Winform 同一支App裡面不同的視窗有不同的Process (1) ,我們繼續實作
Image 029
接下來我們要製作一個PrcessAgent 來啟動 FormA , FormB  ,因為他必須是一個MdiChild 所以我將它設定繼承Form ,當然如果你設計是要放在tabcontrol 裡面 可能你可以繼承usercontrol 等物件

ProcessAgent :

using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace MutiProcessWindows
{
    public partial class ProcessAgent : Form
    {
        #region Win32 API

        //https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms633541(v=vs.85).aspx
        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        //https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms633534(v=vs.85).aspx
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

        //https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx
        [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
        private static extern long SetWindowLong(IntPtr hwnd, int nIndex, int dwNewLong);

        #endregion


        #region Const
        //請參考 https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms633591(v=vs.85).aspx
        private const int GWL_STYLE = -16;
        private const int WS_VISIBLE = 0x10000000;
        #endregion


        public Process MProcess { get; set; }

        public ProcessAgent(string param)
        {

            //初始化Process ,並且設定執行自己exe 但是有帶參數
            //param 可傳入 -forma, -formb
            MProcess = new Process()
            {
                SynchronizingObject = this,
                StartInfo = new ProcessStartInfo()
                {
                    FileName = Application.ExecutablePath,
                    Arguments = param
                }
            };
            //啟動
            MProcess.Start();


            InitializeComponent();
        }

        private void ProcessAgent_Load(object sender, EventArgs e)
        {

            //https://msdn.microsoft.com/zh-tw/library/system.diagnostics.process.waitforinputidle(v=vs.110).aspx
            //讓 Process 元件等候相關聯處理序進入閒置狀態。
            MProcess.WaitForInputIdle();
            while (!MProcess.HasExited && MProcess.MainWindowHandle == IntPtr.Zero)
            {
                Application.DoEvents();
                Thread.Sleep(100);
            }

            //取得或設定是否應該在處理序終止時引發事件
            MProcess.EnableRaisingEvents = true;
            //設定裡面的視窗被關掉時,此中介曾的ProceeAgent 所以要處理的
            MProcess.Exited += M_Process_Exited;

            var handle = MProcess.MainWindowHandle;

            //將發動的handle 爸爸設成此中介層
            SetParent(handle, this.Handle);
            //設定該發動handle(視窗) 顯示樣式
            SetWindowLong(handle, GWL_STYLE, WS_VISIBLE);

            //移動至相關位置
            MoveWindow(handle, 0, 0, (this.MdiParent as Form).Width, (this.MdiParent as Form).Height, true);

        }

        private void M_Process_Exited(object sender, EventArgs e)
        {
            //當然就是把自己關掉
            this.Close();
        }
    }
}

這裡面我都寫上註解跟加上參考的網址,基本上流程是爸爸(Form1) 產生一個新的ProcssAgent(Form),但是這Form 只是一個中介層,他將啟動自己因為帶參數的關係所以用一個Process 啟動了FormA 之後呼叫Win32 把FormA handler的爸爸設成自己(ProcessAgent),因為 Prorcess隸屬於Form1的並且設定為Mdi Child 而做到此效果,Form1 呼叫 FormA 的 Code :
            var processAgent = new ProcessAgent("-forma");
            processAgent.MdiParent = this;
            processAgent.Show();


之後我故意在FormA 裡面製作一個Exception ,按下結束後回復到只有Form1的狀態,並非整個程式都被結束,大致上這案例寫到這邊結束,如果有不懂的下面有原始碼提供。

這邊因為專案要用到所以那時候參考的文件很多,這邊因為遺失所以都沒有整理起來參考到那些大大的,但是可以確定的是蹂躪哥幫我很多忙
這邊是他的網站 : http://larrynung.github.io/2013/11/06/bf1439a5-abbc-4b6e-896a-0b115119f3e7/ 這篇給我幫助也很大,很值得參考一下。

soruce : https://github.com/donma/MutiProcessWindows


當麻許的超技八 2014 | Donma Hsu Design.