Closed
Bug 363332
Opened 18 years ago
Closed 18 years ago
XPConnect's QI can get confused about which object to return
Categories
(Core :: XPConnect, defect)
Tracking
()
RESOLVED
WORKSFORME
People
(Reporter: WeirdAl, Unassigned)
Details
(Keywords: testcase)
Attachments
(2 files)
While working on bug 363290, I ran into a situation where a JS-based component would claim to implement two different interfaces. The problem arose in that both interfaces (in that case nsIEditor, nsIClassInfo) have an identically named property (flags), which means different things for each interface. I figured the best solution would be to use QueryInterface and to write the JS component so that its QI method would return a different object (a tearoff, essentially) for nsIClassInfo. If the tearoff received a QI request for something other than nsIClassInfo, it would refer back to the original object. As it turns out, I didn't need to do the QI, but I did wonder if it would work. I wrote a component (nsIScriptError, nsIClassInfo) in JS, and a xpcshell testcase that would try to QI to the nsIClassInfo tearoff. The testcase failed. Two-part xpcshell testcase coming up.
Reporter | ||
Comment 1•18 years ago
|
||
Reporter | ||
Comment 2•18 years ago
|
||
Steps to reproduce: (1) Save the first part of the testcase into dist/bin/components/testFlagsComponent.js (2) Save the second part of the testcase as a local file. (3) xpcshell -w -s (4) Load the second part of the testcase. (5) js>runTest(); Expected results: (note CI_Tearoff.flags) Creating ClassInfo tearoff Returning CI tearoff isCI: false typeof testError.flags: number testError.flags: 1 isCI: true typeof testError.flags: number testError.flags: 1 CI_Tearoff: Test script error CI_Tearoff.flags: 0 isCI: true typeof testError.flags: number testError.flags: 1 Actual results: Creating ClassInfo tearoff Returning CI tearoff isCI: false typeof testError.flags: number testError.flags: 1 isCI: true typeof testError.flags: number testError.flags: 1 CI_Tearoff: Test script error CI_Tearoff.flags: 1 isCI: true typeof testError.flags: number testError.flags: 1
oh, right, so, the reason i stopped caring is that you can use interface flattening's *other* feature to stop caring: js> SIP=Components.Constructor("@mozilla.org/supports-interface-pointer;1",Components.interfaces.nsISupportsInterfacePointer) [object nsXPCConstructor @ 0x2e88b60 (native @ 0x2e891d8)] js> sip=new SIP [interface pointer] js> function A(){} js> A.prototype.QueryInterface=function QueryInterface(iid) { if (iid.equals(Components.interfaces.nsIObserver) || iid.equals(Components.interfaces.nsISupports)) return this; if (iid.equals(Components.interfaces.nsIConsoleListener)) { if (!this.c) this.c=new C(this); return this.c; } throw Components.results.NS_ERROR_NO_INTERFACE; } function QueryInterface(iid) { if (iid.equals(Components.interfaces.nsIObserver) || iid.equals(Components.interfaces.nsISupports)) { return this; } if (iid.equals(Components.interfaces.nsIConsoleListener)) { if (!this.c) { this.c = new C(this); } return this.c; } throw Components.results.NS_ERROR_NO_INTERFACE; } js> function C(root) { this.root = root; } js> C.prototype.QueryInterface=function QueryInterface2(iid) { if (iid.equals(Components.interfaces.nsIConsoleListener)) return this; return this.root.QueryInterface.apply(this.root, arguments); } function QueryInterface2(iid) { if (iid.equals(Components.interfaces.nsIConsoleListener)) { return this; } return this.root.QueryInterface.apply(this.root, arguments); } js> C.prototype.observe= function Listener_observe() { print("listener"); } function Listener_observe() { print("listener"); } js> A.prototype.observe= function Observer_observe() { print("observer"); } function Observer_observe() { print("observer"); } js> sip.data=new A [object Object] js> sip.data.QueryInterface(Components.interfaces.nsIObserver) [xpconnect wrapped nsIObserver @ 0x2e83238 (native @ 0x2f5ad38)] js> sip.data [xpconnect wrapped nsIObserver @ 0x2e83238 (native @ 0x2f5ad38)] js> sip.data.observe(null, "", "") observer js> sip.data.QueryInterface(Components.interfaces.nsIConsoleListener) [xpconnect wrapped (nsISupports, nsIObserver, nsIConsoleListener) @ 0x2e83238 (n ative @ 0x2f5ad38)] js> sip.data.observe(null) uncaught exception: [Exception... "Not enough arguments [nsIObserver.observe]" nsresult: "0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)" location: "JS frame :: ty pein :: <TOP_LEVEL> :: line 72" data: no] js> sip.data.nsIConsoleListener.observe(null) listener js> sip.data.nsIObserver.observe(null, "", "") observer iow, you don't use explicit QI which only contributes to flattening, you have to use the tearoff system {object.interface): js> sip.data.nsIConsoleListener [xpconnect wrapped nsIConsoleListener @ 0x2e83238 (native @ 0x2f5ad38)] js> sip.data.nsIObserver [xpconnect wrapped nsIObserver @ 0x2e83238 (native @ 0x2f5ad38)] It's not confused, it's working as designed.
Status: NEW → RESOLVED
Closed: 18 years ago
Resolution: --- → WORKSFORME
You need to log in
before you can comment on or make changes to this bug.
Description
•