1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the IDispatch implementation for XPConnect.
16
* The Initial Developer of the Original Code is
18
* Portions created by the Initial Developer are Copyright (C) 2002
19
* the Initial Developer. All Rights Reserved.
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
35
* ***** END LICENSE BLOCK ***** */
37
#include "xpcprivate.h"
39
static const char* const IDISPATCH_NAME = "IDispatch";
41
PRBool XPCIDispatchExtension::mIsEnabled = PR_TRUE;
44
CommonConstructor(JSContext *cx, int name, JSObject *obj, uintN argc,
45
jsval *argv, jsval *rval, PRBool enforceSecurity)
47
XPCCallContext ccx(JS_CALLER, cx, JS_GetGlobalObject(cx));
48
// Check if IDispatch is enabled, fail if not
49
if(!nsXPConnect::IsIDispatchEnabled())
51
XPCThrower::Throw(NS_ERROR_XPC_IDISPATCH_NOT_ENABLED, ccx);
54
XPCJSRuntime *rt = ccx.GetRuntime();
57
XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx);
60
nsIXPCSecurityManager* sm = ccx.GetXPCContext()
61
->GetAppropriateSecurityManager(nsIXPCSecurityManager::HOOK_CALL_METHOD);
62
XPCWrappedNative * wrapper = ccx.GetWrapper();
63
if(sm && NS_FAILED(sm->CanAccess(nsIXPCSecurityManager::ACCESS_CALL_METHOD,
64
&ccx, ccx, ccx.GetFlattenedJSObject(),
65
wrapper->GetIdentityObject(),
66
wrapper->GetClassInfo(),
67
rt->GetStringJSVal(name),
68
wrapper->GetSecurityInfoAddr())))
70
// Security manager will have set an exception
73
// Make sure we were called with one string parameter
74
if(argc != 1 || (argc == 1 && !JSVAL_IS_STRING(argv[0])))
76
XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
80
jschar * className = xpc_JSString2String(ccx, argv[0], &len);
81
CComBSTR bstrClassName(len, className);
84
XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
87
// Instantiate the desired COM object
88
CComPtr<IDispatch> pDispatch;
89
HRESULT rv = XPCDispObject::COMCreateInstance(ccx, bstrClassName,
90
enforceSecurity, &pDispatch);
93
XPCThrower::ThrowCOMError(ccx, rv, NS_ERROR_XPC_COM_CREATE_FAILED);
96
// Get a wrapper for our object
97
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
98
nsresult nsrv = ccx.GetXPConnect()->WrapNative(
99
ccx, ccx.GetOperandJSObject(), NS_REINTERPRET_CAST(nsISupports*, pDispatch.p),
100
NSID_IDISPATCH, getter_AddRefs(holder));
103
XPCThrower::Throw(nsrv, ccx);
106
// get and return the JS object wrapper
108
nsrv = holder->GetJSObject(&jsobj);
111
XPCThrower::Throw(nsrv, ccx);
114
*rval = OBJECT_TO_JSVAL(jsobj);
118
JS_STATIC_DLL_CALLBACK(JSBool)
119
COMObjectConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
122
return CommonConstructor(cx, XPCJSRuntime::IDX_COM_OBJECT, obj, argc,
123
argv, rval, PR_FALSE);
126
JS_STATIC_DLL_CALLBACK(JSBool)
127
ActiveXConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
130
return CommonConstructor(cx, XPCJSRuntime::IDX_ACTIVEX_OBJECT, obj, argc, argv,
134
JS_STATIC_DLL_CALLBACK(JSBool)
135
ActiveXSupports(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
138
XPCCallContext ccx(JS_CALLER, cx, JS_GetGlobalObject(cx));
139
// Check if IDispatch is enabled, fail if not
140
if(!nsXPConnect::IsIDispatchEnabled())
142
XPCThrower::Throw(NS_ERROR_XPC_IDISPATCH_NOT_ENABLED, ccx);
145
XPCJSRuntime *rt = ccx.GetRuntime();
148
XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx);
151
// Make sure we were called with one string parameter
152
if(argc != 1 || (argc == 1 && !JSVAL_IS_STRING(argv[0])))
154
XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
158
jschar * className = xpc_JSString2String(ccx, argv[0], &len);
159
CComBSTR bstrClassName(len, className);
162
XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
165
CLSID classID = CLSID_NULL;
166
HRESULT hr = CLSIDFromString(bstrClassName, &classID);
167
if(FAILED(hr) || ::IsEqualCLSID(classID, CLSID_NULL))
169
XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
172
// Instantiate the desired COM object
173
HRESULT rv = XPCDispObject::SecurityCheck(ccx, classID);
174
*rval = BOOLEAN_TO_JSVAL(SUCCEEDED(rv));
178
class xpcFunctionDefiner
181
xpcFunctionDefiner(JSContext * aJSContext);
182
JSFunction * Define(JSObject * globalObject, uintN aNameIndex,
185
XPCJSRuntime * m_Runtime;
186
JSContext * m_JSContext;
190
xpcFunctionDefiner::xpcFunctionDefiner(JSContext * aJSContext) :
191
m_Runtime(nsXPConnect::GetRuntime()), m_JSContext(aJSContext)
193
NS_ASSERTION(m_Runtime, "nsXPConnect::GetRuntime() returned null");
194
NS_ASSERTION(aJSContext, "xpcFunctionDefiner constructor passed a null context");
198
JSFunction * xpcFunctionDefiner::Define(JSObject * globalObject,
199
uintN aNameIndex, JSNative aCall)
201
return JS_DefineFunction(m_JSContext, globalObject,
202
m_Runtime->GetStringName(aNameIndex),
203
aCall, 1, JSPROP_PERMANENT | JSPROP_READONLY);
206
JSBool XPCIDispatchExtension::Initialize(JSContext * aJSContext,
207
JSObject * aGlobalJSObj)
209
xpcFunctionDefiner fd(aJSContext);
210
JSFunction * func = fd.Define(aGlobalJSObj,
211
XPCJSRuntime::IDX_ACTIVEX_OBJECT,
216
JSObject * funcObject = JS_GetFunctionObject(func);
220
if(!fd.Define(funcObject, XPCJSRuntime::IDX_ACTIVEX_SUPPORTS, ActiveXSupports))
224
if(!fd.Define(aGlobalJSObj, XPCJSRuntime::IDX_COM_OBJECT, COMObjectConstructor))
230
JSBool XPCIDispatchExtension::DefineProperty(XPCCallContext & ccx,
231
JSObject *obj, jsval idval,
232
XPCWrappedNative* wrapperToReflectInterfaceNames,
233
uintN propFlags, JSBool* resolved)
235
if(!JSVAL_IS_STRING(idval))
237
// Look up the native interface for IDispatch and then find a tearoff
238
XPCNativeInterface* iface = XPCNativeInterface::GetNewOrUsed(ccx,
242
XPCWrappedNativeTearOff* to =
243
wrapperToReflectInterfaceNames->FindTearOff(ccx, iface, JS_TRUE);
246
// get the JS Object for the tea
247
JSObject* jso = to->GetJSObject();
250
// Look up the member in the interface
251
const XPCDispInterface::Member * member = to->GetIDispatchInfo()->FindMember(idval);
254
// IDispatch is case insensitive, so if we don't find a case sensitive
255
// match, we'll try a more expensive case-insensisitive search
256
// TODO: We need to create cleaner solution that doesn't create
257
// multiple properties of different case on the JS Object
258
member = to->GetIDispatchInfo()->FindMemberCI(ccx, idval);
262
// Get the function object
264
if(!member->GetValue(ccx, iface, &funval))
267
AUTO_MARK_JSVAL(ccx, funval);
268
// clone a function we can use for this object
269
JSObject* funobj = JS_CloneFunctionObject(ccx, JSVAL_TO_OBJECT(funval), obj);
273
// If this is a function or a parameterized property
274
if(member->IsFunction() || member->IsParameterizedProperty())
276
// define the function on the object
277
AutoResolveName arn(ccx, idval);
280
return JS_ValueToId(ccx, idval, &id) &&
281
OBJ_DEFINE_PROPERTY(ccx, obj, id, OBJECT_TO_JSVAL(funobj),
282
nsnull, nsnull, propFlags, nsnull);
284
// Define the property on the object
285
NS_ASSERTION(member->IsProperty(), "way broken!");
286
propFlags |= JSPROP_GETTER | JSPROP_SHARED;
287
if(member->IsSetter())
289
propFlags |= JSPROP_SETTER;
290
propFlags &= ~JSPROP_READONLY;
292
AutoResolveName arn(ccx, idval);
295
return JS_ValueToId(ccx, idval, &id) &&
296
OBJ_DEFINE_PROPERTY(ccx, obj, id, JSVAL_VOID,
297
(JSPropertyOp) funobj,
298
(JSPropertyOp) funobj,
303
JSBool XPCIDispatchExtension::Enumerate(XPCCallContext& ccx, JSObject* obj,
304
XPCWrappedNative * wrapper)
306
XPCNativeInterface* iface = XPCNativeInterface::GetNewOrUsed(
307
ccx,&NSID_IDISPATCH);
311
XPCWrappedNativeTearOff* tearoff = wrapper->FindTearOff(ccx, iface);
315
XPCDispInterface* pInfo = tearoff->GetIDispatchInfo();
316
PRUint32 members = pInfo->GetMemberCount();
317
// Iterate over the members and force the properties to be resolved
318
for(PRUint32 index = 0; index < members; ++index)
320
const XPCDispInterface::Member & member = pInfo->GetMember(index);
321
jsval name = member.GetName();
322
if(!xpc_ForcePropertyResolve(ccx, obj, name))
328
nsresult XPCIDispatchExtension::IDispatchQIWrappedJS(nsXPCWrappedJS * self,
329
void ** aInstancePtr)
331
// Lookup the root and create a tearoff based on that
332
nsXPCWrappedJS* root = self->GetRootWrapper();
336
*aInstancePtr = nsnull;
337
return NS_NOINTERFACE;
339
XPCDispatchTearOff* tearOff = new XPCDispatchTearOff(root);
341
return NS_ERROR_OUT_OF_MEMORY;
343
*aInstancePtr = tearOff;