【问题标题】:Firefox command line arguments in extension扩展中的 Firefox 命令行参数
【发布时间】:2016-08-23 22:49:57
【问题描述】:

我正在尝试在我的扩展程序中获取 firefox 命令行的参数:

'firefox.exe -viewapp url -another-command -blablala:somedata'

还有here我找到了一个例子

但我不明白如何在第一次启动浏览器时获取所有参数。 我需要在 Web 控制台中显示它,如下所示:

console.log(commandLine.arguments)
// -viewapp url -another-command -blablala:somedata

请帮忙

【问题讨论】:

    标签: firefox firefox-addon firefox-addon-sdk


    【解决方案1】:

    我看到你只是想看看它是用什么命令行参数启动的。我知道一个 js-ctypes 解决方案。这将要求您为不同的平台编写代码。这是一个开始,它为您提供 windows 和 mac 上的参数。我还没有做 linux 部分:

    Cu.import('resource://gre/modules/osfile.jsm');
    Cu.import('resource://gre/modules/ctypes.jsm');
    
    var lib 
    var osname = OS.Constants.Sys.Name.toLowerCase();
    if (osname.indexOf('win') === 0) {
        // windows
        lib = ctypes.open('kernel32');
        var GetCommandLineW = lib.declare('GetCommandLineW', ctypes.winapi_abi,  ctypes.jschar.ptr);
        var rez = GetCommandLineW();
        console.log('rez:', rez.readString());
    } else if (osname == 'darwin') {
        // mac
    
        lib = ctypes.open(ctypes.libraryName('objc'));
    
        // BASIC TYPES
        var BOOL = ctypes.signed_char;
        var NSUINTEGER = ctypes.unsigned_long;
    
        // COMMON FUNCTIONS
        var objc_getClass = lib.declare('objc_getClass', ctypes.default_abi, ctypes.voidptr_t, ctypes.char.ptr);
        var objc_msgSend = lib.declare('objc_msgSend', ctypes.default_abi, ctypes.voidptr_t, ctypes.voidptr_t, ctypes.voidptr_t, '...');
        var sel_registerName = lib.declare('sel_registerName', ctypes.default_abi, ctypes.voidptr_t, ctypes.char.ptr);
    
        // current_application = [NSRunningApplication currentApplciation];
        var NSProcessInfo = objc_getClass('NSProcessInfo');
        var processInfo = sel_registerName('processInfo');
        var process_info = objc_msgSend(NSProcessInfo, processInfo);
    
        // bundle_identifier = [current_application bundleIdentifier]
        var arguments = sel_registerName('arguments');
        var args = objc_msgSend(process_info, arguments);
    
    
        var count = sel_registerName('count');
        var _count = objc_msgSend(args, count);
        console.info('_count:', _count, _count.toString(), uneval(_count), parseInt(_count));
    
        // make it into a js number
        _count = parseInt(ctypes.cast(_count, NSUINTEGER).value); 
        console.log('_count:', _count);
    
        var objectAtIndex = sel_registerName('objectAtIndex:'); // used in for loop
        var UTF8String = sel_registerName('UTF8String'); // used in for loop
    
        for (var i=0; i<_count; i++) {
            var arg = objc_msgSend(args, objectAtIndex, NSUINTEGER(i)); // must wrap `i` in NSUINTEGER as its variadic, you have to specify the type. this is specific to js-ctypes         
            var argString = ctypes.cast(objc_msgSend(arg, UTF8String), ctypes.char.ptr);
            console.log('arg "' + i + '":', argString.readStringReplaceMalformed(), 'arg:', arg, arg.toString(), uneval(arg));
        }
    
    } else {
        // *nix
    
        // todo
        // per - http://stackoverflow.com/a/821889/1828637
        var libcPaths = ['libc.so', 'libc.so.7', 'libc.so.61.0', 'libc.so.6', 'libc.so.0.1', 'libc.dylib'];
        for (var i=0; i<libcPaths.length; i++) {
            try {
                lib = ctypes.open(libcPaths[i]);
                break;
            } catch(ignore) {}
        }
        if (!lib) {
            throw new Error('failed to find libc on this system');
        }
    
        var popen = lib.declare('popen', ctypes.default_abi, ctypes.voidptr_t, ctypes.char.ptr, ctypes.char.ptr);
        var fread = lib.declare('fread', ctypes.default_abi, ctypes.size_t, ctypes.voidptr_t, ctypes.size_t, ctypes.size_t, ctypes.voidptr_t);
        var feof = lib.declare('feof', ctypes.default_abi, ctypes.int, ctypes.voidptr_t);
        var pclose = lib.declare('pclose', ctypes.default_abi, ctypes.int, ctypes.voidptr_t);
        var getpid = lib.declare('getpid', ctypes.default_abi, ctypes.int32_t);
    
        // ps -fp 2540
        var pid = getpid();
        var file = popen('ps -ww -fp' + pid, 'r');
    
        var buf = ctypes.char.array(100)();
        var jsbuf = [];
        var reachedEof = false;
        while (!reachedEof) {
            var cnt = fread(buf, 1, buf.length * buf.constructor.elementType.size, file);
            cnt = parseInt(cnt);
            if (cnt > 0) {
                jsbuf.push(buf.readString().substring(0, cnt));
            }
            reachedEof = feof(file);
        }
    
        var closeit = pclose(file);
        console.log('closeit:', closeit);
    
        console.log('jsbuf:', jsbuf.join(''));
    }
    
    lib.close();
    

    【讨论】:

    • 哦,是的!就是这个! // 你需要更正代码中的一个错误: var GetCommandLineW = kernel32.declare('GetCommandLineW', ctypes.winapi_abi, ctypes.jschar.ptr); // to: var GetCommandLineW = lib.declare('GetCommandLineW', ctypes.winapi_abi, ctypes.jschar.ptr);
    • 更简单的 linux 方法:阅读自 /proc/self/cmdline
    • 我没有看到/proc/self 在那个答案中不起作用。它提到了其他 unix,但我们正在讨论“不兼容 linux
    • 另外,如果你想运行ps,你可以使用sdk的进程生成模块,不需要js-ctypes。
    • 并不重要,因为您只需要获取命令行一次。毕竟它没有改变。因此您可以使用该模块来简化代码。
    【解决方案2】:

    这是一个非常简单的插件:

    https://github.com/Noitidart/Restore--remote/blob/master/bootstrap.js

    这里的这个插件是一个引导(所以无需重启——这很好)插件。因此,如果您使用 SDK,则必须利用低级别的东西。它也不需要像您链接到的 MDN 上那样的 chrome.manifest 文件。

    这是市场上的插件 - https://addons.mozilla.org/en-US/firefox/addon/restore-remote/

    代码如下:

    const Cc = Components.classes;
    const Ci = Components.interfaces;
    const Cm = Components.manager;
    const Cu = Components.utils;
    const Cr = Components.results;
    
    Cm.QueryInterface(Ci.nsIComponentRegistrar);
    
    Cu.import('resource://gre/modules/XPCOMUtils.jsm');
    Cu.import('resource://gre/modules/Services.jsm');
    Cu.import('resource://gre/modules/Preferences.jsm');
    
    function RemoteCommandLine(target, url, cl) {
      this._target = target;
      this._url = url;
      this._cl = cl;
    }
    
    RemoteCommandLine.prototype = {
      get preventDefault() {
        return this._cl.preventDefault;
      }, 
      set preventDefault(value) {
        this._cl.preventDefault = value;
      },
      handleFlag: function(flag, caseSensitive) {
        return false;
      },
      handleFlagWithParam: function(flag, caseSensitive) {
        if (!(flag == 'new-tab' && this._target == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) &&
            !(flag == 'new-window' && this._target == Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW))
          return null;
        var url = this._url;
        this._url = null;
        return url
      },
      resolveURI: function(url) {
        return this._cl.resolveURI(url);
      },
    };
    
    function Remote() {}
    
    Remote.prototype = {
      QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
      classDescription: 'remote',
      classID: Components.ID('{1280e159-cac2-4188-af5a-e6089527b7b8}'),
      contractID: '@mozilla.org/commandlinehandler/general-startup;1?type=remote',
    
      handle: function(cmdLine)
      {
        try {
          var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
        }
        catch (e) {
          throw Cr.NS_ERROR_ABORT;
        }
    
        if (remoteCommand != null) {
          try {
            var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
            var remoteVerb;
            if (a) {
              remoteVerb = a[1].toLowerCase();
              var remoteParams = [];
              var sepIndex = a[2].lastIndexOf(",");
              if (sepIndex == -1)
                remoteParams[0] = a[2];
              else {
                remoteParams[0] = a[2].substring(0, sepIndex);
                remoteParams[1] = a[2].substring(sepIndex + 1);
              }
            }
    
            switch (remoteVerb) {
            case "openurl":
            case "openfile":
              // openURL(<url>)
              // openURL(<url>,new-window)
              // openURL(<url>,new-tab)
    
              // First param is the URL, second param (if present) is the "target"
              // (tab, window)
              var url = remoteParams[0];
              var target = Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
              if (remoteParams[1]) {
                var targetParam = remoteParams[1].toLowerCase()
                                                 .replace(/^\s*|\s*$/g, "");
                if (targetParam == "new-tab")
                  target = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB;
                else if (targetParam == "new-window")
                  target = Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW;
                else {
                  // The "target" param isn't one of our supported values, so
                  // assume it's part of a URL that contains commas.
                  url += "," + remoteParams[1];
                }
              }
    
              if (target == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
                target = Preferences.get('browser.link.open_newwindow',
                                         Ci.nsIBrowserDOMWindow.OPEN_NEWTAB);
              }
    
              var clh = Cc['@mozilla.org/browser/clh;1'].getService(Ci.nsICommandLineHandler);
              clh.handle(new RemoteCommandLine(target, url, cmdLine));
              break;
    
    
            case "ping":
              break;
            default:
              // Somebody sent us a remote command we don't know how to process:
              // just abort.
              throw "Unknown remote command.";
            }
    
            cmdLine.preventDefault = true;
          }
          catch (e) {
            Components.utils.reportError(e);
            // If we had a -remote flag but failed to process it, throw
            // NS_ERROR_ABORT so that the xremote code knows to return a failure
            // back to the handling code.
            throw Cr.NS_ERROR_ABORT;
          }
        }
      },
    };
    
    const RemoteFactory = XPCOMUtils.generateNSGetFactory([Remote])(Remote.prototype.classID);
    
    function startup(aData, aReason) {
      Cm.registerFactory(Remote.prototype.classID,
                         Remote.prototype.classDescription,
                         Remote.prototype.contractID,
                         RemoteFactory);
      var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
      catman.addCategoryEntry('command-line-handler', 'l-remote', Remote.prototype.contractID, false, true);
    }
    
    function shutdown(aData, aReason) {
      var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
      catman.deleteCategoryEntry('command-line-handler', 'l-remote', false);
      Cm.unregisterFactory(Remote.prototype.classID, RemoteFactory);
    }
    

    【讨论】:

    • 我认为这不是我想要的。我不需要命令行实例,我需要在启动 firefox 时获取第一个参数。
    • @jazzperio 哦,我明白了。这很容易通过 js-ctypes 实现。你只是想看看它是用什么论据发起的,对吗?你在哪个平台?我有一个现成的 mac 示例 - gist.github.com/Noitidart/72d379828e0a3f98b5d6 - 我也可以帮助你为 Windows 和 Linux 敲定它。
    猜你喜欢
    • 2019-05-09
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 2019-06-09
    • 1970-01-01
    • 2016-06-05
    相关资源
    最近更新 更多