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

C++ Firefox 组件拦截/操作 HTML DOM

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.51/5 (15投票s)

2007年9月28日

CPOL

4分钟阅读

viewsIcon

179344

downloadIcon

1569

本文使用一个简单的例子展示如何构建一个拦截/操作 DOM 的 Firefox 组件。

背景

我已经开发 BHO 组件几个月了。开发 BHO 组件很有趣。相比之下,Firefox 似乎非常令人沮丧。我认为第一个原因是,缺乏可供参考的示例和代码。其次,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);
// called as part of a largerDeleteAllCookies() function 
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。您可以在 www.xulplanet.com 上找到更多信息。

切入正题。现在,我想为 Firefox 构建一个 FormFiller。同时,由于以下原因,我不想使用 JavaScript 来完成这项工作:

  • JavaScript 会暴露您的代码。
  • 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_IMETHOD Nothing(nsIDOMWindow *domWindow); //.h file

NS_IMETHODIMP MyComponent::Nothing(nsIDOMWindow *domWindow) //cpp file

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

好的,一半的工作已经完成了。

另一半很简单。看看下面的代码,您就会明白了。

NS_IMETHODIMP MyComponent::Nothing(nsIDOMWindow *domWindow)
{
    nsEmbedString temp(L"test");
    nsEmbedString attribute(L"value");
    nsEmbedString id(L"id");
    nsEmbedString value(L"value");

    //The above declare some strings. 
    /* 
    Please note that the string in XPCOM is declared as either nsAString 
    or nsString or nsEmbedString Please refer to 
    https://mdn.org.cn/en/docs/XPCOM:Strings for more information
    */

    nsIDOMWindow* window; //you can use the parameter directly
    window=domWindow;
    nsCOMPtr<nsIDOMDocument> domDocument; 
    nsCOMPtr<nsIDOMElement> element;
    window->GetDocument(getter_AddRefs(domDocument)); //Get document
    domDocument->GetElementById(temp,getter_AddRefs(element)); 
    //Find target element, you also can use GetElementByTagName
    //to get a node list. Then loop through the node list.
    //Please refer to XULPlanet for more info
    //about nsIDOMDocument
    element->GetAttribute(id,value);
    //I get the value of "id" attribute
    //and fill it into "value attribute"
    element->SetAttribute(attribute,value);
    return NS_OK;
}

好的,以上就是您需要的所有代码了。

如何构建项目

我强烈推荐 http://www.iosart.com/firefox/xpcom/。我从那里学到了关于 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 类型库文件。

然后按照 http://www.iosart.com/firefox/xpcom/ 的说明进行操作。

调用组件

有两种方法可以调用该组件:

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

都一样。扩展是一个带有 JavaScript 的 XUL。请参考 http://www.borngeek.com/firefox/toolbar-tutorial/ 来了解其工作原理。

下面的 HTML 页面代码调用了该组件。

<HTML>
<SCRIPT  type="text/javascript">
function MyComponentTestGo() {
    try {
        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
        const cid = "@mydomain.com/XPCOMSample/MyComponent;1";
        obj = Components.classes[cid].createInstance();
        obj = obj.QueryInterface(Components.interfaces.IMyComponent);
    } catch (err) {
        alert(err);
        return; 
    }
    var res = obj.Nothing(window);}
</SCRIPT>
<BODY>
<BUTTON ONCLICK="MyComponentTestGo();" id="go">Go</BUTTON>
<input id="test" value="" />
</BODY>
</HTML>

结论

开发 Firefox 组件最大的问题是缺乏文档和代码。即使是 XPCOM 本身也存在同样的问题。但我认为情况会越来越好。通常,Mozillzine 上有一些有经验的人可以寻求帮助。

我希望这篇简单的文章能对那些在开发 Firefox 时感到沮丧的人有所帮助。如果您有任何评论或问题,请在此处留言。我将尽我所能回复您。

© . All rights reserved.