65.9K
CodeProject 正在变化。 阅读更多。
Home

在单独进程中运行 AxWebBrowser 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (2投票s)

2014 年 11 月 17 日

CPOL

4分钟阅读

viewsIcon

21017

downloadIcon

714

浏览器控件在混合应用程序开发中扮演着重要角色,当浏览器控件使用时间较长时,其内存占用会逐渐增加。本文介绍了一种将浏览器控件托管在单独的进程中,可以根据需要加载/卸载的方法。

引言

该示例利用 Microsoft AddIn Framework (MAF) 将浏览器控件托管在单独的进程中。这有助于确保导航到的网站的内存泄漏、错误和异常被隔离并在单独的进程中运行。这可以避免 Windows WPF 父进程因浏览的网站的任何问题而崩溃。

此应用程序以 URL 作为输入,并在单独的进程中导航到指定的 URL。宿主应用程序是一个 WPF Windows 应用程序。AddIn 浏览器控件是 axWebBrowser 的 WPF 包装器,它运行在名为 AddInProcess32 的单独进程中。它支持通过方法调用从宿主应用程序到 AddIn 的双向通信,以及通过事件机制从 AddIn 到宿主应用程序的通信。

Microsoft AddIn Framework 基础知识

对于 MAF 新手用户,请访问以下 MSDN 文档,以了解管道开发工作方式的基本架构。

浏览器宿主应用程序

加载浏览器:在单独的 AddIn 进程中加载浏览器控件,并在指定的框架内进行绘制。

卸载浏览器:卸载浏览器控件并终止 AddIn 进程。

导航:将浏览器导航到指定的 URL。

URL 列表框:显示从 BeforeNavigate 事件导航到的 URL。

从列表导航:选择一个 URL,然后单击此按钮导航到选定的 URL。

使用代码

在管道架构的每个层中都有七个项目引用。

项目 1:AppContracts

定义接口 IBrowserAddInContract ,该接口派生自 IContract,并用 AddInContract 进行属性标记。IBrowserAddInContract 是在 AddIn 中实现的接口,用于在进程外使用 AddIn 框架运行浏览器。此接口有两个方法:一个用于获取句柄,另一个用于导航到指定 URL。

在导航之前,通知宿主它将导航到的 URL。这是基于事件实现的。使用 BeforeNavigateEventAdd 和 BeforeNavigateEventRemove 来添加/删除事件处理程序。

[AddInContract]
public interface IBrowserAddInContract : IContract
{
	INativeHandleContract GetUI();
	void Navigate(string url, string cookie);
	void BeforeNavigateEventAdd(INavigateEventHandler handler);
	void BeforeNavigateEventRemove(INavigateEventHandler handler);
}

定义两个接口:一个用于处理 AddIn 在宿主应用程序中引发的事件,另一个用于传递事件参数。

public interface INavigateEventHandler : IContract
{
  bool Handler(INavigateEventArgs args);
}
public interface INavigateEventArgs : IContract
{
        string url
        {
            get;
        }
}

项目 2:HostSideAdapter

在此项目中,引用 AppContracts BrowserHostView 项目。实现两个类:一个用于调用 ContractToHost 的方法,另一个用于调用 HostToContract 的方法。

ContractToView:从 BrowserHostView.BrowserAddIn 派生类 IsolatedElementContractToViewHostAdapter。用 HostAdapter 对类进行属性标记。声明一个事件和事件处理程序变量。通过组合引用 AppContract。


Contracts 实例由框架分配。该类执行 4 个功能:
- 实现 GetUI。
- 实现 Navigate。
- 触发 _Navigate 以调用事件。
- 添加和删除事件函数。

ViewToContract:从 AppContracts 接口派生类。实现定义的所有方法。

项目 3:AddInSideAdapter

在此项目中,引用 AppContracts BrowserAddInView 项目。
在此项目中需要处理的一个重要事项是用于运行事件的分派器。这是在 AppDispatcher 类中完成的。


ViewToContract:此类依赖 AppDispatcher 来调用事件。从 AppContracts 接口派生类。用 AddInAdapterAttribute 对类进行属性标记。实现定义的所有方法。

ContractToView:通过组合引用 AppContract。

项目 4 和 5:BrowserAddInView 和 BrowserHostView

两个项目都将视图类定义为抽象的。AppContracts 中的所有方法都已定义。仅将 AddInView 属性化为 [AddInBase]

public abstract class BrowserAddIn
{
    public abstract event System.EventHandler<NavigateEventArgs> Navigating;
 public abstract FrameworkElement GetUI();
 public abstract void Navigate(string url, string cookie);
}

项目 6:BrowserHostApplication

在此项目中,引用 BrowserHostView。如 LoadAddIn 方法中所述,找到 AddIn 的特定类型。使用 AddInStore 静态方法 FindAddIns 在特定路径下检索机器上可用的 AddIns。创建 AddIn 作为单独的进程,如下所示:

private void LoadAddIn()
{
	String path = Environment.CurrentDirectory;
        String[] warnings = AddInStore.Rebuild(path);
        IList<AddInToken> tokens = AddInStore.FindAddIns(typeof(BrowserHostView.BrowserAddIn), path);
        addins = new List<BrowserHostView.BrowserAddIn>();

        ap = new AddInProcess();
        ap.Start();
        AddInStore.FindAddIns(typeof(BrowserHostView.BrowserAddIn), PipelineStoreLocation.ApplicationBase);
        addInInstance = tokens[0].Activate<BrowserHostView.BrowserAddIn>(ap,
                                                                                  AddInSecurityLevel.FullTrust);
        addins.Add(addInInstance);
        addInIndex = dp.Children.Add(c.GetUI());
        addInInstance.Navigating += new EventHandler<BrowserHostView.NavigateEventArgs>(usercontrol_BeforeNavigate);
}

 

要卸载 AddIn,请删除事件并关闭进程,如下所示:

private void UnloadAddIn()
{
    addInInstance.Navigating -= usercontrol_BeforeNavigate;
    dp.Children.RemoveAt(addInIndex);
    addInInstance = null;
    ap.Shutdown();
}

 

项目 7:BrowserAddIn

声明一个新类 BrowserAddInCode 并将其属性化为 [System.AddIn.AddIn("BrowserAddIn")]。实现抽象视图类及其方法 GetUINavigate NavigatingEventCall。此类实例化 BrowserControl

参考文献

所有这些都是通过引用以下文章实现的。这使我能够在我的项目中完成我正在寻找的任务。感谢文章中提供的贡献和示例。

Jack Gudenkauf 和 Jesse Kaplan 的 .NET Application Extensibility, Part 2

Chango V. - MSFT 的 Hosting WPF UI cross-thread and cross-process

Jesse Kaplan 的 AppDomain Isolated WPF Add-Ins 

关注点

AddIn 架构提供了一种非常快速的方法,可以使用很少的代码行将任何控件托管在单独的进程中,而无需担心同步和进程间通信。

 

© . All rights reserved.