VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/python/src/PyGBase.cpp@ 101955

Last change on this file since 101955 was 101955, checked in by vboxsync, 7 months ago

libs/xpcom/python: Convert to IPRT and remove some dead code, bugref:10545

  • Property svn:eol-style set to native
File size: 28.6 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
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/
8 *
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
12 * License.
13 *
14 * The Original Code is the Python XPCOM language bindings.
15 *
16 * The Initial Developer of the Original Code is
17 * ActiveState Tool Corp.
18 * Portions created by the Initial Developer are Copyright (C) 2000
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 * Mark Hammond <mhammond@skippinet.com.au> (original author)
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38// PyGBase.cpp - implementation of the PyG_Base class
39//
40// This code is part of the XPCOM extensions for Python.
41//
42// Written May 2000 by Mark Hammond.
43//
44// Based heavily on the Python COM support, which is
45// (c) Mark Hammond and Greg Stein.
46//
47// (c) 2000, ActiveState corp.
48
49#include "PyXPCOM_std.h"
50#include <nsIModule.h>
51#include <nsIComponentLoader.h>
52#include <nsIInputStream.h>
53
54#include <iprt/asm.h>
55
56static uint32_t cGateways = 0;
57uint32_t _PyXPCOM_GetGatewayCount(void)
58{
59 return cGateways;
60}
61
62extern PyG_Base *MakePyG_nsIModule(PyObject *);
63extern PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance);
64extern PyG_Base *MakePyG_nsIInputStream(PyObject *instance);
65
66static char *PyXPCOM_szDefaultGatewayAttributeName = (char*)"_com_instance_default_gateway_";
67PyG_Base *GetDefaultGateway(PyObject *instance);
68void AddDefaultGateway(PyObject *instance, nsISupports *gateway);
69PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway);
70
71/*static*/ nsresult
72PyG_Base::CreateNew(PyObject *pPyInstance, const nsIID &iid, void **ppResult)
73{
74 NS_PRECONDITION(ppResult && *ppResult==NULL, "NULL or uninitialized pointer");
75 if (ppResult==nsnull)
76 return NS_ERROR_NULL_POINTER;
77
78 PyG_Base *ret;
79 // Hack for few extra gateways we support.
80 if (iid.Equals(NS_GET_IID(nsIModule)))
81 ret = MakePyG_nsIModule(pPyInstance);
82 else if (iid.Equals(NS_GET_IID(nsIComponentLoader)))
83 ret = MakePyG_nsIComponentLoader(pPyInstance);
84 else if (iid.Equals(NS_GET_IID(nsIInputStream)))
85 ret = MakePyG_nsIInputStream(pPyInstance);
86 else
87 ret = new PyXPCOM_XPTStub(pPyInstance, iid);
88 if (ret==nsnull)
89 return NS_ERROR_OUT_OF_MEMORY;
90 ret->AddRef(); // The first reference for the caller.
91 *ppResult = ret->ThisAsIID(iid);
92 NS_ABORT_IF_FALSE(*ppResult != NULL, "ThisAsIID() gave NULL, but we know it supports it!");
93 return *ppResult ? NS_OK : NS_ERROR_FAILURE;
94}
95
96PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid)
97{
98 // Note that "instance" is the _policy_ instance!!
99 ASMAtomicIncU32(&cGateways);
100 m_pBaseObject = GetDefaultGateway(instance);
101 // m_pWeakRef is an nsCOMPtr and needs no init.
102
103 NS_ABORT_IF_FALSE(!(iid.Equals(NS_GET_IID(nsISupportsWeakReference)) || iid.Equals(NS_GET_IID(nsIWeakReference))),"Should not be creating gateways with weak-ref interfaces");
104 m_iid = iid;
105 m_pPyObject = instance;
106 NS_PRECONDITION(instance, "NULL PyObject for PyXPCOM_XPTStub!");
107
108#ifdef NS_BUILD_REFCNT_LOGGING
109 // If XPCOM reference count logging is enabled, then allow us to give the Python class.
110 PyObject *realInstance = PyObject_GetAttrString(instance, "_obj_");
111 PyObject *r = PyObject_Repr(realInstance);
112 const char *szRepr;
113 if (r==NULL) {
114 PyXPCOM_LogError("Getting the __repr__ of the object failed");
115 PyErr_Clear();
116 szRepr = "(repr failed!)";
117 }
118 else
119#if PY_MAJOR_VERSION <= 2
120 szRepr = PyString_AsString(r);
121#else
122 szRepr = PyUnicode_AsUTF8(r);
123#endif
124 if (szRepr==NULL) szRepr = "";
125 int reprOffset = *szRepr=='<' ? 1 : 0;
126 static const char *reprPrefix = "component:";
127 if (strncmp(reprPrefix, szRepr+reprOffset, strlen(reprPrefix)) == 0)
128 reprOffset += strlen(reprPrefix);
129 strncpy(refcntLogRepr, szRepr + reprOffset, sizeof(refcntLogRepr)-1);
130 refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0';
131 // See if we should get rid of the " at 0x12345" portion.
132 char *lastPos = strstr(refcntLogRepr, " at ");
133 if (lastPos) *lastPos = '\0';
134 Py_XDECREF(realInstance);
135 Py_XDECREF(r);
136#endif // NS_BUILD_REFCNT_LOGGING
137
138#ifdef DEBUG_LIFETIMES
139 {
140 char *iid_repr;
141 nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
142 if (iim!=nsnull)
143 iim->GetNameForIID(&iid, &iid_repr);
144 PyObject *real_instance = PyObject_GetAttrString(instance, "_obj_");
145 PyObject *real_repr = PyObject_Repr(real_instance);
146
147 PYXPCOM_LOG_DEBUG("PyG_Base created at %p\n instance_repr=%s\n IID=%s\n", this, PyString_AsString(real_repr), iid_repr);
148 nsMemory::Free(iid_repr);
149 Py_XDECREF(real_instance);
150 Py_XDECREF(real_repr);
151 }
152#endif // DEBUG_LIFETIMES
153 Py_XINCREF(instance); // instance should never be NULL - but whats an X between friends!
154
155 PyXPCOM_DLLAddRef();
156
157#ifdef DEBUG_FULL
158 LogF("PyGatewayBase: created %s", m_pPyObject ? PyXPCOM_ObTypeName(m_pPyObject) : "<NULL>");
159#endif
160}
161
162PyG_Base::~PyG_Base()
163{
164 ASMAtomicDecU32(&cGateways);
165#ifdef DEBUG_LIFETIMES
166 PYXPCOM_LOG_DEBUG("PyG_Base: deleted %p", this);
167#endif
168 if ( m_pPyObject ) {
169 CEnterLeavePython celp;
170 Py_DECREF(m_pPyObject);
171 }
172 if (m_pBaseObject)
173 m_pBaseObject->Release();
174 if (m_pWeakRef) {
175 // Need to ensure some other thread isnt doing a QueryReferent on
176 // our weak reference at the same time
177 CEnterLeaveXPCOMFramework _celf;
178 PyXPCOM_GatewayWeakReference *p = (PyXPCOM_GatewayWeakReference *)(nsISupports *)m_pWeakRef;
179 p->m_pBase = nsnull;
180 m_pWeakRef = nsnull;
181 }
182 PyXPCOM_DLLRelease();
183}
184
185// Get the correct interface pointer for this object given the IID.
186void *PyG_Base::ThisAsIID( const nsIID &iid )
187{
188 if (this==NULL) return NULL;
189 if (iid.Equals(NS_GET_IID(nsISupports)))
190 return (nsISupports *)(nsIInternalPython *)this;
191 if (iid.Equals(NS_GET_IID(nsISupportsWeakReference)))
192 return (nsISupportsWeakReference *)this;
193 if (iid.Equals(NS_GET_IID(nsIInternalPython)))
194 return (nsISupports *)(nsIInternalPython *)this;
195 return NULL;
196}
197
198// Call back into Python, passing a Python instance, and get back
199// an interface object that wraps the instance.
200/*static*/ PRBool
201PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **ppret)
202{
203 NS_PRECONDITION(ppret!=NULL, "null pointer when wrapping a Python instance!");
204 NS_PRECONDITION(ob && PyObject_HasAttrString(ob, "__class__"),
205 "AutoWrapPythonInstance is expecting an non-NULL instance!");
206 PRBool ok = PR_FALSE;
207 // XXX - todo - this static object leaks! (but Python on Windows leaks 2000+ objects as it is ;-)
208 static PyObject *func = NULL; // fetch this once and remember!
209 PyObject *obIID = NULL;
210 PyObject *wrap_ret = NULL;
211 PyObject *args = NULL;
212 if (func==NULL) { // not thread-safe, but nothing bad can happen, except an extra reference leak
213 PyObject *mod = PyImport_ImportModule("xpcom.server");
214 if (mod)
215 func = PyObject_GetAttrString(mod, "WrapObject");
216 Py_XDECREF(mod);
217 if (func==NULL) goto done;
218 }
219 // See if the instance has previously been wrapped.
220 if (CheckDefaultGateway(ob, iid, ppret)) {
221 ok = PR_TRUE; // life is good!
222 } else {
223 PyErr_Clear();
224
225 obIID = Py_nsIID::PyObjectFromIID(iid);
226 if (obIID==NULL) goto done;
227 args = Py_BuildValue("OOzi", ob, obIID, NULL, 0);
228 if (args==NULL) goto done;
229 wrap_ret = PyEval_CallObject(func, args);
230 if (wrap_ret==NULL) goto done;
231 ok = Py_nsISupports::InterfaceFromPyObject(wrap_ret, iid, ppret, PR_FALSE, PR_FALSE);
232#ifdef DEBUG
233 if (ok)
234 // Check we _now_ have a default gateway
235 {
236 nsISupports *temp = NULL;
237 NS_ABORT_IF_FALSE(CheckDefaultGateway(ob, iid, &temp), "Auto-wrapped object didnt get a default gateway!");
238 if (temp) temp->Release();
239 }
240#endif
241 }
242done:
243// Py_XDECREF(func); -- func is static for performance reasons.
244 Py_XDECREF(obIID);
245 Py_XDECREF(wrap_ret);
246 Py_XDECREF(args);
247 return ok;
248}
249
250// Call back into Python, passing a raw nsIInterface object, getting back
251// the object to actually use as the gateway parameter for this interface.
252// For example, it is expected that the policy will wrap the interface
253// object in one of the xpcom.client.Interface objects, allowing
254// natural usage of the interface from Python clients.
255// Note that piid will usually be NULL - this is because the runtime
256// reflection interfaces dont provide this information to me.
257// In this case, the Python code may choose to lookup the complete
258// interface info to obtain the IID.
259// It is expected (but should not be assumed) that the method info
260// or the IID will be NULL.
261// Worst case, the code should provide a wrapper for the nsiSupports interface,
262// so at least the user can simply QI the object.
263PyObject *
264PyG_Base::MakeInterfaceParam(nsISupports *pis,
265 const nsIID *piid,
266 int methodIndex /* = -1 */,
267 const XPTParamDescriptor *d /* = NULL */,
268 int paramIndex /* = -1 */)
269{
270 if (pis==NULL) {
271 Py_INCREF(Py_None);
272 return Py_None;
273 }
274 // This condition is true today, but not necessarily so.
275 // But if it ever triggers, the poor Python code has no real hope
276 // of returning something useful, so we should at least do our
277 // best to provide the useful data.
278 NS_WARN_IF_FALSE( ((piid != NULL) ^ (d != NULL)) == 1, "No information on the interface available - Python's gunna have a hard time doing much with it!");
279 PyObject *obIID = NULL;
280 PyObject *obISupports = NULL;
281 PyObject *obParamDesc = NULL;
282 PyObject *result = NULL;
283
284 // get the basic interface first, as if we fail, we can try and use this.
285 // If we don't know the IID, we must explicitly query for nsISupports.
286 nsCOMPtr<nsISupports> piswrap;
287 nsIID iid_check;
288 if (piid) {
289 iid_check = *piid;
290 piswrap = pis;
291 } else {
292 /* HACK ALERT! Dropping the python interpreter lock here while
293 doing QueryInterface because it may involve IPC to a python
294 object in the same interpreter and deadlock. Not at all
295 sure if this is a good idea or not for the internal PyXPCOM
296 state, but it might fix the deadloock... Hoping for the best. */
297 Py_BEGIN_ALLOW_THREADS;
298 iid_check = NS_GET_IID(nsISupports);
299 pis->QueryInterface(iid_check, getter_AddRefs(piswrap));
300 Py_END_ALLOW_THREADS;
301 }
302
303 obISupports = Py_nsISupports::PyObjectFromInterface(piswrap, iid_check, PR_FALSE);
304 if (!obISupports)
305 goto done;
306 if (piid==NULL) {
307 obIID = Py_None;
308 Py_INCREF(Py_None);
309 } else
310 obIID = Py_nsIID::PyObjectFromIID(*piid);
311 if (obIID==NULL)
312 goto done;
313 obParamDesc = PyObject_FromXPTParamDescriptor(d);
314 if (obParamDesc==NULL)
315 goto done;
316
317 result = PyObject_CallMethod(m_pPyObject,
318 (char*)"_MakeInterfaceParam_",
319 (char*)"OOiOi",
320 obISupports,
321 obIID,
322 methodIndex,
323 obParamDesc,
324 paramIndex);
325done:
326 if (PyErr_Occurred()) {
327 NS_WARN_IF_FALSE(result==NULL, "Have an error, but also a result!");
328 PyXPCOM_LogError("Wrapping an interface object for the gateway failed\n");
329 }
330 Py_XDECREF(obIID);
331 Py_XDECREF(obParamDesc);
332 if (result==NULL) { // we had an error.
333 PyErr_Clear(); // but are not reporting it back to Python itself!
334 // return our obISupports. If NULL, we are really hosed and nothing we can do.
335 return obISupports;
336 }
337 // Dont need to return this - we have a better result.
338 Py_XDECREF(obISupports);
339 return result;
340}
341
342NS_IMETHODIMP
343PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
344{
345#ifdef PYXPCOM_DEBUG_FULL
346 {
347 char *sziid = iid.ToString();
348 LogF("PyGatewayBase::QueryInterface: %s", sziid);
349 Allocator::Free(sziid);
350 }
351#endif
352 NS_PRECONDITION(ppv, "NULL pointer");
353 if (ppv==nsnull)
354 return NS_ERROR_NULL_POINTER;
355 *ppv = nsnull;
356 // If one of our native interfaces (but NOT nsISupports if we have a base)
357 // return this.
358 // It is important is that nsISupports come from the base object
359 // to ensure that we live by XPCOM identity rules (other interfaces need
360 // not abide by this rule - only nsISupports.)
361 if ( (m_pBaseObject==NULL || !iid.Equals(NS_GET_IID(nsISupports)))
362 && (*ppv=ThisAsIID(iid)) != NULL ) {
363 AddRef();
364 return NS_OK;
365 }
366 // If we have a "base object", then we need to delegate _every_ remaining
367 // QI to it.
368 if (m_pBaseObject != NULL)
369 return m_pBaseObject->QueryInterface(iid, ppv);
370
371 // Call the Python policy to see if it (says it) supports the interface
372 PRBool supports = PR_FALSE;
373 { // temp scope for Python lock
374 CEnterLeavePython celp;
375
376 PyObject * ob = Py_nsIID::PyObjectFromIID(iid);
377 // must say this is an 'internal' call, else we recurse QI into
378 // oblivion.
379 PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface(
380 (nsXPTCStubBase *)this,
381 iid, PR_FALSE, PR_TRUE);
382 if ( !ob || !this_interface_ob) {
383 Py_XDECREF(ob);
384 Py_XDECREF(this_interface_ob);
385 return NS_ERROR_OUT_OF_MEMORY;
386 }
387
388 PyObject *result = PyObject_CallMethod(m_pPyObject, (char*)"_QueryInterface_",
389 (char*)"OO",
390 this_interface_ob, ob);
391 Py_DECREF(ob);
392 Py_DECREF(this_interface_ob);
393
394 if ( result ) {
395 if (Py_nsISupports::InterfaceFromPyObject(result, iid, (nsISupports **)ppv, PR_TRUE)) {
396 // If OK, but NULL, _QI_ returned None, which simply means
397 // "no such interface"
398 supports = (*ppv!=NULL);
399 // result has been QI'd and AddRef'd all ready for return.
400 } else {
401 // Dump this message and any Python exception before
402 // reporting the fact that QI failed - this error
403 // may provide clues!
404 PyXPCOM_LogError("The _QueryInterface_ method returned an object of type '%s', but an interface was expected\n", PyXPCOM_ObTypeName(result));
405 // supports remains false
406 }
407 Py_DECREF(result);
408 } else {
409 NS_ABORT_IF_FALSE(PyErr_Occurred(), "Got NULL result, but no Python error flagged!");
410 NS_WARN_IF_FALSE(!supports, "Have failure with success flag set!");
411 PyXPCOM_LogError("The _QueryInterface_ processing failed.\n");
412 // supports remains false.
413 // We have reported the error, and are returning to COM,
414 // so we should clear it.
415 PyErr_Clear();
416 }
417 } // end of temp scope for Python lock - lock released here!
418 if ( !supports )
419 return NS_ERROR_NO_INTERFACE;
420 return NS_OK;
421}
422
423nsrefcnt
424PyG_Base::AddRef(void)
425{
426 nsrefcnt cnt = (nsrefcnt) ASMAtomicIncS32((volatile int32_t*)&mRefCnt);
427#ifdef NS_BUILD_REFCNT_LOGGING
428 // If we have no pBaseObject, then we need to ignore them
429 if (m_pBaseObject == NULL)
430 NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this));
431#endif
432 return cnt;
433}
434
435nsrefcnt
436PyG_Base::Release(void)
437{
438 nsrefcnt cnt = (nsrefcnt) ASMAtomicDecS32((volatile int32_t*)&mRefCnt);
439#ifdef NS_BUILD_REFCNT_LOGGING
440 if (m_pBaseObject == NULL)
441 NS_LOG_RELEASE(this, cnt, refcntLogRepr);
442#endif
443 if ( cnt == 0 )
444 delete this;
445 return cnt;
446}
447
448NS_IMETHODIMP
449PyG_Base::GetWeakReference(nsIWeakReference **ret)
450{
451 // always delegate back to the "base" gateway for the object, as this tear-off
452 // interface may not live as long as the base. So we recurse back to the base.
453 if (m_pBaseObject) {
454 NS_PRECONDITION(m_pWeakRef == nsnull, "Not a base object, but do have a weak-ref!");
455 return m_pBaseObject->GetWeakReference(ret);
456 }
457 NS_PRECONDITION(ret, "null pointer");
458 if (ret==nsnull) return NS_ERROR_INVALID_POINTER;
459 if (!m_pWeakRef) {
460 // First query for a weak reference - create it.
461 // XXX - this looks like it needs thread safety!?
462 m_pWeakRef = new PyXPCOM_GatewayWeakReference(this);
463 NS_ABORT_IF_FALSE(m_pWeakRef, "Shouldn't be able to fail creating a weak reference!");
464 if (!m_pWeakRef)
465 return NS_ERROR_UNEXPECTED;
466 }
467 *ret = m_pWeakRef;
468 (*ret)->AddRef();
469 return NS_OK;
470}
471
472nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName)
473{
474 nsresult rc = NS_OK;
475 if (PyErr_Occurred()) {
476 // The error handling - fairly involved, but worth it as
477 // good error reporting is critical for users to know WTF
478 // is going on - especially with TypeErrors etc in their
479 // return values (ie, after the Python code has successfully
480 // exited, but we encountered errors unpacking their
481 // result values for the COM caller - there is literally no
482 // way to catch these exceptions from Python code, as their
483 // is no Python function directly on the call-stack)
484
485 // First line of attack in an error is to call-back on the policy.
486 // If the callback of the error handler succeeds and returns an
487 // integer (for the nsresult), we take no further action.
488
489 // If this callback fails, we log _2_ exceptions - the error
490 // handler error, and the original error.
491
492 PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing!
493 PyObject *exc_typ, *exc_val, *exc_tb;
494 PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
495
496 PyObject *err_result = PyObject_CallMethod(m_pPyObject,
497 (char*)"_GatewayException_",
498 (char*)"z(OOO)",
499 szMethodName,
500 exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming...
501 exc_val ? exc_val : Py_None, // may well be NULL.
502 exc_tb ? exc_tb : Py_None); // may well be NULL.
503 if (err_result == NULL) {
504 PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n");
505 } else if (err_result == Py_None) {
506 // The exception handler has chosen not to do anything with
507 // this error, so we still need to print it!
508 ;
509 } else if (PyInt_Check(err_result)) {
510 // The exception handler has given us the nresult.
511 rc = PyInt_AsLong(err_result);
512 bProcessMainError = PR_FALSE;
513 } else {
514 // The exception handler succeeded, but returned other than
515 // int or None.
516 PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", PyXPCOM_ObTypeName(err_result));
517 }
518 Py_XDECREF(err_result);
519 PyErr_Restore(exc_typ, exc_val, exc_tb);
520 if (bProcessMainError) {
521 PyXPCOM_LogError("The function '%s' failed\n", szMethodName);
522 rc = PyXPCOM_SetCOMErrorFromPyException();
523 }
524 PyErr_Clear();
525 }
526 return rc;
527}
528
529static nsresult do_dispatch(
530 PyObject *pPyObject,
531 PyObject **ppResult,
532 const char *szMethodName,
533 const char *szFormat,
534 va_list va
535 )
536{
537 NS_PRECONDITION(ppResult, "Must provide a result buffer");
538 *ppResult = nsnull;
539 // Build the Invoke arguments...
540 PyObject *args = NULL;
541 PyObject *method = NULL;
542 PyObject *real_ob = NULL;
543 nsresult ret = NS_ERROR_FAILURE;
544 if ( szFormat )
545 args = Py_VaBuildValue((char *)szFormat, va);
546 else
547 args = PyTuple_New(0);
548 if ( !args )
549 goto done;
550
551 // make sure a tuple.
552 if ( !PyTuple_Check(args) ) {
553 PyObject *a = PyTuple_New(1);
554 if ( a == NULL )
555 {
556 Py_DECREF(args);
557 goto done;
558 }
559 PyTuple_SET_ITEM(a, 0, args);
560 args = a;
561 }
562 // Bit to a hack here to maintain the use of a policy.
563 // We actually get the policies underlying object
564 // to make the call on.
565 real_ob = PyObject_GetAttrString(pPyObject, "_obj_");
566 if (real_ob == NULL) {
567 PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute.");
568 goto done;
569 }
570 method = PyObject_GetAttrString(real_ob, (char *)szMethodName);
571 if ( !method ) {
572 PyErr_Clear();
573 ret = NS_PYXPCOM_NO_SUCH_METHOD;
574 goto done;
575 }
576 // Make the call
577 *ppResult = PyEval_CallObject(method, args);
578 ret = *ppResult ? NS_OK : NS_ERROR_FAILURE;
579done:
580 Py_XDECREF(method);
581 Py_XDECREF(real_ob);
582 Py_XDECREF(args);
583 return ret;
584}
585
586
587nsresult PyG_Base::InvokeNativeViaPolicyInternal(
588 const char *szMethodName,
589 PyObject **ppResult,
590 const char *szFormat,
591 va_list va
592 )
593{
594 if ( m_pPyObject == NULL || szMethodName == NULL )
595 return NS_ERROR_NULL_POINTER;
596
597 PyObject *temp = nsnull;
598 if (ppResult == nsnull)
599 ppResult = &temp;
600 nsresult nr = do_dispatch(m_pPyObject, ppResult, szMethodName, szFormat, va);
601
602 // If temp is NULL, they provided a buffer, and we dont touch it.
603 // If not NULL, *ppResult = temp, and _we_ do own it.
604 Py_XDECREF(temp);
605 return nr;
606}
607
608nsresult PyG_Base::InvokeNativeViaPolicy(
609 const char *szMethodName,
610 PyObject **ppResult /* = NULL */,
611 const char *szFormat /* = NULL */,
612 ...
613 )
614{
615 va_list va;
616 va_start(va, szFormat);
617 nsresult nr = InvokeNativeViaPolicyInternal(szMethodName, ppResult, szFormat, va);
618 va_end(va);
619
620 if (nr == NS_PYXPCOM_NO_SUCH_METHOD) {
621 // Only problem was missing method.
622 PyErr_Format(PyExc_AttributeError, "The object does not have a '%s' function.", szMethodName);
623 }
624 return nr == NS_OK ? NS_OK : HandleNativeGatewayError(szMethodName);
625}
626
627nsresult PyG_Base::InvokeNativeGetViaPolicy(
628 const char *szPropertyName,
629 PyObject **ppResult /* = NULL */
630 )
631{
632 PyObject *ob_ret = NULL;
633 nsresult ret = NS_OK;
634 PyObject *real_ob = NULL;
635 if ( m_pPyObject == NULL || szPropertyName == NULL )
636 return NS_ERROR_NULL_POINTER;
637 // First see if we have a method of that name.
638 char buf[256];
639 strcpy(buf, "get_");
640 strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1);
641 buf[sizeof(buf)/sizeof(buf[0])-1] = '\0';
642 ret = InvokeNativeViaPolicyInternal(buf, ppResult, nsnull, nsnull);
643 if (ret == NS_PYXPCOM_NO_SUCH_METHOD) {
644 // No method of that name - just try a property.
645 // Bit to a hack here to maintain the use of a policy.
646 // We actually get the policies underlying object
647 // to make the call on.
648 real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_");
649 if (real_ob == NULL) {
650 PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute.");
651 ret = HandleNativeGatewayError(szPropertyName);
652 goto done;
653 }
654 ob_ret = PyObject_GetAttrString(real_ob, (char *)szPropertyName);
655 if (ob_ret==NULL) {
656 PyErr_Format(PyExc_AttributeError,
657 "The object does not have a 'get_%s' function, or a '%s attribute.",
658 szPropertyName, szPropertyName);
659 } else {
660 ret = NS_OK;
661 if (ppResult)
662 *ppResult = ob_ret;
663 else
664 Py_XDECREF(ob_ret);
665 }
666 }
667 if (ret != NS_OK)
668 ret = HandleNativeGatewayError(szPropertyName);
669
670done:
671 Py_XDECREF(real_ob);
672 return ret;
673}
674
675nsresult PyG_Base::InvokeNativeSetViaPolicy(
676 const char *szPropertyName,
677 ...
678 )
679{
680 if ( m_pPyObject == NULL || szPropertyName == NULL )
681 return NS_ERROR_NULL_POINTER;
682 nsresult ret = NS_OK;
683 PyObject *real_ob = NULL;
684 char buf[256];
685 strcpy(buf, "set_");
686 strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1);
687 buf[sizeof(buf)/sizeof(buf[0])-1] = '\0';
688 va_list va;
689 va_start(va, szPropertyName);
690 ret = InvokeNativeViaPolicyInternal(buf, NULL, "O", va);
691 va_end(va);
692 if (ret == NS_PYXPCOM_NO_SUCH_METHOD) {
693 // No method of that name - just try a property.
694 // Bit to a hack here to maintain the use of a policy.
695 // We actually get the policies underlying object
696 // to make the call on.
697 real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_");
698 if (real_ob == NULL) {
699 PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute.");
700 ret = HandleNativeGatewayError(szPropertyName);
701 goto done;
702 }
703 va_list va2;
704 va_start(va2, szPropertyName);
705 PyObject *arg = va_arg( va2, PyObject *);
706 va_end(va2);
707 if (PyObject_SetAttrString(real_ob, (char *)szPropertyName, arg) == 0)
708 ret = NS_OK;
709 else {
710 PyErr_Format(PyExc_AttributeError,
711 "The object does not have a 'set_%s' function, or a '%s attribute.",
712 szPropertyName, szPropertyName);
713 }
714 }
715 if (ret != NS_OK)
716 ret = HandleNativeGatewayError(szPropertyName);
717done:
718 Py_XDECREF(real_ob);
719 return ret;
720}
721
722// Get at the underlying Python object.
723PyObject *PyG_Base::UnwrapPythonObject(void)
724{
725 Py_INCREF(m_pPyObject);
726 return m_pPyObject;
727}
728/******************************************************
729
730 Some special support to help with object identity.
731
732 In the simplest case, assume a Python XPCOM object is
733 supporting a function "nsIWhatever GetWhatever()",
734 so implements it as:
735 return self
736 it is almost certain they intend returning
737 the same COM OBJECT to the caller! Thus, if a user of this COM
738 object does:
739
740 p1 = foo.GetWhatever();
741 p2 = foo.GetWhatever();
742
743 We almost certainly expect p1==p2==foo.
744
745 We previously _did_ have special support for the "self"
746 example above, but this implements a generic scheme that
747 works for _all_ objects.
748
749 Whenever we are asked to "AutoWrap" a Python object, the
750 first thing we do is see if it has been auto-wrapped before.
751
752 If not, we create a new wrapper, then make a COM weak reference
753 to that wrapper, and store it directly back into the instance
754 we are auto-wrapping! The use of a weak-reference prevents
755 cycles.
756
757 The existance of this attribute in an instance indicates if it
758 has been previously auto-wrapped.
759
760 If it _has_ previously been auto-wrapped, we de-reference the
761 weak reference, and use that gateway.
762
763*********************************************************************/
764
765PyG_Base *GetDefaultGateway(PyObject *policy)
766{
767 // NOTE: Instance is the policy, not the real instance
768 PyObject *instance = PyObject_GetAttrString(policy, "_obj_");
769 if (instance == nsnull)
770 return nsnull;
771 PyObject *ob_existing_weak = PyObject_GetAttrString(instance, PyXPCOM_szDefaultGatewayAttributeName);
772 Py_DECREF(instance);
773 if (ob_existing_weak != NULL) {
774 PRBool ok = PR_TRUE;
775 nsCOMPtr<nsIWeakReference> pWeakRef;
776 ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak,
777 NS_GET_IID(nsIWeakReference),
778 getter_AddRefs(pWeakRef),
779 PR_FALSE));
780 Py_DECREF(ob_existing_weak);
781 nsISupports *pip;
782 if (ok) {
783 nsresult nr = pWeakRef->QueryReferent( NS_GET_IID(nsIInternalPython), (void **)&pip);
784 if (NS_FAILED(nr))
785 return nsnull;
786 return (PyG_Base *)(nsIInternalPython *)pip;
787 }
788 } else
789 PyErr_Clear();
790 return nsnull;
791}
792
793PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway)
794{
795 NS_ABORT_IF_FALSE(real_inst, "Did not have an _obj_ attribute");
796 if (real_inst==NULL) {
797 PyErr_Clear();
798 return PR_FALSE;
799 }
800 PyObject *ob_existing_weak = PyObject_GetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName);
801 if (ob_existing_weak != NULL) {
802 // We have an existing default, but as it is a weak reference, it
803 // may no longer be valid. Check it.
804 PRBool ok = PR_TRUE;
805 nsCOMPtr<nsIWeakReference> pWeakRef;
806 ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak,
807 NS_GET_IID(nsIWeakReference),
808 getter_AddRefs(pWeakRef),
809 PR_FALSE));
810 Py_DECREF(ob_existing_weak);
811 if (ok) {
812 Py_BEGIN_ALLOW_THREADS;
813 ok = NS_SUCCEEDED(pWeakRef->QueryReferent( iid, (void **)(ret_gateway)));
814 Py_END_ALLOW_THREADS;
815 }
816 if (!ok) {
817 // We have the attribute, but not valid - wipe it
818 // before restoring it.
819 if (0 != PyObject_DelAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName))
820 PyErr_Clear();
821 }
822 return ok;
823 }
824 PyErr_Clear();
825 return PR_FALSE;
826}
827
828void AddDefaultGateway(PyObject *instance, nsISupports *gateway)
829{
830 // NOTE: Instance is the _policy_!
831 PyObject *real_inst = PyObject_GetAttrString(instance, "_obj_");
832 NS_ABORT_IF_FALSE(real_inst, "Could not get the '_obj_' element");
833 if (!real_inst) return;
834 if (!PyObject_HasAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName)) {
835 nsCOMPtr<nsISupportsWeakReference> swr( do_QueryInterface((nsISupportsWeakReference *)(gateway)) );
836 NS_ABORT_IF_FALSE(swr, "Our gateway failed with a weak reference query");
837 // Create the new default gateway - get a weak reference for our gateway.
838 if (swr) {
839 nsCOMPtr<nsIWeakReference> pWeakReference;
840 swr->GetWeakReference( getter_AddRefs(pWeakReference) );
841 if (pWeakReference) {
842 PyObject *ob_new_weak = Py_nsISupports::PyObjectFromInterface(pWeakReference,
843 NS_GET_IID(nsIWeakReference),
844 PR_FALSE ); /* bMakeNicePyObject */
845 // pWeakReference reference consumed.
846 if (ob_new_weak) {
847 PyObject_SetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName, ob_new_weak);
848 Py_DECREF(ob_new_weak);
849 }
850 }
851 }
852 }
853 Py_DECREF(real_inst);
854}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use