列出协议和内容类型处理程序

Listing protocol and content type handlers

是否有用于列出所有协议处理程序和内容类型处理程序的 XPCOM 接口?

我看到信息在 mimeTypes.rdf 中可用,虽然我看到了获取特定已知处理程序信息的接口,但我找不到任何列出所有这些信息的 XPCOM 接口。

嘿 Brett 这是我在使用 MailtoWebmails 时写的东西,请分享你学到的任何东西、怪癖等:

GitHubGIST :: Noitidart / _ff-addon-tutorial-CheckGetSetRemoveAddHandlerOfProtocol.md

获取handlerInfo对象

nsIHandlerService 方法

这里返回的handlerInfo对象和上面nsiExternalProtocolService的方法完全一样。

如果您转到选项面板并更改为 alwaysAsk,日志 handlerInfo 中的 alwaysAskBeforeHandling 属性 将正确反映。

var handlerService = Cc['@mozilla.org/uriloader/handler-service;1'].getService(Ci.nsIHandlerService);
var listOfWrappedHandlers = handlerService.enumerate();
var i = 0;
while (listOfWrappedHandlers.hasMoreElements()) {
  var handlerInfo = listOfWrappedHandlers.getNext().QueryInterface(Ci.nsIHandlerInfo);
  //console.log(i, 'handler for', wrappedHandlerInfo.type, wrappedHandlerInfo);
  if (handlerInfo.type == 'mailto') {
    break;
  }
  i++;
}
console.log('handlerServicehandlerInfo=', handlerInfo); //is the mailto one as we broke the loop once it found that

handlerInfo 中没有 possibleLocalHandlers

nsiExternalProtocolService 方法

这里返回的handlerInfo对象和上面nsIHandlerService的方法完全一样。

如果您转到选项面板并更改为 alwaysAsk,日志 handlerInfo 中的 alwaysAskBeforeHandling 属性 将正确反映。

var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo('mailto');
console.log('epsHandlerInfo', handlerInfo)

handlerInfo 中没有 possibleLocalHandlers

nsIMIMEService 方法 注意:有一些主要的怪癖,比如没有准确地反映 preferedHandleralwaysAskBeforeHandling(到目前为止我只注意到这两个我没有探索其他属性,但它们可能同样被抬高了

使用nsIHandlerServicensiExternalProtocolService这两个上面的方法,如果你去选项面板,改成alwaysAsk the alwaysAskBeforeHandling 属性 in the log handlerInfos 将正确反映。但是,如果您使用此方法获得 handlerInfo nsIMIMEService,那么它并不能准确反映 alwaysAskBeforeHandling 的下拉设置,这太奇怪了:

它还有possibleApplicationHandlers,长度为0。奇怪的。它还有 possibleLocalHandlers,在我的例子中长度为 53,很有趣。

var mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService);
var CONTENT_TYPE = 'mailto';
var TYPE_EXTENSION = '';

var handlerInfo = mimeService.getFromTypeAndExtension(CONTENT_TYPE, TYPE_EXTENSION);
console.info('mimeServiceHandlerInfo:', handlerInfo); //http://i.imgur.com/dUKox24.png

mimeServiceHandlerInfo 也与 EPS 和 HandlerService 的前两个方法返回的 handlerInfo 具有不同的对象键。

检查与此关联的处理程序

使用上述三种方法中的任何一种方法 handlerInfo(好吧,我还没有测试 nsiMIMServicehandlerInfo,但我猜它应该有效)

queryElementAt 方法

这种方式没有列出"Microsoft Outlook",它只列出了gmail,ymail和我添加的东西,很奇怪

 var handlers = handlerInfo.possibleApplicationHandlers;
 console.log('handlers', handlers)
 for (var i = 0; i < handlers.length; ++i) {
   var handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp); //instead of Ci.nsIHandlerApp
   console.log('poss handler', i, handler, handler.uriTemplate);

 }
enumerate 方法

我认为这种方式也不会列出 "Microsoft Outlook",但我不确定,因为它只记录小的 handler 对象。

这种方式只有 returns/logs 小对象 (handler) 用于第一个非系统默认处理程序(我认为就是这样,但它绝对只有 returns 一个)。 returns 名称等 我通过添加 .QueryInterface(Ci.nsIHandlerApp)

