程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C# WinForm將其它應用程序窗體嵌入自己內部

C# WinForm將其它應用程序窗體嵌入自己內部

編輯:關於C#

這是最近在做的一個項目中提到的需求,把一個現有的窗體應用程序界面嵌入到自己開發的窗體中來,看 起來就像自己開發的一樣(實際上……跟自己開發的還是有一點點區別的,就是內嵌程序和宿主程序的窗口激 活狀態問題)。

在codeproject找到了一篇相關的文章 (http://www.codeproject.com/Articles/9123/Hosting-EXE-Applications-in-a-WinForm-project),雖然 可用,但是很不方便,於是重新設計編寫了一個類庫,用一個控件完成內嵌其它應用程序的功能。

直 接上圖先:

從打開Adobe Reader那張圖片可以看出來所謂的“內嵌程序和宿主程序的窗口激活狀態問題”。當內嵌程序窗口激活時,表 面上將其包裹起來的宿主窗口卻處於非激活的狀態。想隱藏這一點的話,把窗口的FormBorderStyle屬性設為 None吧,然後自己在窗口上畫關閉、最大化、最小化按鈕好了。

原作者的實現思路更能暴露本質,所 以這裡用原作者的代碼段解釋一下實現過程。

1、啟動要嵌入的應用程序進程

Process p = 

null; 
 try
 {
   // Start the process 
   p = System.Diagnostics.Process.Start(this.exeName); 
     
   // Wait for process to be created and enter idle condition 
   p.WaitForInputIdle(); 
     
   // Get the main handle
   appWin = p.MainWindowHandle; 
 } 
 catch (Exception ex) 
 { 
   MessageBox.Show(this, ex.Message, "Error"); 
 }

2、調用Windows API將啟動的應用程序窗口嵌入自定義的控件(作者用的是Panel控件)

// Put it into this form
 SetParent(appWin, this.Handle);//this在這裡是Panel控件
     
 // Remove border and whatnot
 SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
     
 // Move the window to overlay it on this window
 MoveWindow(appWin, 0, 0, this.Width, this.Height, true);

3、設置被嵌入的窗體大小隨宿主 窗體改變

protected override void OnResize(EventArgs e)
 {
   if (this.appWin != IntPtr.Zero)
   {
     MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
   }
   base.OnResize (e);
 }

4、設置被嵌入的窗體應用程序在宿主程序關閉時也關閉

protected override void 

OnHandleDestroyed(EventArgs e)
 {
   // Stop the application
   if (appWin != IntPtr.Zero)
   {
     // Post a colse message
     PostMessage(appWin, WM_CLOSE, 0, 0);
     
     // Delay for it to get the message
     System.Threading.Thread.Sleep(1000);
     
     // Clear internal handle
     appWin = IntPtr.Zero;
   }
   base.OnHandleDestroyed (e);
 }

原作者的代碼實際用起來是很不方便的,具體大家試試就知道,不細說了(反正我只學了學上面 的步驟,也不用他的庫)。

本人開發了一個比較實用的控件,使用起來也很簡單,只需三步。

首先,在窗體應用程序項目中引用類庫SmileWei.EmbeddedApp。

然後,在宿主窗體上拖一個 AppContainer控件,擺放好位置。(如果工具箱裡沒有AppContainer,就F6生成解決方案一下,然後再看就有 了。)

最後,告訴AppContainer控件,要嵌入的應用程序(*.exe文件)的絕對路徑(本人以使用OpenFileDialog 為例),命令AppContainer控件啟動之。

1 appContainer1.AppFilename = openEXE.FileName;
2 appContainer1.Start();

這個AppContainer控件有什麼好處呢?

1、原作者想到的Resize 和隨宿主程序關閉而關閉的問題,AppContainer都實現了。

2、AppContainer指定要嵌入的應用程序和 啟動是分開的,這樣更靈活,開發過程中也不會看到如下的情況了:開發的時候原作者的控件就“情不自禁” 地把內嵌程序加載進來了。

3、AppContainer防范了各種可能出錯的情形,例如禁止自己嵌入自己(死循環)、內嵌Console程序時提 示不能嵌入、參數為null或無效的檢驗等。

4、其它。例如,AppContainer裡面不會使用 Thread.Sleep(1000);這樣低端的句子來保證程序正確地嵌入(而且對於類似photoshop這樣啟動很慢的程序也 保證不了),而是通過Application.Ilde事件實現了在被嵌程序加載完畢後才將其窗體嵌入的技巧。

當然,有些應用程序是不能這麼自動化地嵌入進來的。因為程序啟動窗體和主窗體句柄不一樣,AppContainer 無法獲得主窗體句柄,所以無法自動嵌入。

為了解決這個問題,我在宿主窗體的狀態欄上設置了“句 柄嵌入”標簽,點擊“句柄嵌入”,你可以填入想嵌入的應用程序主窗體句柄,然後宿主窗體就可以嵌入它了 。

然後有同學就問了,我怎麼知 道想要嵌入的窗體句柄是多少啊?方法很多啦,我這裡也提供一個自己制作的小程序,大家可以在這裡下載: WindowDetective(窗口偵探)0.20.rar

界面是這個樣子的:

裡面“句柄:{1903014}”那一行就給出了本人正在用的Windows Live Writer的主窗體句柄。

用法很簡單,啟動這個程序後,它會自動檢測鼠標所在位置的窗體信息,顯示在窗口中。所以把鼠標 放在你想了解的窗體菜單欄上就OK了。QQ TM版也可以這樣嵌進來滴。(QQ嵌不進來,不知道騰訊在搞什麼)

大家還可以試試把QQ對話框嵌進來,很好玩哦~

我的源代碼都給出了 明確的注釋,類型、變量名也都規范易懂,在此不再多做解釋了,有疑問請留言吧O(∩_∩)O

本文所有 源代碼、可執行程序均可在下面列出的鏈接中下載到。

示例宿主程序及類庫源代碼:SmileWei.EmbeddedApp.rar

示例宿主程序可執行文件(及必需的類庫):SmileWei.EmbeddedApp.EXE. rar

窗口偵探(用於查看窗口句柄):WindowDetective(窗口偵探)0.20.rar

出處, http://www.cnblogs.com/bitzhuwei/archive/2012/05/24/SmileWei_EmbeddedApp.html

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved