在專案開發中,常遇到需將現有獨立視窗應用程式嵌入自家開發的 WinForm 介面,使其外觀彷彿原生開發。然而,內嵌程式與宿主程式的視窗啟動狀態仍存有細微差異(例如內嵌視窗啟動時,宿主視窗卻處於非啟動狀態)。
早期在 CodeProject 發現相關文章(Hosting EXE Applications in a WinForm project),雖可行但使用不便。因此重新設計封裝類庫,以單一控件完成嵌入功能。
以下展示嵌入 Adobe Reader 等程式的實際畫面:
從 Adobe Reader 畫面可見「視窗啟動狀態問題」:內嵌程式視窗啟動時,包裹它的宿主視窗卻非啟動狀態。若欲隱藏此差異,可將宿主視窗 FormBorderStyle 設為 None,並自行繪製關閉、最大化、最小化按鈕。
Process p = null;
try {
p = System.Diagnostics.Process.Start(this.exeName);
p.WaitForInputIdle();
appWin = p.MainWindowHandle;
} catch (Exception ex) {
MessageBox.Show(this, ex.Message, "Error");
}
SetParent(appWin, this.Handle);
SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
protected override void OnResize(EventArgs e) {
if (this.appWin != IntPtr.Zero) {
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
}
base.OnResize(e);
}
protected override void OnHandleDestroyed(EventArgs e) {
if (appWin != IntPtr.Zero) {
PostMessage(appWin, WM_CLOSE, 0, 0);
System.Threading.Thread.Sleep(1000);
appWin = IntPtr.Zero;
}
base.OnHandleDestroyed(e);
}
原作者程式碼使用不便,故開發 AppContainer 控件,僅需三步即可完成嵌入:
SmileWei.EmbeddedApp 類庫。AppContainer 控件至宿主視窗,調整位置(若未出現請先建置方案)。appContainer1.AppFilename = openEXE.FileName;
appContainer1.Start();
Application.Idle 事件而非 Thread.Sleep 確保嵌入時機,支援 Photoshop 等啟動緩慢程式。部分程式啟動視窗與主視窗控制代碼不同,導致無法自動嵌入。解決方法:在宿主視窗狀態列提供「控制代碼嵌入」功能,輸入目標主視窗控制代碼即可嵌入。
如何取得目標視窗控制代碼?提供自製工具 WindowDetective (窗口偵探) 0.20:
啟動後自動偵測滑鼠所指視窗資訊,將滑鼠移至目標視窗標題列即可獲得控制代碼(如圖所示 Windows Live Writer 控制代碼)。QQ TM 版亦可嵌入,但正式版 QQ 可能因防護機制無法嵌入。
原文出處:https://www.cnblogs.com/bitzhuwei/archive/2012/05/24/SmileWei_EmbeddedApp.html