在过去的几个月里,开发浏览器扩展组件变得越来越流行。对于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来完成这项工作,原因如下:
因此,这里有两种解决方案:
选择了第二种。尽管在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的XUL。