Firefox bootstrapped扩展:获取浏览器窗口的本机HWND句柄

时间:2014-02-24 14:55:40

标签: firefox-addon xul xpcom jsctypes

我有一个外部应用程序,我希望它在浏览器窗口的顶部显示一些信息。我的自举扩展需要将浏览器窗口句柄(本机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);

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:3)

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;

答案 1 :(得分:2)

问题是我在subject观察者的xul-window-registered param中查询错误的界面。我需要获得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;
}

它有效!

非常感谢你的帮助。

答案 2 :(得分:0)

我也遇到过这个问题,可能会很好:

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*/

答案 3 :(得分:0)

用户'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),几乎完全没有注释。我发现我在浪费这种方法。

要理解运行在多个相互通信的进程中的Firefox的源代码是极其困难的。变量win的内容似乎对应于C ++类mozIDOMWindowProxynsChromeOuterWindowProxy。但是这些似乎只是其他类的包装器类。最后,我放弃了尝试理解Firefox源代码的过程。

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

它更简单:

var baseWindow = win.docShell
                    .treeOwner
                    .nsIBaseWindow; 

它可在Firefox 70(最高为79)(当前为最新版本)上运行。但是,此新代码无法在<= 62的Firefox版本上运行。在Firefox 62或更早版本上,您会收到错误消息

TypeError: win.docShell is undefined

因此,从63到69的Firefox允许两种版本的代码。也许在版本70中,QueryInterface()已被删除,因为不再需要'MozillaWindowClass'并使其成为旧版?

注意:在Firefox 68中,他们进行了另一项更改。现在有2个本机窗口:顶层'MozillaCompositorWindowClass现在有一个子窗口class sampleclass: count = 0 # class attribute def increase(self): sampleclass.count += 1 # Calling increase() on an object s1 = sampleclass() s1.increase() print(s1.count) ',该子窗口在另一个进程中运行并绘制Web内容。