Back to index

lightning-sunbird  0.9+nobinonly
PyXPCOM.h
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Python XPCOM language bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * ActiveState Tool Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Mark Hammond <mhammond@skippinet.com.au> (original author)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // PyXPCOM.h - the main header file for the Python XPCOM support.
00039 //
00040 // This code is part of the XPCOM extensions for Python.
00041 //
00042 // Written May 2000 by Mark Hammond.
00043 //
00044 // Based heavily on the Python COM support, which is
00045 // (c) Mark Hammond and Greg Stein.
00046 //
00047 // (c) 2000, ActiveState corp.
00048 
00049 #ifndef __PYXPCOM_H__
00050 #define __PYXPCOM_H__
00051 
00052 #ifdef XP_WIN
00053 #      ifdef BUILD_PYXPCOM
00054               /* We are building the main dll */
00055 #             define PYXPCOM_EXPORT __declspec(dllexport)
00056 #      else
00057               /* This module uses the dll */
00058 #             define PYXPCOM_EXPORT __declspec(dllimport)
00059 #      endif // BUILD_PYXPCOM
00060 
00061        // We need these libs!
00062 #      pragma comment(lib, "xpcom.lib")
00063 #      pragma comment(lib, "nspr4.lib")
00064 
00065 #else // XP_WIN
00066 #      define PYXPCOM_EXPORT
00067 #endif // XP_WIN
00068 
00069 
00070 // An IID we treat as NULL when passing as a reference.
00071 extern nsIID Py_nsIID_NULL;
00072 
00073 /*************************************************************************
00074 **************************************************************************
00075 
00076  Error and exception related function.
00077 
00078 **************************************************************************
00079 *************************************************************************/
00080 
00081 #define NS_PYXPCOM_NO_SUCH_METHOD \
00082   NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_PYXPCOM, 0)
00083 
00084 // The exception object (loaded from the xpcom .py code)
00085 extern PYXPCOM_EXPORT PyObject *PyXPCOM_Error;
00086 
00087 // Client related functions - generally called by interfaces before
00088 // they return NULL back to Python to indicate the error.
00089 // All these functions return NULL so interfaces can generally
00090 // just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)"
00091 PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res);
00092 
00093 // Used in gateways to handle the current Python exception
00094 // NOTE: this function assumes it is operating within the Python context
00095 PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException();
00096 
00097 // A couple of logging/error functions.  These probably end up
00098 // being written to the console service.
00099 
00100 // Log a warning for the user - something at runtime
00101 // they may care about, but nothing that prevents us actually
00102 // working.
00103 // As it's designed for user error/warning, it exists in non-debug builds.
00104 PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...);
00105 
00106 // Log an error for the user - something that _has_ prevented
00107 // us working.  This is probably accompanied by a traceback.
00108 // As it's designed for user error/warning, it exists in non-debug builds.
00109 PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...);
00110 
00111 #ifdef DEBUG
00112 // Mainly designed for developers of the XPCOM package.
00113 // Only enabled in debug builds.
00114 PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...);
00115 #define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug
00116 #else
00117 #define PYXPCOM_LOG_DEBUG()
00118 #endif // DEBUG
00119 
00120 // Create a Unicode Object from the PRUnichar buffer src of the given size
00121 #define PyUnicode_FromPRUnichar(src, size) \
00122        PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL)
00123 
00124 /*************************************************************************
00125 **************************************************************************
00126 
00127  Support for CALLING (ie, using) interfaces.
00128 
00129 **************************************************************************
00130 *************************************************************************/
00131 
00132 class Py_nsISupports;
00133 
00134 typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &);
00135 
00137 // class PyXPCOM_TypeObject
00138 // Base class for (most of) the type objects.
00139 
00140 class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyTypeObject {
00141 public:
00142        PyXPCOM_TypeObject( 
00143               const char *name, 
00144               PyXPCOM_TypeObject *pBaseType, 
00145               int typeSize, 
00146               struct PyMethodDef* methodList,
00147               PyXPCOM_I_CTOR ctor);
00148        ~PyXPCOM_TypeObject();
00149 
00150        PyMethodChain chain;
00151        PyXPCOM_TypeObject *baseType;
00152        PyXPCOM_I_CTOR ctor;
00153 
00154        static PRBool IsType(PyTypeObject *t);
00155        // Static methods for the Python type.
00156        static void Py_dealloc(PyObject *ob);
00157        static PyObject *Py_repr(PyObject *ob);
00158        static PyObject *Py_str(PyObject *ob);
00159        static PyObject *Py_getattr(PyObject *self, char *name);
00160        static int Py_setattr(PyObject *op, char *name, PyObject *v);
00161        static int Py_cmp(PyObject *ob1, PyObject *ob2);
00162        static long Py_hash(PyObject *self);
00163 };
00164 
00166 // class Py_nsISupports
00167 // This class serves 2 purposes:
00168 // * It is a base class for other interfaces we support "natively"
00169 // * It is instantiated for _all_ other interfaces.
00170 //
00171 // This is different than win32com, where a PyIUnknown only
00172 // ever holds an IUnknown - but here, we could be holding
00173 // _any_ interface.
00174 class PYXPCOM_EXPORT Py_nsISupports : public PyObject
00175 {
00176 public:
00177        static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) {
00178               Py_nsISupports *self = static_cast<Py_nsISupports *>(ob);
00179               if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type ))
00180                      return PR_FALSE;
00181               if (!checkIID.Equals(Py_nsIID_NULL))
00182                      return self->m_iid.Equals(checkIID) != 0;
00183               return PR_TRUE;
00184        }
00185        // Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED
00186        static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL);
00187        nsISupports *m_obj;
00188        nsIID m_iid;
00189 
00190        // Given an nsISupports and an Interface ID, create and return an object
00191        // Does not QI the object - the caller must ensure the nsISupports object
00192        // is really a pointer to an object identified by the IID.
00193        // PRBool bAddRef indicates if a COM reference count should be added to the interface.
00194        //  This depends purely on the context in which it is called.  If the interface is obtained
00195        //  from a function that creates a new ref (eg, ???) then you should use
00196        //  FALSE.  If you receive the pointer as (eg) a param to a gateway function, then
00197        //  you normally need to pass TRUE, as this is truly a new reference.
00198        //  *** ALWAYS take the time to get this right. ***
00199        // PRBool bMakeNicePyObject indicates if we should call back into
00200        //  Python to wrap the object.  This allows Python code to
00201        //  see the correct xpcom.client.Interface object even when calling
00202        //  xpcom function directly.
00203        static PyObject *PyObjectFromInterface(nsISupports *ps, 
00204                                               const nsIID &iid, 
00205                                               PRBool bAddRef,
00206                                               PRBool bMakeNicePyObject = PR_TRUE);
00207 
00208        static PyObject *PyObjectFromInterfaceOrVariant(nsISupports *ps,
00209                                                        const nsIID &iid, 
00210                                                        PRBool bAddRef,
00211                                                        PRBool bMakeNicePyObject = PR_TRUE);
00212 
00213        // Given a Python object that is a registered COM type, return a given
00214        // interface pointer on its underlying object, with a NEW REFERENCE ADDED.
00215        // bTryAutoWrap indicates if a Python instance object should attempt to
00216        //  be automatically wrapped in an XPCOM object.  This is really only
00217        //  provided to stop accidental recursion should the object returned by
00218        //  the wrap process itself be in instance (where it should already be
00219        //  a COM object.
00220        // If |iid|==nsIVariant, then arbitary Python objects will be wrapped
00221        // in an nsIVariant.
00222        static PRBool InterfaceFromPyObject(
00223               PyObject *ob,
00224               const nsIID &iid,
00225               nsISupports **ppret,
00226               PRBool bNoneOK,
00227               PRBool bTryAutoWrap = PR_TRUE);
00228 
00229        // Given a Py_nsISupports, return an interface.
00230        // Object *must* be Py_nsISupports - there is no
00231        // "autowrap", no "None" support, etc
00232        static PRBool InterfaceFromPyISupports(PyObject *ob, 
00233                                               const nsIID &iid, 
00234                                               nsISupports **ppv);
00235 
00236        static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid);
00237        // The Python methods
00238        static PyObject *QueryInterface(PyObject *self, PyObject *args);
00239 
00240        // Internal (sort-of) objects.
00241        static PyXPCOM_TypeObject *type;
00242        static PyMethodDef methods[];
00243        static PyObject *mapIIDToType;
00244        static void SafeRelease(Py_nsISupports *ob);
00245        static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
00246        static void InitType();
00247 
00248        virtual ~Py_nsISupports();
00249        virtual PyObject *getattr(const char *name);
00250        virtual int setattr(const char *name, PyObject *val);
00251 protected:
00252        // ctor is protected - must create objects via
00253        // PyObjectFromInterface()
00254        Py_nsISupports(nsISupports *p, 
00255                           const nsIID &iid, 
00256                          PyTypeObject *type);
00257 
00258        static PyObject *MakeInterfaceResult(PyObject *pyis, const nsIID &iid);
00259 
00260 };
00261 
00262 // Python/XPCOM IID support 
00263 class PYXPCOM_EXPORT Py_nsIID : public PyObject
00264 {
00265 public:
00266        Py_nsIID(const nsIID &riid);
00267        nsIID m_iid;
00268 
00269        PRBool 
00270        IsEqual(const nsIID &riid) {
00271               return m_iid.Equals(riid);
00272        }
00273 
00274        PRBool
00275        IsEqual(PyObject *ob) {
00276               return ob && 
00277                      ob->ob_type== &type && 
00278                      m_iid.Equals(((Py_nsIID *)ob)->m_iid);
00279        }
00280 
00281        PRBool
00282        IsEqual(Py_nsIID &iid) {
00283               return m_iid.Equals(iid.m_iid);
00284        }
00285 
00286        static PyObject *
00287        PyObjectFromIID(const nsIID &iid) {
00288               return new Py_nsIID(iid);
00289        }
00290 
00291        static PRBool IIDFromPyObject(PyObject *ob, nsIID *pRet);
00292        /* Python support */
00293        static PyObject *PyTypeMethod_getattr(PyObject *self, char *name);
00294        static int PyTypeMethod_compare(PyObject *self, PyObject *ob);
00295        static PyObject *PyTypeMethod_repr(PyObject *self);
00296        static long PyTypeMethod_hash(PyObject *self);
00297        static PyObject *PyTypeMethod_str(PyObject *self);
00298        static void PyTypeMethod_dealloc(PyObject *self);
00299        static PyTypeObject type;
00300        static PyMethodDef methods[];
00301 };
00302 
00304 //
00305 // Helper classes for managing arrays of variants.
00306 class PythonTypeDescriptor; // Forward declare.
00307 
00308 class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper {
00309 public:
00310        PyXPCOM_InterfaceVariantHelper();
00311        ~PyXPCOM_InterfaceVariantHelper();
00312        PRBool Init(PyObject *obParams);
00313        PRBool FillArray();
00314 
00315        PyObject *MakePythonResult();
00316 
00317        nsXPTCVariant *m_var_array;
00318        int m_num_array;
00319 protected:
00320        PyObject *MakeSinglePythonResult(int index);
00321        PRBool FillInVariant(const PythonTypeDescriptor &, int, int);
00322        PRBool PrepareOutVariant(const PythonTypeDescriptor &td, int value_index);
00323        PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size);
00324        PRUint32 GetSizeIs( int var_index, PRBool is_arg1);
00325 
00326        PyObject *m_pyparams; // sequence of actual params passed (ie, not including hidden)
00327        PyObject *m_typedescs; // desc of _all_ params, including hidden.
00328        PythonTypeDescriptor *m_python_type_desc_array;
00329        void **m_buffer_array;
00330 
00331 };
00332 
00333 /*************************************************************************
00334 **************************************************************************
00335 
00336  Support for IMPLEMENTING interfaces.
00337 
00338 **************************************************************************
00339 *************************************************************************/
00340 #define NS_IINTERNALPYTHON_IID_STR "AC7459FC-E8AB-4f2e-9C4F-ADDC53393A20"
00341 #define NS_IINTERNALPYTHON_IID \
00342        { 0xac7459fc, 0xe8ab, 0x4f2e, { 0x9c, 0x4f, 0xad, 0xdc, 0x53, 0x39, 0x3a, 0x20 } }
00343 
00344 class PyXPCOM_GatewayWeakReference;
00345 
00346 // This interface is needed primarily to give us a known vtable base.
00347 // If we QI a Python object for this interface, we can safely cast the result
00348 // to a PyG_Base.  Any other interface, we do now know which vtable we will get.
00349 // We also allow the underlying PyObject to be extracted
00350 class nsIInternalPython : public nsISupports {
00351 public: 
00352        NS_DEFINE_STATIC_IID_ACCESSOR(NS_IINTERNALPYTHON_IID)
00353        // Get the underlying Python object with new reference added
00354        virtual PyObject *UnwrapPythonObject(void) = 0;
00355 };
00356 
00357 // This is roughly equivalent to PyGatewayBase in win32com
00358 //
00359 class PYXPCOM_EXPORT PyG_Base : public nsIInternalPython, public nsISupportsWeakReference
00360 {
00361 public:
00362        NS_DECL_ISUPPORTS
00363        NS_DECL_NSISUPPORTSWEAKREFERENCE
00364        PyObject *UnwrapPythonObject(void);
00365 
00366        // A static "constructor" - the real ctor is protected.
00367        static nsresult CreateNew(PyObject *pPyInstance, 
00368                                 const nsIID &iid, 
00369                               void **ppResult);
00370 
00371        // A utility to auto-wrap an arbitary Python instance 
00372        // in a COM gateway.
00373        static PRBool AutoWrapPythonInstance(PyObject *ob, 
00374                                          const nsIID &iid, 
00375                                       nsISupports **ppret);
00376 
00377 
00378        // A helper that creates objects to be passed for nsISupports
00379        // objects.  See extensive comments in PyG_Base.cpp.
00380        PyObject *MakeInterfaceParam(nsISupports *pis, 
00381                                             const nsIID *piid, 
00382                                         int methodIndex = -1,
00383                                         const XPTParamDescriptor *d = NULL, 
00384                                         int paramIndex = -1);
00385 
00386        // A helper that ensures all casting and vtable offsetting etc
00387        // done against this object happens in the one spot!
00388        virtual void *ThisAsIID( const nsIID &iid ) = 0;
00389 
00390        // Helpers for "native" interfaces.
00391        // Not used by the generic stub interface.
00392        nsresult HandleNativeGatewayError(const char *szMethodName);
00393 
00394        // These data members used by the converter helper functions - hence public
00395        nsIID m_iid;
00396        PyObject * m_pPyObject;
00397        // We keep a reference count on this object, and the object
00398        // itself uses normal refcount rules - thus, it will only
00399        // die when we die, and all external references are removed.
00400        // This means that once we have created it (and while we
00401        // are alive) it will never die.
00402        nsCOMPtr<nsIWeakReference> m_pWeakRef;
00403 #ifdef NS_BUILD_REFCNT_LOGGING
00404        char refcntLogRepr[64]; // sigh - I wish I knew how to use the Moz string classes :(  OK for debug only tho.
00405 #endif
00406 protected:
00407        PyG_Base(PyObject *instance, const nsIID &iid);
00408        virtual ~PyG_Base();
00409        PyG_Base *m_pBaseObject; // A chain to implement identity rules.
00410        nsresult InvokeNativeViaPolicy(    const char *szMethodName,
00411                      PyObject **ppResult = NULL,
00412                      const char *szFormat = NULL,
00413                      ...
00414                      );
00415        nsresult InvokeNativeViaPolicyInternal(   const char *szMethodName,
00416                      PyObject **ppResult,
00417                      const char *szFormat,
00418                      va_list va);
00419        nsresult InvokeNativeGetViaPolicy(const char *szPropertyName,
00420                      PyObject **ppResult = NULL
00421                      );
00422        nsresult InvokeNativeSetViaPolicy(const char *szPropertyName,
00423                      ...);
00424 };
00425 
00426 class PYXPCOM_EXPORT PyXPCOM_XPTStub : public PyG_Base, public nsXPTCStubBase
00427 {
00428 friend class PyG_Base;
00429 public:
00430        NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr)      \
00431               {return PyG_Base::QueryInterface(aIID, aInstancePtr);}     \
00432        NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();}    \
00433        NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();}  \
00434 
00435        NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info);
00436        // call this method and return result
00437        NS_IMETHOD CallMethod(PRUint16 methodIndex,
00438                           const nsXPTMethodInfo* info,
00439                           nsXPTCMiniVariant* params);
00440 
00441        virtual void *ThisAsIID(const nsIID &iid);
00442 protected:
00443        PyXPCOM_XPTStub(PyObject *instance, const nsIID &iid) : PyG_Base(instance, iid) {;}
00444 private:
00445 };
00446 
00447 // For the Gateways we manually implement.
00448 #define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE)                    \
00449        NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr)      \
00450               {return PyG_Base::QueryInterface(aIID, aInstancePtr);}     \
00451        NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();}    \
00452        NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();}  \
00453        virtual void *ThisAsIID(const nsIID &iid) {                        \
00454               if (iid.Equals(NS_GET_IID(INTERFACE))) return (INTERFACE *)this; \
00455               return GATEWAY_BASE::ThisAsIID(iid);                       \
00456        }                                                                  \
00457 
00458 
00459 // Weak Reference class.  This is a true COM object, representing
00460 // a weak reference to a Python object.  For each Python XPCOM object,
00461 // there is exactly zero or one corresponding weak reference instance.
00462 // When both are alive, each holds a pointer to the other.  When the main
00463 // object dies due to XPCOM reference counting, it zaps the pointer
00464 // in its corresponding weak reference object.  Thus, the weak-reference
00465 // can live beyond the object (possibly with a NULL pointer back to the 
00466 // "real" object, but as implemented, the weak reference will never be 
00467 // destroyed  before the object
00468 class PYXPCOM_EXPORT PyXPCOM_GatewayWeakReference : public nsIWeakReference {
00469 public:
00470        PyXPCOM_GatewayWeakReference(PyG_Base *base);
00471        virtual ~PyXPCOM_GatewayWeakReference();
00472        NS_DECL_ISUPPORTS
00473        NS_DECL_NSIWEAKREFERENCE
00474        PyG_Base *m_pBase; // NO REF COUNT!!!
00475 #ifdef NS_BUILD_REFCNT_LOGGING
00476        char refcntLogRepr[41];
00477 #endif
00478 };
00479 
00480 
00481 // Helpers classes for our gateways.
00482 class PYXPCOM_EXPORT PyXPCOM_GatewayVariantHelper
00483 {
00484 public:
00485        PyXPCOM_GatewayVariantHelper( PyG_Base *gateway,
00486                                      int methodIndex,
00487                                      const nsXPTMethodInfo *info, 
00488                                      nsXPTCMiniVariant* params );
00489        ~PyXPCOM_GatewayVariantHelper();
00490        PyObject *MakePyArgs();
00491        nsresult ProcessPythonResult(PyObject *ob);
00492        PyG_Base *m_gateway;
00493 private:
00494        nsresult BackFillVariant( PyObject *ob, int index);
00495        PyObject *MakeSingleParam(int index, PythonTypeDescriptor &td);
00496        PRBool GetIIDForINTERFACE_ID(int index, const nsIID **ppret);
00497        nsresult GetArrayType(PRUint8 index, PRUint8 *ret);
00498        PRUint32 GetSizeIs( int var_index, PRBool is_arg1);
00499        PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size);
00500        PRBool CanSetSizeIs( int var_index, PRBool is_arg1 );
00501        nsIInterfaceInfo *GetInterfaceInfo(); // NOTE: no ref count on result.
00502 
00503 
00504        nsXPTCMiniVariant* m_params;
00505        const nsXPTMethodInfo *m_info;
00506        int m_method_index;
00507        PythonTypeDescriptor *m_python_type_desc_array;
00508        int m_num_type_descs;
00509        nsCOMPtr<nsIInterfaceInfo> m_interface_info;
00510 };
00511 
00512 // Misc converters.
00513 PyObject *PyObject_FromXPTType( const nsXPTType *d);
00514 // XPTTypeDescriptor derived from XPTType - latter is automatically processed via PyObject_FromXPTTypeDescriptor XPTTypeDescriptor 
00515 PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d);
00516 
00517 PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d);
00518 PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d);
00519 PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d);
00520 
00521 nsIVariant *PyObject_AsVariant( PyObject *ob);
00522 PyObject *PyObject_FromVariant( nsIVariant *v);
00523 
00524 // DLL reference counting functions.
00525 // Although we maintain the count, we never actually
00526 // finalize Python when it hits zero!
00527 void PyXPCOM_DLLAddRef();
00528 void PyXPCOM_DLLRelease();
00529 
00530 /*************************************************************************
00531 **************************************************************************
00532 
00533  LOCKING AND THREADING
00534 
00535 **************************************************************************
00536 *************************************************************************/
00537 
00538 //
00539 // We have 2 discrete locks in use (when no free-threaded is used, anyway).
00540 // The first type of lock is the global Python lock.  This is the standard lock
00541 // in use by Python, and must be used as documented by Python.  Specifically, no
00542 // 2 threads may _ever_ call _any_ Python code (including INCREF/DECREF) without
00543 // first having this thread lock.
00544 //
00545 // The second type of lock is a "global framework lock", and used whenever 2 threads 
00546 // of C code need access to global data.  This is different than the Python 
00547 // lock - this lock is used when no Python code can ever be called by the 
00548 // threads, but the C code still needs thread-safety.
00549 
00550 // We also supply helper classes which make the usage of these locks a one-liner.
00551 
00552 // The "framework" lock, implemented as a PRLock
00553 PYXPCOM_EXPORT void PyXPCOM_AcquireGlobalLock(void);
00554 PYXPCOM_EXPORT void PyXPCOM_ReleaseGlobalLock(void);
00555 
00556 // Helper class for the DLL global lock.
00557 //
00558 // This class magically waits for PyXPCOM framework global lock, and releases it
00559 // when finished.  
00560 // NEVER new one of these objects - only use on the stack!
00561 class CEnterLeaveXPCOMFramework {
00562 public:
00563        CEnterLeaveXPCOMFramework() {PyXPCOM_AcquireGlobalLock();}
00564        ~CEnterLeaveXPCOMFramework() {PyXPCOM_ReleaseGlobalLock();}
00565 };
00566 
00567 // Python thread-lock stuff.  Free-threading patches use different semantics, but
00568 // these are abstracted away here...
00569 //#include <threadstate.h>
00570 
00571 // Helper class for Enter/Leave Python
00572 //
00573 // This class magically waits for the Python global lock, and releases it
00574 // when finished.  
00575 
00576 // Nested invocations will deadlock, so be careful.
00577 
00578 // NEVER new one of these objects - only use on the stack!
00579 
00580 extern PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls();
00581 extern PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure();
00582 
00583 // For 2.3, use the PyGILState_ calls
00584 #if (PY_VERSION_HEX >= 0x02030000)
00585 #define PYXPCOM_USE_PYGILSTATE
00586 #endif
00587 
00588 #ifdef PYXPCOM_USE_PYGILSTATE
00589 class CEnterLeavePython {
00590 public:
00591        CEnterLeavePython() {
00592               state = PyGILState_Ensure();
00593               // See "pending calls" comment below.  We reach into the Python
00594               // implementation to see if we are the first call on the stack.
00595               if (PyThreadState_Get()->gilstate_counter==1) {
00596                      PyXPCOM_MakePendingCalls();
00597               }
00598        }
00599        ~CEnterLeavePython() {
00600               PyGILState_Release(state);
00601        }
00602        PyGILState_STATE state;
00603 };
00604 #else
00605 
00606 extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState;
00607 extern PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure();
00608 extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free();
00609 extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear();
00610 extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire();
00611 extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release();
00612 
00613 // Pre 2.3 thread-state dances.
00614 class CEnterLeavePython {
00615 public:
00616        CEnterLeavePython() {
00617               created = PyXPCOM_ThreadState_Ensure();
00618               PyXPCOM_InterpreterLock_Acquire();
00619               if (created) {
00620                      // If pending python calls are waiting as we enter Python,
00621                      // it will generally mean an asynch signal handler, etc.
00622                      // We can either call it here, or wait for Python to call it
00623                      // as part of its "even 'n' opcodes" check.  If we wait for
00624                      // Python to check it and the pending call raises an exception,
00625                      // then it is _our_ code that will fail - this is unfair,
00626                      // as the signal was raised before we were entered - indeed,
00627                      // we may be directly responding to the signal!
00628                      // Thus, we flush all the pending calls here, and report any
00629                      // exceptions via our normal exception reporting mechanism.
00630                      // We can then execute our code in the knowledge that only
00631                      // signals raised _while_ we are executing will cause exceptions.
00632                      PyXPCOM_MakePendingCalls();
00633               }
00634        }
00635        ~CEnterLeavePython() {
00636        // The interpreter state must be cleared
00637        // _before_ we release the lock, as some of
00638        // the sys. attributes cleared (eg, the current exception)
00639        // may need the lock to invoke their destructors - 
00640        // specifically, when exc_value is a class instance, and
00641        // the exception holds the last reference!
00642               if ( created )
00643                      PyXPCOM_ThreadState_Clear();
00644               PyXPCOM_InterpreterLock_Release();
00645               if ( created )
00646                      PyXPCOM_ThreadState_Free();
00647        }
00648 private:
00649        PRBool created;
00650 };
00651 #endif // PYXPCOM_USE_PYGILSTATE
00652 
00653 // Our classes.
00654 // Hrm - So we can't have templates, eh??
00655 // preprocessor to the rescue, I guess.
00656 #define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )     \
00657                                                                           \
00658 extern struct PyMethodDef Methods[];                                      \
00659                                                                           \
00660 class ClassName : public Py_nsISupports                                   \
00661 {                                                                         \
00662 public:                                                                   \
00663        static PyXPCOM_TypeObject *type;                                  \
00664        static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
00665               return new ClassName(pInitObj, iid);                      \
00666        }                                                                 \
00667        static void InitType(PyObject *iidNameDict) {                     \
00668               type = new PyXPCOM_TypeObject(                            \
00669                             #InterfaceName,                           \
00670                             Py_nsISupports::type,                     \
00671                             sizeof(ClassName),                        \
00672                             Methods,                                  \
00673                             Constructor);                             \
00674               const nsIID &iid = NS_GET_IID(InterfaceName);             \
00675               RegisterInterface(iid, type);                             \
00676               PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid);        \
00677               PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
00678               Py_DECREF(iid_ob);                                        \
00679        }                                                                 \
00680 protected:                                                                \
00681        ClassName(nsISupports *p, const nsIID &iid) :                     \
00682               Py_nsISupports(p, iid, type) {                            \
00683               /* The IID _must_ be the IID of the interface we are wrapping! */    \
00684               NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
00685        }                                                                 \
00686 };                                                                        \
00687                                                                           \
00688 // End of PyXPCOM_INTERFACE_DECLARE macro
00689 
00690 #define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\
00691                                                                           \
00692 extern struct PyMethodDef Methods[];                                      \
00693                                                                           \
00694 class ClassName : public Py_nsISupports                                   \
00695 {                                                                         \
00696 public:                                                                   \
00697        static PyXPCOM_TypeObject *type;                                  \
00698        static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
00699               return new ClassName(pInitObj, iid);                      \
00700        }                                                                 \
00701        static void InitType(PyObject *iidNameDict) {                     \
00702               type = new PyXPCOM_TypeObject(                            \
00703                             #InterfaceName,                           \
00704                             Py_nsISupports::type,                     \
00705                             sizeof(ClassName),                        \
00706                             Methods,                                  \
00707                             Constructor);                             \
00708               const nsIID &iid = NS_GET_IID(InterfaceName);             \
00709               RegisterInterface(iid, type);                             \
00710               PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid);        \
00711               PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
00712               Py_DECREF(iid_ob);                                        \
00713 }                                                                         \
00714        virtual PyObject *getattr(const char *name);                      \
00715        virtual int setattr(const char *name, PyObject *val);             \
00716 protected:                                                                \
00717        ClassName(nsISupports *p, const nsIID &iid) :                     \
00718               Py_nsISupports(p, iid, type) {                            \
00719               /* The IID _must_ be the IID of the interface we are wrapping! */    \
00720               NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
00721        }                                                                 \
00722 };                                                                        \
00723                                                                           \
00724 // End of PyXPCOM_ATTR_INTERFACE_DECLARE macro
00725 
00726 #define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods )      \
00727 PyXPCOM_TypeObject *ClassName::type = NULL;
00728 
00729 
00730 // And the classes
00731 PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
00732 PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
00733 PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
00734 PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
00735 PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
00736 PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
00737 PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
00738 PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIVariant, nsIVariant, PyMethods_IVariant)
00739 // deprecated, but retained for backward compatibility:
00740 PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete)
00741 
00742 #endif // __PYXPCOM_H__