解决了这个问题
 var handlers = handlerInfo.possibleApplicationHandlers.enumerate();
 while (handlers.hasMoreElements()) {
   var handler = handlers.getNext().QueryInterface(Ci.nsIWebHandlerApp); //instead of Ci.nsIHandlerApp
   console.log('handler', handler);
 }
关于 enumeratequeryElementAt 的注释
  • QI'ing Ci.nsIHandlerApphandler 对象中不会有 uriTemplate,所以我将其更改为 Ci.nsIWebHandlerApp,这个在 hte 对象 uriTemplate.

    中返回
    • 可以用 Ci.nsIHandlerApppossibleApplicationHandlers 中 QI handlers 但不能在 possibleLocalHandlers 中用 [=62= QI handlers ] 它将抛出以下异常:

      异常:组件返回失败代码:0x80004002 (NS_NOINTERFACE) [nsISupports.QueryInterface]

向协议添加处理程序

registerProtocolHandler 显示了添加处理程序时要进行的所有检查,并显示了如何添加它。 MXR :: mozilla-release/ mozilla/ browser/ components/ feeds/ src/ WebContentConverter.js #L368 - registerProtocolHandler

此代码段展示了如何添加 nsIWebAppHandler。我不确定如何添加 nsILocalAppHandler(我不确定它是否甚至被称为 nsILocalAppHandler 也许它只是(实际上可能是)nsIAppHandler)。在将其添加到此处之前不进行任何验证检查。您应该在添加之前进行以下检查:

  1. 检查我们添加的处理程序是否已经存在作为可能的处理程序MXR :: mozilla-release/ mozilla/ browser/ components/ feeds/ src/ WebContentConverter.js #349 - _protocolHandlerRegistered
    • 请注意:这只检查 possibleApplicationHandlers 而不会检查 possibleLocalHandlers,我不确定为什么,但可能是因为我们正在处理 nsIWebAppHandler
  2. 检查以确保我们添加处理程序的协议尚未在内部处理(我们不想让他们接管,比如 "chrome")。 MXR :: mozilla-release/ mozilla/ browser/ components/ feeds/ src/ WebContentConverter.js #390
  3. 检查我们要添加处理程序的协议是否在黑名单中。如果它在黑名单中,则意味着它不希望将其他处理程序添加到其中。我不确定这有多重要,但 registerProtocolHandler 做到了。 MXR :: mozilla-release/ mozilla/ browser/ components/ feeds/ src/ WebContentConverter.js #402

所以最后是关于如何添加处理程序而不进行上述三项检查中的任何一项的代码。

var protocol = 'mailto';
var name = 'Hotmail Mailto Handler';
var newURIArgs = {
    aURL: 'http://mail.live.com/secure/start?action=compose&to=%s',
    aOriginCharset: null,
    aBaseURI: null
};
var myURI = Services.io.newURI(newURIArgs.aURL, newURIArgs.aOriginCharset, newURIArgs.aBaseURI);
var myURISpec = myURI.spec;


var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance(Ci.nsIWebHandlerApp);
handler.name = name;
handler.uriTemplate = myURISpec;

var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo(protocol);
handlerInfo.possibleApplicationHandlers.appendElement(handler, false);

if (handlerInfo.possibleApplicationHandlers.length > 1) {
    // May want to always ask user before handling because it now has multiple possibleApplicationsHandlers BUT dont have to
    //handlerInfo.alwaysAskBeforeHandling = true;
}

var hs = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
hs.store(handlerInfo);

如何获取协议的当前设置处理程序

