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