为 Mozilla Firefox 创建新协议(C++)






4.31/5 (11投票s)
2005年2月18日
4分钟阅读

96620

1186
为 Firefox 创建新协议。
引言
本文将向您展示如何为 Mozilla Firefox 浏览器创建新协议。Mozilla Firefox 支持通用的 Web 协议,例如 HTTP 和 FTP,并且还支持 Chrome 等自己的协议。有时需要为您的项目创建自定义协议,该协议将插入到现有的 Firefox 安装中。
要创建新协议,您需要实现一个 XPCOM 组件。XPCOM 非常类似于 MS COM(本文不涵盖 XPCOM 的基础知识,您可以在网上找到许多关于 XPCOM 的优秀文章和在线书籍)。您可以使用 JavaScript 或 C++ 来实现 XPCOM。我找到了一篇由 Doron Rosenberg 撰写的非常有用的文章,其中介绍了如何使用 JavaScript 为 Mozilla 构建新协议。
在本文中,我们将使用 C++ 来构建协议的 XPCOM。本文的目的是提供一个非常简单的自定义协议示例,该协议用 C++ 编写,当您急需为 Mozilla Firefox 创建自定义协议时,可以重复使用大部分代码,并专注于协议功能逻辑,而不是到处搜索 Mozilla 协议的基本框架。
您可以在Mozilla 网站上找到 C++ 实现协议的另一个地方,但它稍微复杂且文档较少。
本示例协议的作用是什么?
本文的示例将构建“find:”协议,该协议将使用用户的默认搜索引擎来发起搜索,类似于 Doron Rosenberg 用 JavaScript 创建的“x-search:”协议。
当此协议安装在 Mozilla Firefox 中时,可以通过输入以下内容来调用它:
find:<search term>
或者
find://<search term>
到 URL 栏并按 Enter。
如何安装此协议?
只需下载文件“findprotocol.xpi”并用 Mozilla Firefox 打开它。Firefox 将其作为新协议安装。.xpi 文件就是一个重命名为 .xpi 的 .zip 文件。
或者,您可以将 XPCOM(这是一个 DLL 文件)复制到现有 Mozilla Firefox 安装的“components”文件夹中,然后从“C:\Documents and Settings\<user>\application Data\Mozilla\Firefox\Profiles\<wtimmm.default>" 中删除“Compreg.dat”文件,并重新启动 Firefox,Firefox 将注册新的 XPCOM DLL。
如何编译源代码?
此示例是在安装了 Service Pack 5 的 VC++ 6 中编译的。您需要构建 Mozilla Firefox,因为构建 Firefox 后,您将获得创建 XPCOM 所需的所有头文件和库。构建 Mozilla 并非易事,您可以在网上找到许多有关构建 Mozilla 的指南。构建完成后,它将生成一个名为“Dist”的文件夹,其中包含所有需要与您的代码链接以构建此文件的库和头文件。
注意:- 此代码在警告级别 3 下可以干净地编译,没有任何警告。在警告级别 4 下会出现警告。
使用代码
要创建新协议,您必须实现 nsIProtocolHandler
接口。协议处理程序是实现 nsIProtocolHandler
的类。它负责向网络库返回关于协议的基本信息(例如默认端口和 URI 格式),并负责创建适当类型的通道来处理请求。
以下是在 nsFindHandler.h 中实现的:
#ifndef nsFindHandler_h___ #define nsFindHandler_h___ #include "nsIProtocolHandler.h" #define FIND_PORT -1 //this is the UUID #define NS_FINDHANDLER_CID \ { 0x7F1D8DA4, 0x668F, 0x4c3c, \ {0xBD, 0x7B, 0xEA, 0x95, 0xB2, 0x8D, 0x5A, 0xD0} } #define kPROTOCOL_CONTRACTID "@mozilla.org/network/protocol;1?name=find" #define kIOSERVICE_CONTRACTID "@mozilla.org/network/io-service;1" class nsFindHandler : public nsIProtocolHandler { public: NS_DECL_ISUPPORTS NS_DECL_NSIPROTOCOLHANDLER // nsFindHandler methods: nsFindHandler(); virtual ~nsFindHandler(); // Define a Create method to be used with a factory: static NS_METHOD Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); private: char *pStr;//for holding the total url typed }; #endif /* nsFindHandler_h___ */
NS_FINDHANDLER_CID
应该唯一;您可以使用 GUIDgen.exe 生成它。
这是 nsFindHandler.cpp。
#ifndef XP_WIN #define XP_WIN #endif #include <Windows.h> #include "nspr.h" #include "nsFindHandler.h" #include "nsIURL.h" #include "nsCRT.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIProgressEventSink.h" #include "nsNetCID.h" #include "nsIIOService.h" #include "nsIChannel.h" #include "nsEmbedString.h" #include "BuildSearchString.h" static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); //////////////////////////////////////////////////////////////////////////////// nsFindHandler::nsFindHandler() { } nsFindHandler::~nsFindHandler() { } NS_IMPL_ISUPPORTS1(nsFindHandler, nsIProtocolHandler); NS_METHOD nsFindHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) { nsFindHandler* ph = new nsFindHandler(); if (ph == nsnull) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(ph); nsresult rv = ph->QueryInterface(aIID, aResult); NS_RELEASE(ph); return rv; } //////////////////////////////////////////////////////////////////////////////// // nsIProtocolHandler methods: NS_IMETHODIMP nsFindHandler::GetScheme(nsACString &result) { result = "find"; return NS_OK; } NS_IMETHODIMP nsFindHandler::GetDefaultPort(PRInt32 *result) { *result = FIND_PORT; return NS_OK; } NS_IMETHODIMP nsFindHandler::NewURI(const nsACString &aSpec, const char *aCharset, // ignore charset info nsIURI *aBaseURI, nsIURI **result) { const char* data; NS_CStringGetData(aSpec, &data); //Copy the whole url in pStr pStr = _strdup( data ); //standard implementation //*********************************** nsresult rv; nsIURI* url; rv = CallCreateInstance(kSimpleURICID, &url); if (NS_FAILED(rv)) return rv; rv = url->SetSpec(aSpec); if (NS_FAILED(rv)) { NS_RELEASE(url); return rv; } *result = url; return rv; } //****************************************************** //function:- NewChannel //This is the most important function //You'll have to return a Channel(pointer //of nsIChannel, so that the protocol works //****************************************************** NS_IMETHODIMP nsFindHandler::NewChannel(nsIURI* aURI, nsIChannel* *result) { nsCOMPtr<nsIServiceManager> servMan; nsresult rv=NS_GetServiceManager(getter_AddRefs(servMan)); if(NS_FAILED(rv)) { MessageBox(0,"Service Manager failed...","Err",0); return rv; } //Create a smart pointer to nsIIOService nsCOMPtr<nsIIOService> ioser; rv=servMan->GetServiceByContractID("@mozilla.org/network/io-service;1", NS_GET_IID(nsIIOService),getter_AddRefs(ioser)); if(NS_FAILED(rv)) { MessageBox(0,"IO failed....","err",0); return rv; } //We need to extract the search //term from the total typed url CBuildSearchString asStr; char *strFinalURL; //get the final searching url asStr.BuildString (pStr,&strFinalURL); free( pStr ); //create a new channel nsCOMPtr<nsIChannel> tempChannel; ioser->NewChannel(nsEmbedCString(strFinalURL),nsnull, nsnull, getter_AddRefs(tempChannel)); NS_ENSURE_TRUE (tempChannel, NS_ERROR_FAILURE); //Now the Channel is returned *result =tempChannel.get(); NS_ADDREF(*result); delete [] strFinalURL; return NS_OK; } //////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP nsFindHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval) { if (port == FIND_PORT) *_retval = PR_TRUE; else *_retval = PR_FALSE; return NS_OK; } //////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP nsFindHandler::GetProtocolFlags(PRUint32 *result) { *result = URI_NORELATIVE | URI_NOAUTH | ALLOWS_PROXY; return NS_OK; }
大部分代码都可以重复用于您的自定义协议。
有四个区域可能需要自定义才能将此用于您的协议
GetScheme
更改此项以返回协议使用的前缀。
GetDefaultPort
更改此项以返回协议运行的默认端口。对于不使用端口的协议,可以返回 -1。此示例不使用任何端口,因此返回 -1。
NewURI
此处使用
NS_SIMPLEURI_CID
,它解析简单的 URL,例如没有路径的 URL。此函数获取整个输入的 URL。每当用户输入“find://<anything>”时,Firefox 就会调用此函数,字符串将作为第一个参数传递给此函数。代码如下:NS_IMETHODIMP nsFindHandler::NewURI(const nsACString &aSpec, const char *aCharset, // ignore charset info nsIURI *aBaseURI, nsIURI **result) { const char* data; NS_CStringGetData(aSpec, &data); //Copy the whole url in pStr pStr = _strdup( data );
NewChannel
您必须在此处返回一个通道,即
nsIChannel
接口的一个指针。这是来自NewChannel
函数的代码。//create a new channel nsCOMPtr<NSICHANNEL> tempChannel;ioser->NewChannel(nsEmbedCString(strFinalURL),nsnull, nsnull, getter_AddRefs(tempChannel)); NS_ENSURE_TRUE (tempChannel, NS_ERROR_FAILURE); //Now the Channel is returned *result =tempChannel.get();
您也可以实现 nsIChannel
,就像finger 协议示例一样。此示例中还使用了另一个类 CBuildSearchString
,用于从整个 URL 中提取搜索词并构建最终的 URL 字符串。
结论
我希望这个示例能帮助大家在准备 Mozilla Firefox 的协议时有所帮助。如果您有任何疑问,或者有任何需要,可以联系我。
致谢/鸣谢
- 感谢Brian Ryner先生,他实现了finger 协议。这是网上唯一一个使用 C++ 的示例协议。
- 感谢 Doron Rosenberg 先生,他用 JavaScript 简洁地实现了协议。
- 感谢 Prasadarao 先生和 Dileep C. George 先生构建了 Mozilla Firefox。