首先使用获取 handlerInfo 对象 - nsIHandlerService - 方法或获取 handlerInfo 对象 - nsiExternalProtocolService 获取协议的 handlerInfo 对象方法。

  1. 然后先检查handlerInfo.alwaysAskBeforeHandling是否为true。如果是这种情况,则活动处理程序是 "Always Ask"。如果是这种情况,那么 handlerInfo.preferredApplicationHandlerhandlerInfo.preferredAction 就过时了。陈旧的意思是它们不是真的,它们被设置为之前设置的任何值。
  2. handlerInfo.alwaysAskBeforeHandlingfalse 然后检查 handlerInfo.preferredAction
    • 如果 handlerInfo.preferredAction == Ci.nsIHandlerInfo.useSystemDefaulthandler.preferredApplicaitonHandler 陈旧,因为它是上次设置的任何值。因此,活动处理程序是 userSystemDefault 中的任何一个。 (在撰写本文时,2014 年 8 月 3 日——我不确定如何找出协议的系统默认处理程序)
    • 如果 handlerInfo.preferredAction == Ci.nsIHandlerInfo.useHelperApp 则默认处理程序是 handlerInfo.preferredApplicationHandler 中保存的任何内容。在这种情况下 handler.preferredApplicaitonHandler 不应该是 null。在所有其他情况下 handler.preferredApplicaitonHandler 有可能成为 null.
    • 如果 handlerInfo.preferredAction == Ci.nsIHandlerInfo.saveToDisk 比默认处理程序要下载它
    • 如果 handlerInfo.preferredAction == Ci.nsIHandlerInfo.handleInternally 不是默认处理程序,我在撰写本文时不知道(2014 年 8 月 3 日)

Demo/Example - 将 mailto 处理程序设置为 "Yahoo! Mail"

//start - demo make handler for mailto be y! mail
var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo('mailto');
console.log('epsHandlerInfo', handlerInfo)

var handlers = handlerInfo.possibleApplicationHandlers.enumerate();
var foundYahooMailHandler = false;
while (handlers.hasMoreElements()) {
    var handler = handlers.getNext();
    if (handler.QueryInterface(Ci.nsIWebHandlerApp).uriTemplate == 'https://compose.mail.yahoo.com/?To=%s') { //this is how i decided to indentify if the handler is of yahoo mail
        foundYahooMailHandler = true;
        break;
    }
}

if (foundYahooMailHandler) {
    //it was found. and in the while loop when i found it, i "break"ed out of the loop which left handlerInfo set at the yahoo mail handler
    //set this to the prefered handler as this handler is the y! mail handler
    handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp; //Ci.nsIHandlerInfo has keys: alwaysAsk:1, handleInternally:3, saveToDisk:0, useHelperApp:2, useSystemDefault:4
    handlerInfo.preferredApplicationHandler = handler;
    handlerInfo.alwaysAskBeforeHandling = false;
    var hs = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
    hs.store(handlerInfo);
} else {
    alert('could not find yahoo mail handler. meaning i couldnt find a handler with uriTemplate of ...compose.mail.yahoo....')
}
//end - demo make handler for mailto be y! mail
如何删除处理程序

Demo/Example

var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo('mailto');
console.log('epsHandlerInfo', handlerInfo)

console.log('handlerInfo.preferredApplicationHandler', handlerInfo.preferredApplicationHandler);
console.log('handlerInfo.possibleApplicationHandlers', handlerInfo.possibleApplicationHandlers);

var handlers = handlerInfo.possibleApplicationHandlers;
console.log('handlers', handlers)
for (var i = 0; i < handlers.length; ++i) {
    var handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
    console.log('handler', i, handler, handler.uriTemplate);

    if (Services.wm.getMostRecentWindow(null).confirm('delete handler at position ' + i + '? its uriTemplate = "' + handler.uriTemplate + '" and name = "' + handler.name + '"')) {
        if (handler.equals(handlerInfo.preferredApplicationHandler)) {
            Services.wm.getMostRecentWindow(null).alert('the preferredApplicationHandler was the one we are removing now, so null the preferredAppHand and set to always ask');
            //if the last preferredApplicationHandler was this then nullify it, just me trying to keep things not stale
            handlerInfo.preferredApplicationHandler = null;
            if (handlerInfo.preferredAction == Ci.nsIHandlerInfo.useHelperApp) {
                //it looks like the preferredAction was to use this helper app, so now that its no longer there we will have to ask what the user wants to do next time the uesrs clicks a mailto: link
                handlerInfo.alwaysAskBeforeHandling = true;
                handlerInfo.preferredAction = Ci.nsIHandlerInfo.alwaysAsk; //this doesnt really do anything but its just nice to be not stale. it doesnt do anything because firefox checks handlerInfo.alwaysAskBeforeHandling to decide if it should ask. so me doing this is just formality to be looking nice
            }
        }
        handlers.removeElementAt(i);
        i--;
    }
    var hs = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
    hs.store(handlerInfo);
}