From 03d094a554f315e7597571f1832c74edd7b232da Mon Sep 17 00:00:00 2001 From: "andersca@apple.com" Date: Fri, 14 Dec 2007 19:47:16 +0000 Subject: [PATCH] JavaScriptCore: Reviewed by Darin and Geoff. REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) Get rid of unnecessary and incorrect security checks for plug-ins accessing JavaScript objects. The way this used to work was that each NPObject that wrapped a JSObject would have a root object corresponding to the frame object (used for managing the lifecycle) and an origin root object (used for doing security checks). This would prevent a plug-in from accessing a frame's window object if it's security origin was different (some parts of the window, such as the location object, can be accessed from frames with different security origins, and those checks are being done in WebCore). Also, if a plug-in were to access a window object of a frame that later went away, it could lead to that Window JSObject being garbage collected and the NPObject pointing to freed memory. How this works now is that there is no origin root object anymore, and all NPObject wrappers that are created for a plug-in will have the root object of the containing frame of that plug-in. * bindings/NP_jsobject.cpp: (jsDeallocate): Don't free the origin root object. (_NPN_CreateScriptObject): Remove the origin root object parameter. (_NPN_InvokeDefault): (_NPN_Invoke): (_NPN_Evaluate): (_NPN_GetProperty): (_NPN_SetProperty): (_NPN_RemoveProperty): (_NPN_HasProperty): (_NPN_HasMethod): (_NPN_Enumerate): Get rid of all security checks. * bindings/NP_jsobject.h: Remove originRootObject from the JavaScriptObject struct. * bindings/c/c_utility.cpp: (KJS::Bindings::convertValueToNPVariant): Always use the root object from the ExecState. WebCore: Reviewed by Darin and Geoff. REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) _NPN_CreateScriptObject doesn't take an origin root object anymore. * html/HTMLPlugInElement.cpp: (WebCore::HTMLPlugInElement::createNPObject): * page/Frame.cpp: (WebCore::Frame::windowScriptNPObject): WebKitTools: Reviewed by Darin and Geoff. REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) Add property getting methods to the plug-in. * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: (pluginInvoke): LayoutTests: Reviewed by Darin and Geoff. REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) Add cross frame plug/in test where a plug/in inside an iframe tries to access properties of the top-level frame. * http/tests/plugins/cross-frame-object-access-expected.txt: Added. * http/tests/plugins/cross-frame-object-access.html: Added. * http/tests/plugins/resources/cross-frame-object-access.html: Added. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@28715 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- JavaScriptCore/ChangeLog | 48 ++++++++++++ JavaScriptCore/JavaScriptCore.exp | 2 +- JavaScriptCore/bindings/NP_jsobject.cpp | 36 +-------- JavaScriptCore/bindings/NP_jsobject.h | 3 +- JavaScriptCore/bindings/c/c_utility.cpp | 12 +-- LayoutTests/ChangeLog | 16 +++- .../cross-frame-object-access-expected.txt | 20 +++++ .../plugins/cross-frame-object-access.html | 11 +++ .../resources/cross-frame-object-access.html | 78 +++++++++++++++++++ WebCore/ChangeLog | 14 ++++ WebCore/html/HTMLPlugInElement.cpp | 2 +- WebCore/page/Frame.cpp | 2 +- WebKitTools/ChangeLog | 14 +++- .../PluginObject.cpp | 46 ++++++++++- 14 files changed, 250 insertions(+), 54 deletions(-) create mode 100644 LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt create mode 100644 LayoutTests/http/tests/plugins/cross-frame-object-access.html create mode 100644 LayoutTests/http/tests/plugins/resources/cross-frame-object-access.html diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 627764b4693a..f3a836790d29 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,51 @@ +2007-12-14 Anders Carlsson + + Reviewed by Darin and Geoff. + + + REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) + + Get rid of unnecessary and incorrect security checks for plug-ins accessing JavaScript objects. + + The way this used to work was that each NPObject that wrapped a JSObject would have a root object + corresponding to the frame object (used for managing the lifecycle) and an origin root object (used for + doing security checks). + + This would prevent a plug-in from accessing a frame's window object if it's security origin was different + (some parts of the window, such as the location object, can be accessed from frames with different security + origins, and those checks are being done in WebCore). + + Also, if a plug-in were to access a window object of a frame that later went away, it could lead to that + Window JSObject being garbage collected and the NPObject pointing to freed memory. + + How this works now is that there is no origin root object anymore, and all NPObject wrappers that are created + for a plug-in will have the root object of the containing frame of that plug-in. + + * bindings/NP_jsobject.cpp: + (jsDeallocate): + Don't free the origin root object. + + (_NPN_CreateScriptObject): + Remove the origin root object parameter. + + (_NPN_InvokeDefault): + (_NPN_Invoke): + (_NPN_Evaluate): + (_NPN_GetProperty): + (_NPN_SetProperty): + (_NPN_RemoveProperty): + (_NPN_HasProperty): + (_NPN_HasMethod): + (_NPN_Enumerate): + Get rid of all security checks. + + * bindings/NP_jsobject.h: + Remove originRootObject from the JavaScriptObject struct. + + * bindings/c/c_utility.cpp: + (KJS::Bindings::convertValueToNPVariant): + Always use the root object from the ExecState. + 2007-12-13 Steve Falkenburg Move source file generation into its own vcproj to fix build dependencies. diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index b95cd999a8f5..1fd3d9cd21b2 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -104,7 +104,7 @@ __NPN_UTF8FromIdentifier __Z12jsRegExpFreeP8JSRegExp __Z15jsRegExpCompilePKti24JSRegExpIgnoreCaseOption23JSRegExpMultilineOptionPjPPKc __Z15jsRegExpExecutePK8JSRegExpPKtiiPii -__Z23_NPN_CreateScriptObjectP4_NPPPN3KJS8JSObjectEN3WTF10PassRefPtrINS1_8Bindings10RootObjectEEES8_ +__Z23_NPN_CreateScriptObjectP4_NPPPN3KJS8JSObjectEN3WTF10PassRefPtrINS1_8Bindings10RootObjectEEE __Z25_NPN_CreateNoScriptObjectv __ZN3KJS10Identifier11addSlowCaseEPNS_7UString3RepE __ZN3KJS10Identifier3addEPKNS_5UCharEi diff --git a/JavaScriptCore/bindings/NP_jsobject.cpp b/JavaScriptCore/bindings/NP_jsobject.cpp index a5878a68e55d..4eef8f6c007d 100644 --- a/JavaScriptCore/bindings/NP_jsobject.cpp +++ b/JavaScriptCore/bindings/NP_jsobject.cpp @@ -62,9 +62,6 @@ static void jsDeallocate(NPObject* npObj) if (obj->rootObject) obj->rootObject->deref(); - if (obj->originRootObject) - obj->originRootObject->deref(); - free(obj); } @@ -74,22 +71,10 @@ static NPClass noScriptClass = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; NPClass* NPScriptObjectClass = &javascriptClass; static NPClass* NPNoScriptObjectClass = &noScriptClass; -static bool _isSafeScript(JavaScriptObject* obj) -{ - if (!obj->originRootObject || !obj->rootObject) - return true; - - if (!obj->originRootObject->isValid() || !obj->rootObject->isValid()) - return false; - - return obj->rootObject->globalObject()->allowsAccessFrom(obj->originRootObject->globalObject()); -} - -NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr originRootObject, PassRefPtr rootObject) +NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr rootObject) { JavaScriptObject* obj = (JavaScriptObject*)_NPN_CreateObject(npp, NPScriptObjectClass); - obj->originRootObject = originRootObject.releaseRef(); obj->rootObject = rootObject.releaseRef(); if (obj->rootObject) @@ -108,8 +93,6 @@ bool _NPN_InvokeDefault(NPP, NPObject* o, const NPVariant* args, uint32_t argCou { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; VOID_TO_NPVARIANT(*result); @@ -147,8 +130,6 @@ bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant* { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; PrivateIdentifier* i = (PrivateIdentifier*)methodName; if (!i->isString) @@ -205,9 +186,6 @@ bool _NPN_Evaluate(NPP, NPObject* o, NPString* s, NPVariant* variant) if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; - RootObject* rootObject = obj->rootObject; if (!rootObject || !rootObject->isValid()) return false; @@ -246,8 +224,6 @@ bool _NPN_GetProperty(NPP, NPObject* o, NPIdentifier propertyName, NPVariant* va { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; RootObject* rootObject = obj->rootObject; if (!rootObject || !rootObject->isValid()) @@ -289,8 +265,6 @@ bool _NPN_SetProperty(NPP, NPObject* o, NPIdentifier propertyName, const NPVaria { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; RootObject* rootObject = obj->rootObject; if (!rootObject || !rootObject->isValid()) @@ -316,8 +290,6 @@ bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName) { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; RootObject* rootObject = obj->rootObject; if (!rootObject || !rootObject->isValid()) @@ -348,8 +320,6 @@ bool _NPN_HasProperty(NPP, NPObject* o, NPIdentifier propertyName) { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; RootObject* rootObject = obj->rootObject; if (!rootObject || !rootObject->isValid()) @@ -373,8 +343,6 @@ bool _NPN_HasMethod(NPP, NPObject* o, NPIdentifier methodName) { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; PrivateIdentifier* i = (PrivateIdentifier*)methodName; if (!i->isString) @@ -414,8 +382,6 @@ bool _NPN_Enumerate(NPP, NPObject *o, NPIdentifier **identifier, uint32_t *count { if (o->_class == NPScriptObjectClass) { JavaScriptObject* obj = (JavaScriptObject*)o; - if (!_isSafeScript(obj)) - return false; RootObject* rootObject = obj->rootObject; if (!rootObject || !rootObject->isValid()) diff --git a/JavaScriptCore/bindings/NP_jsobject.h b/JavaScriptCore/bindings/NP_jsobject.h index 3f24532fc215..6e3d84174d1f 100644 --- a/JavaScriptCore/bindings/NP_jsobject.h +++ b/JavaScriptCore/bindings/NP_jsobject.h @@ -44,11 +44,10 @@ struct JavaScriptObject { NPObject object; KJS::JSObject* imp; - KJS::Bindings::RootObject* originRootObject; KJS::Bindings::RootObject* rootObject; }; -NPObject* _NPN_CreateScriptObject(NPP npp, KJS::JSObject*, PassRefPtr originRootObject, PassRefPtr rootObject); +NPObject* _NPN_CreateScriptObject(NPP npp, KJS::JSObject*, PassRefPtr rootObject); NPObject* _NPN_CreateNoScriptObject(void); #endif diff --git a/JavaScriptCore/bindings/c/c_utility.cpp b/JavaScriptCore/bindings/c/c_utility.cpp index 50c93e8d0669..7e2a19f79ef0 100644 --- a/JavaScriptCore/bindings/c/c_utility.cpp +++ b/JavaScriptCore/bindings/c/c_utility.cpp @@ -115,19 +115,11 @@ void convertValueToNPVariant(ExecState *exec, JSValue *value, NPVariant *result) OBJECT_TO_NPVARIANT(obj, *result); } } else { - JSGlobalObject* originGlobalObject = exec->dynamicGlobalObject(); - RootObject* originRootObject = findRootObject(originGlobalObject); - - JSGlobalObject* globalObject = 0; - if (object->isGlobalObject()) - globalObject = static_cast(object); - - if (!globalObject) - globalObject = originGlobalObject; + JSGlobalObject* globalObject = exec->dynamicGlobalObject(); RootObject* rootObject = findRootObject(globalObject); if (rootObject) { - NPObject* npObject = _NPN_CreateScriptObject(0, object, originRootObject, rootObject); + NPObject* npObject = _NPN_CreateScriptObject(0, object, rootObject); OBJECT_TO_NPVARIANT(npObject, *result); } } diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 94582eedf82d..c4d29df8c2ad 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,17 @@ +2007-12-14 Anders Carlsson + + Reviewed by Darin and Geoff. + + + REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) + + Add cross frame plug/in test where a plug/in inside an iframe tries to access properties of the + top-level frame. + + * http/tests/plugins/cross-frame-object-access-expected.txt: Added. + * http/tests/plugins/cross-frame-object-access.html: Added. + * http/tests/plugins/resources/cross-frame-object-access.html: Added. + 2007-12-14 Oliver Hunt Reviewed by Adam. @@ -178,7 +192,7 @@ * svg/custom/inline-svg-in-xhtml-expected.checksum: Added. * svg/custom/inline-svg-in-xhtml-expected.png: Added. -2007-12-11 Anders Carlsson +2007-12-12 Anders Carlsson Reviewed by Sam. diff --git a/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt b/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt new file mode 100644 index 000000000000..91b7235434dc --- /dev/null +++ b/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt @@ -0,0 +1,20 @@ +CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://127.0.0.1:8000/plugins/cross-frame-object-access.html from frame with URL http://localhost:8000/plugins/resources/cross-frame-object-access.html. Domains, protocols and ports must match. + +CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://127.0.0.1:8000/plugins/cross-frame-object-access.html from frame with URL http://localhost:8000/plugins/resources/cross-frame-object-access.html. Domains, protocols and ports must match. + +CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://127.0.0.1:8000/plugins/cross-frame-object-access.html from frame with URL http://localhost:8000/plugins/resources/cross-frame-object-access.html. Domains, protocols and ports must match. + +CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://127.0.0.1:8000/plugins/cross-frame-object-access.html from frame with URL http://localhost:8000/plugins/resources/cross-frame-object-access.html. Domains, protocols and ports must match. + +CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://127.0.0.1:8000/plugins/cross-frame-object-access.html from frame with URL http://localhost:8000/plugins/resources/cross-frame-object-access.html. Domains, protocols and ports must match. + +CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://127.0.0.1:8000/plugins/cross-frame-object-access.html from frame with URL http://localhost:8000/plugins/resources/cross-frame-object-access.html. Domains, protocols and ports must match. + + + +-------- +Frame: 'childFrame' +-------- + +This tests that plug-ins can access objects in other frames as allowed by the security model enforced in WebCore. +SUCCESS diff --git a/LayoutTests/http/tests/plugins/cross-frame-object-access.html b/LayoutTests/http/tests/plugins/cross-frame-object-access.html new file mode 100644 index 000000000000..002073337c35 --- /dev/null +++ b/LayoutTests/http/tests/plugins/cross-frame-object-access.html @@ -0,0 +1,11 @@ + + + + + + diff --git a/LayoutTests/http/tests/plugins/resources/cross-frame-object-access.html b/LayoutTests/http/tests/plugins/resources/cross-frame-object-access.html new file mode 100644 index 000000000000..f03f2eb11f90 --- /dev/null +++ b/LayoutTests/http/tests/plugins/resources/cross-frame-object-access.html @@ -0,0 +1,78 @@ + + + + + + +
This tests that plug-ins can access objects in other frames as allowed by the security model enforced in WebCore.
+
    +
