我有一个外部应用程序,我希望它在浏览器窗口的顶部显示一些信息。我的自举扩展需要将浏览器窗口句柄(本机HWND)传递给我的应用程序,以及有关该窗口的一些其他有用信息。我能够在它们之间进行通信,唯一缺少的是获取Firefox窗口的本机HWND的方法。
我读了很多关于它的内容,虽然我相信它是可能的,但我找不到可行的解决方案。这是我到目前为止所尝试的内容:
这个应该给我nsIBaseWindow
,所以我可以获得nsIBaseWindow.nativeHandle
或nsIBaseWindow.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);
任何帮助都将不胜感激。
答案 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 ++类mozIDOMWindowProxy
或nsChromeOuterWindowProxy
。但是这些似乎只是其他类的包装器类。最后,我放弃了尝试理解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内容。