【问题标题】:Firefox bootstrapped extension: Get native HWND handle of the browser windowFirefox 引导扩展:获取浏览器窗口的本机 HWND 句柄
【发布时间】:2014-02-24 14:55:39
【问题描述】:

我有一个外部应用程序,我希望它在浏览器窗口顶部显示一些信息。我的引导扩展需要将浏览器窗口句柄(本机 HWND)以及有关窗口的其他一些有用信息传递给我的应用程序。我能够在它们之间进行通信,唯一缺少的是获取 Firefox 窗口的本机 HWND 的方法。

我阅读了很多关于它的内容,虽然我相信这是可能的,但我找不到可行的解决方案。到目前为止,这是我尝试过的:

这个应该给我nsIBaseWindow,所以我可以得到nsIBaseWindow.nativeHandlensIBaseWindow.ParentNativeWindow,但没有成功:

var window = SomeDOMWindow; // Informative
var baseWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                        .getInterface(Components.interfaces.nsIWebNavigation)
                        .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                        .treeOwner
                        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                        .getInterface(Components.interfaces.nsIXULWindow)
                        .docShell
                        .QueryInterface(Components.interfaces.nsIBaseWindow);

上面的代码在论坛上广泛传播,但我无法让它为我工作。

另一个似乎不太准确,因为它根据窗口的类和标题获取 HWND,这可能会导致错误的结果:

Components.utils.import("resource://gre/modules/ctypes.jsm");
var lib = ctypes.open("user32.dll");
var fww = lib.declare("FindWindowW", ctypes.winapi_abi,
  ctypes.voidptr_t, ctypes.jschar.ptr, ctypes.jschar.ptr);
var sfw = lib.declare("SetForegroundWindow", ctypes.winapi_abi,
  ctypes.int32_t, ctypes.voidptr_t);
var hwnd = fww("MozillaWindowClass", document.title);
setTimeout(function() {
  sfw(hwnd);
  lib.close();
}, 3000);

任何帮助将不胜感激。

【问题讨论】:

    标签: firefox-addon xul xpcom jsctypes


    【解决方案1】:

    window 必须是根(即ChromeWindow 的实例)

    下面的代码应该可以工作

    var win = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");
    var basewindow = win.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShellTreeItem)
                     .treeOwner
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .nsIBaseWindow;
    var nativehandle = basewindow.nativeHandle;
    

    【讨论】:

    • 我需要从xul-window-registered 事件观察器中获取创建的ChromeWindow,以便测试您的解决方案。我有事件处理程序:observe: function(subject, topic, data) {...},这就是我需要获取句柄的地方,但我只知道如何从那里获取nsIDOMWindow,而不是创建的ChromeWindow
    • 嗯,xul-window-registered 通知的主题是您要查找的窗口。
    • 我尝试使用它,但它是一个nsISupports 接口。当我尝试从中获取basewindow 时出现错误:[nsIInterfaceRequestor.getInterface]" nsresult: "0x80004002 (NS_NOINTERFACE)"
    • 测试您可以将他的代码复制粘贴到暂存器中,并将环境设置为浏览器。效果很好。
    • @Kekas 我猜当观察者收到xul-window-registered 主题的通知时,窗口对象的初始化还没有完成。也许你应该等到load 事件被触发。
    【解决方案2】:

    问题是我从xul-window-registered 观察者中的subject 参数查询了错误的接口。我需要获得 nsIDOMWindow 而不是 nsIXULWindow 所以我的问题中提到的第一个代码有效。所以现在我正在做以下事情,并建议了一些代码@Noit:

    observe: function(subject, topic, data) {
        var newWindow  = subject.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
        var basewindow = newWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIWebNavigation)
                         .QueryInterface(Ci.nsIDocShellTreeItem)
                         .treeOwner
                         .QueryInterface(Ci.nsIInterfaceRequestor)
                         .nsIBaseWindow;
        var nativehandle = basewindow.nativeHandle;
    }
    

    而且它有效!

    非常感谢您的帮助。

    【讨论】:

    • 非常感谢分享sn-p的代码,它将帮助人们
    • 哇再次感谢分享这个,我遇到了一个问题,我在设置窗口的标题然后做 FindWindow 但 findwindow 没有找到它,因为它在更改窗口标题后运行得很快我现在想起了这个话题,甚至不需要FindWindow 超级男人再次感谢!这就是为什么人们应该总是分享解决方案! :)
    • 此代码在 Firefox 70 上不再有效。请参阅我的答案。
    【解决方案3】:

    我也刚遇到这个,应该不错:

    Cu.import("resource://gre/modules/ctypes.jsm");
    
    /*start getcursorpos*/
    var lib = ctypes.open("user32.dll");
    
    /*foreground window stuff*/
    var FindWindowA = lib.declare('FindWindowA', ctypes.winapi_abi, ctypes.uint32_t, ctypes.jschar.ptr, ctypes.jschar.ptr)
    var GetForegroundWindow = lib.declare('GetForegroundWindow', ctypes.winapi_abi, ctypes.uint32_t)
    function doFindWindow() {
        var wm = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
        var title = wm.getMostRecentWindow('navigator:browser').gBrowser.contentDocument.title;
        Cu.reportError('title=' + title)
        var ret = FindWindowA('', title + ' - Mozilla Firefox');
        //var ret = GetForegroundWindow();
    
        Cu.reportError(ret);
    }
    /*end foreground window stuff*/
    

    【讨论】:

    • 它不是很可靠,因为它使用窗口的标题,并且某些发行版有不同的名称。更不用说在这个过程中标题可能会改变,或者多个窗口有相同的标题,你最终可能会得到错误的句柄。
    【解决方案4】:

    用户“paa”的answer 中的代码在 Firefox 版本 69 之前一直有效。 如果你在 Firefox 70 中执行它,你会得到一个异常:

    TypeError: win.QueryInterface is not a function
    

    这很奇怪,因为变量 win 在 Firefox 69 和 70 中具有相同的内容。

    当我在两个浏览器中执行alert(win) 时,我得到:"[object ChromeWindow]"

    并且alert(win.document.title) 在两个浏览器中都能正确显示文档的标题。

    我下载了两个 Firefox 版本的源代码来比较它们并可能找到原因。但是 Firefox 的源代码很大(2 GB)并且几乎完全没有 cmets。我发现我在用这种方法浪费时间。

    很难理解 Firefox 的源代码,它运行在多个相互通信的进程中。看来变量win的内容对应的是C++类mozIDOMWindowProxy或者nsChromeOuterWindowProxy。但这些似乎只是其他类的包装类。最后我放弃了尝试理解 Firefox 源代码。

    但是玩了几个小时,我终于通过尝试和错误找到了解决方案。

    更简单:

    var baseWindow = win.docShell
                        .treeOwner
                        .nsIBaseWindow; 
    

    它适用于 Firefox 70 至 79(目前是最新版本)。但是,此新代码无法在 Firefox 版本

    TypeError: win.docShell is undefined
    

    所以从 63 到 69 的 Firefox 允许这两个版本的代码。也许在第 70 版中,QueryInterface() 已被删除,因为它不再需要并已成为旧版?

    注意:在 Firefox 68 中,他们进行了另一项更改。现在有 2 个原生窗口:顶层 'MozillaWindowClass' 现在有一个子窗口 'MozillaCompositorWindowClass',它在另一个进程中运行并绘制 Web 内容。

    【讨论】:

      猜你喜欢
      • 2020-10-22
      • 1970-01-01
      • 2013-01-02
      • 2013-02-08
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      相关资源
      最近更新 更多