+
FAILURE
+ + diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index 0af29b07a5bf..0d16d186f780 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,17 @@ +2007-12-14 Anders Carlsson + + Reviewed by Darin and Geoff. + + + REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) + + _NPN_CreateScriptObject doesn't take an origin root object anymore. + + * html/HTMLPlugInElement.cpp: + (WebCore::HTMLPlugInElement::createNPObject): + * page/Frame.cpp: + (WebCore::Frame::windowScriptNPObject): + 2007-12-14 Dan Bernstein Reviewed by Darin Adler. diff --git a/WebCore/html/HTMLPlugInElement.cpp b/WebCore/html/HTMLPlugInElement.cpp index f1658e4a41db..fd91273d6825 100644 --- a/WebCore/html/HTMLPlugInElement.cpp +++ b/WebCore/html/HTMLPlugInElement.cpp @@ -192,7 +192,7 @@ NPObject* HTMLPlugInElement::createNPObject() // Wrap the JSObject in an NPObject RootObject* rootObject = frame->bindingRootObject(); - return _NPN_CreateScriptObject(0, jsElementValue->getObject(), rootObject, rootObject); + return _NPN_CreateScriptObject(0, jsElementValue->getObject(), rootObject); } NPObject* HTMLPlugInElement::getNPObject() diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index 1aba62f6f732..2905a4dab228 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -1107,7 +1107,7 @@ NPObject* Frame::windowScriptNPObject() KJS::JSObject* win = KJS::Window::retrieveWindow(this); ASSERT(win); KJS::Bindings::RootObject* root = bindingRootObject(); - d->m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root, root); + d->m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root); } else { // JavaScript is not enabled, so we cannot bind the NPObject to the JavaScript window object. // Instead, we create an NPObject of a different class, one which is not bound to a JavaScript object. diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog index 8be7a5c7dd5a..55fa25769941 100644 --- a/WebKitTools/ChangeLog +++ b/WebKitTools/ChangeLog @@ -1,3 +1,15 @@ +2007-12-14 Anders Carlsson + + Reviewed by Darin and Geoff. + + + REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9) + + Add property getting methods to the plug-in. + + * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: + (pluginInvoke): + 2007-12-14 Kevin McCullough Reviewed by Darin. @@ -50,7 +62,7 @@ * DumpRenderTree/win/LayoutTestControllerWin.cpp: (LayoutTestController::pathToLocalResource): -2007-12-11 Anders Carlsson +2007-12-12 Anders Carlsson Reviewed by Sam. diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp index 8680a4f92e2e..eed2261e8dcd 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp @@ -94,7 +94,9 @@ static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { #define ID_DESTROY_STREAM 6 #define ID_TEST_ENUMERATE 7 #define ID_TEST_GETINTIDENTIFIER 8 -#define NUM_METHOD_IDENTIFIERS 9 +#define ID_TEST_GET_PROPERTY 9 +#define ID_TEST_EVALUATE 10 +#define NUM_METHOD_IDENTIFIERS 11 static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { @@ -106,7 +108,9 @@ static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { "testInvokeDefault", "destroyStream", "testEnumerate", - "testGetIntIdentifier" + "testGetIntIdentifier", + "testGetProperty", + "testEvaluate", }; static NPUTF8* createCStringFromNPVariant(const NPVariant *variant) @@ -315,6 +319,44 @@ static bool pluginInvoke(NPObject *header, NPIdentifier name, const NPVariant *a INT32_TO_NPVARIANT((int32)identifier, *result); return true; } + } else if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE] && + argCount == 1 && NPVARIANT_IS_STRING(args[0])) { + NPObject *windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPString s = NPVARIANT_TO_STRING(args[0]); + + bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result); + browser->releaseobject(windowScriptObject); + return retval; + } else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY] && + argCount > 0) { + NPObject *object; + browser->getvalue(obj->npp, NPNVWindowNPObject, &object); + + for (uint32_t i = 0; i < argCount; i++) { + assert(NPVARIANT_IS_STRING(args[i])); + char *propertyString = createCStringFromNPVariant(&args[i]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + + NPVariant variant; + bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant); + browser->releaseobject(object); + + if (!retval) + break; + + if (i + 1 < argCount) { + assert(NPVARIANT_IS_OBJECT(variant)); + object = NPVARIANT_TO_OBJECT(variant); + } else { + *result = variant; + return true; + } + } + + VOID_TO_NPVARIANT(*result); + return false; } return false; -- 2.36.0