出處:http://www.dotblogs.com.tw/larrynung/archive/2013/02/23/91903.aspx
首先準備個很簡易的Browser主UI,上方放一個內建的TabControl,而下方則是放置個按鈕,期望使用時按下下面的按鈕上方就可以加入一頁瀏覽器分頁。
另外還要準備一個瀏覽器頁面用來讓我們內嵌到瀏覽器分頁中。
接著進入程式的撰寫,這邊筆者透過Command Line Parser去做命令列參數處理。當程式透過滑鼠點擊開啟,預設是沒有帶任何的命令列參數,這時叫出主要的表單。若是有帶特定的參數,則改叫出瀏覽器頁面讓已開啟的程式嵌進瀏覽器分頁。
02 | static void Main( string [] args) |
04 | Application.EnableVisualStyles(); |
05 | Application.SetCompatibleTextRenderingDefault( false ); |
07 | var options = new Options(); |
08 | ICommandLineParser parser = new CommandLineParser(); |
09 | if (parser.ParseArguments(args, options)) |
11 | m_ReceiverHandel = (IntPtr)options.Handle; |
12 | if (options.IsBrowser) |
14 | var browserTab = new WebBrowserPage() |
16 | StartPosition = FormStartPosition.Manual, |
23 | browserTab.TextChanged += browserTab_TextChanged; |
25 | Application.Run(browserTab); |
30 | Application.Run( new MainForm()); |
而主頁面下方加入瀏覽器分頁的按鈕這邊,我們需要建立一個TabPage,並將
[C#]如何在程式中內嵌其它應用程式整理好的ApplicationHost元件放置於其中,帶入當前的執行擋位置以及特定的參數,讓ApplicationHost幫我們帶出瀏覽器分頁並嵌進元件內。(這邊因為瀏覽器分頁的Process若發生異常時我們需要關閉對應的分頁,所以必須要在ApplicationHost.ProcessUnLoaded事件觸發時做關閉分頁的動作。)
01 | private void btnAddTab_Click( object sender, EventArgs e) |
03 | var tabpage = new TabPage(); |
04 | tabControl1.TabPages.Add(tabpage); |
06 | var host = new ApplicationHost() |
08 | File = Application.ExecutablePath, |
09 | Arguments = string .Format( "-b -h {0}" , this .Handle), |
10 | HideApplicationTitleBar = true , |
14 | host.ProcessLoaded += host_ProcessLoaded; |
15 | host.ProcessUnLoaded += host_ProcessUnLoaded; |
17 | tabpage.Controls.Add(host); |
到這邊為止,這個簡易的瀏覽器已經具備了類似的效果了,但仍美中不足,因為瀏覽器分頁與瀏覽器主視窗之間並無法溝通,所以運行起來還是怪怪的,離Chrome的架構也還有一點距離。因此我們必須將IPC給加上去,這邊可以用很多方法來達成,像是Memory-mapped file、Named pipe...,這邊筆者為了方便選用了比較一般的SendMessage方式來做。
因為這邊只是個嘗試,並沒有想做到多強大、多複雜,這邊筆者只將顯示瀏覽的網頁Title給稍稍補上,在瀏覽器頁面那邊Title變動時主動發送訊息給瀏覽器主視窗。
01 | static void browserTab_TextChanged( object sender, EventArgs e) |
03 | var browserTab = sender as WebBrowserPage; |
04 | var buffer = Encoding.Default.GetBytes(browserTab.Text); |
06 | var cds = new CopyDataStruct(); |
07 | cds.cbData = buffer.Length; |
08 | cds.dwData = browserTab.Handle; |
09 | cds.lpData = Marshal.AllocHGlobal(buffer.Length); |
11 | Marshal.Copy(buffer, 0, cds.lpData, buffer.Length); |
13 | SendMessage(m_ReceiverHandel, WM_COPYDATA, 0x401, ref cds); |
當瀏覽器主視窗收到瀏覽器頁面送過來的訊息,會將收到的Title替換到對應的分頁上。
01 | protected override void WndProc( ref Message m) |
03 | if (m.Msg == WM_COPYDATA && m.WParam == (IntPtr)0x401) |
05 | var cds = (CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof (CopyDataStruct)); |
07 | m_HostPool[cds.dwData].Parent.Text = Marshal.PtrToStringAnsi(cds.lpData, cds.cbData); |
整個簡易的瀏覽器做到這邊就已經完成了,程式運行起來會像下面這樣,每一個分頁都會是一個Process,各分頁都會有當前瀏覽的網站名稱。
若某頁面的Process不慎毀壞。
該分頁會自動關閉,且不會影響到整個程式的運作。
沒有留言:
張貼留言