开发Firefox扩展组件的挑战与实践

在过去的几个月里,开发浏览器扩展组件变得越来越流行。对于Internet Explorer,开发BHO组件相对容易,但Firefox的开发过程却显得有些令人沮丧。首先,缺乏足够的示例和代码供参考。其次,Mozilla提供的文档远不如Microsoft那样丰富。尽管如此,并不责怪Mozilla,毕竟它是一家小公司,而且其产品是开源的。

在接下来的部分,将通过一个示例展示如何在Firefox中拦截DOM元素,并像在BHO中那样操作它们。在继续阅读本文之前,强烈推荐您阅读以下两篇文章:

第一篇文章教您如何构建一个组件;第二篇文章教您如何制作一个扩展。本文的示例基于第一篇文章中的示例。花了整整两周时间学习Firefox以及XPCOM的运作方式。将使用这个简单的图表来展示结构:

UI --> XPConnect --> XPCOM

您所看到的大多数插件都是扩展,例如工具栏等。它们大多数是用JavaScript编写的。如果您不想触及一些高级组件,例如工具栏只导航窗口等,那么这是可以的。但如果您想进一步发展,您必须调用在XPConnect或XPCOM下构建的组件。

以下是Mozilla官方教程中的一个简单的Cookie管理器示例:

var cookiemanager = Components.classes["@mozilla.org/cookiemanager;1"].getService(); cookiemanager = cookiemanager.QueryInterface(Components.interfaces.nsICookieManager); function FinalizeCookieDeletions() { for (var c = 0; c < deletedCookies.length; c++) { cookiemanager.remove(deletedCookies[c].host, deletedCookies[c].name, deletedCookies[c].path); } deletedCookies.length = 0; }

这个过程很容易理解。获取组件服务,然后调用组件下的方法。这部分的技术含量并不高。但是,组件是如何工作的则是另一个问题。

Firefox基于Gecko SDK。基本上,所有以"ns"开头的API,例如nsIWebBrowser(类似于BHO中的IWebBrowser),都来自Gecko SDK。您可以在上找到更多信息。

现在,想为Firefox构建一个表单填充器。同时,不想使用JavaScript来完成这项工作,原因如下:

因此,这里有两种解决方案:

  • 使用C++构建Firefox扩展。
  • 使用C++构建Firefox组件。

选择了第二种。尽管在Firefox上注册一个组件比注册一个扩展要复杂得多。但在调用核心组件和操作数据时,它要安全得多。

如何做到这一点

就像BHO一样,有一个nsIWebBrowser提供了任何基于XPCOM的浏览器(如SeaMonkey或NetScape)的API。通过nsIWebBrowser,可以得到nsIDOMWindow->nsIDOMDocument->nsIDOMElement,然后填写想要的信息。然而,这在Firefox中不起作用。原因很简单:Firefox不使用nsIWebBrowser。当您通过组件管理器调用nsIWebBrowser时,它会返回一些随机的无用信息。

不知道他们为什么要这样做。也许是因为Firefox的多标签结构。所以问题就在这里。必须在进一步操作之前初始化nsIDOMWindow

为了节省您在Google上搜索所有信息的时间,请允许提供一个简单的函数原型:

var res = obj.Nothing(window);

其中Nothing是用于填充表单的方法。"window"是浏览器窗口对象,JavaScript自然拥有。

所以,在您的代码中,您需要声明方法如下:

NS_IMETHODIMP MyComponent::Nothing(nsIDOMWindow *domWindow)

当JavaScript将窗口传递给方法时,它将自动转换为nsIDOMWindow

一半的工作已经完成。另一半很容易。看看以下代码,您就会明白了。

NS_IMETHODIMP MyComponent::Nothing(nsIDOMWindow *domWindow) { nsEmbedString temp(L"test"); nsEmbedString attribute(L"value"); nsEmbedString id(L"id"); nsEmbedString value(L"value"); // 上面声明了一些字符串。 nsIDOMWindow* window; // 您可以直接使用参数 window = domWindow; nsCOMPtr domDocument; nsCOMPtr element; window->GetDocument(getter_AddRefs(domDocument)); // 获取文档 domDocument->GetElementById(temp, getter_AddRefs(element)); // 查找目标元素,您也可以使用GetElementByTagName获取节点列表。然后遍历节点列表。 // 有关nsIDOMDocument的更多信息,请参考XULPlanet element->GetAttribute(id, value); // 获取了"id"属性的值 // 并将其填充到"value"属性中 element->SetAttribute(attribute, value); return NS_OK; }

以上是您需要的所有代码。

如何构建项目

强烈推荐。在那里学到了很多关于XPCOM组件的知识。要开始您的项目,您需要有一个.idl文件。

#include "nsISupports.idl" #include "nsIDOMWindow.idl" [scriptable, uuid(_YOUR_INTERFACE_GUID_)] interface IMyComponent : nsISupports { void Nothing(in nsIDOMWindow domWindow); };

然后下载XPIDL.exe以生成.h文件:

xpidl -m header -I_DIR_ IMyComponent.idl 将创建IMyComponent.h头文件。 xpidl -m typelib -I_DIR_ IMyComponent.idl 将创建IMyComponent.xpt类型库文件。

然后按照进行操作。

调用组件

有两种方式可以调用组件:

  • 通过扩展调用
  • 从页面上的JavaScript调用

这两者是一样的。扩展是一个带有JavaScript的XUL。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485