PyXPCOM.h revision 16a8d09569a2ebd598cef72fa605be6fb4563607
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Python XPCOM language bindings.
*
* The Initial Developer of the Original Code is
* ActiveState Tool Corp.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Hammond <mhammond@skippinet.com.au> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// PyXPCOM.h - the main header file for the Python XPCOM support.
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#ifndef __PYXPCOM_H__
#define __PYXPCOM_H__
#include "nsIAllocator.h"
#include "nsIWeakReference.h"
#include "nsIInterfaceInfoManager.h"
#include "nsIClassInfo.h"
#include "nsIComponentManager.h"
#include "nsIComponentManagerObsolete.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIVariant.h"
#include "nsIModule.h"
#include "nsXPIDLString.h"
#include "nsCRT.h"
#include "xptcall.h"
#include "xpt_xdr.h"
#ifdef HAVE_LONG_LONG
// Mozilla also defines this - we undefine it to
// prevent a compiler warning.
#endif // HAVE_LONG_LONG
#ifdef _POSIX_C_SOURCE // Ditto here
#endif // _POSIX_C_SOURCE
#ifdef VBOX_PYXPCOM
// unfortunatelly, if SOLARIS is defined Python porting layer
// defines gethostname() in invalid fashion what kills compilation
#ifdef SOLARIS
#define SOLARIS_WAS_DEFINED
#endif
#include <Python.h>
#ifdef SOLARIS_WAS_DEFINED
#define SOLARIS
#endif
#ifdef VBOX_PYXPCOM
#if (PY_VERSION_HEX <= 0x02040000)
// although in more recent versions of Python this type is ssize_t, earlier
// it was used as int
typedef int Py_ssize_t;
#endif
#else
#include <Python.h>
#endif
#if (PY_VERSION_HEX <= 0x02030000)
// this one not defined before
{
if (ok)
else
return result;
}
#endif
#endif
#ifdef BUILD_PYXPCOM
/* We are building the main dll */
# define PYXPCOM_EXPORT NS_EXPORT
#else
/* This module uses the dll */
# define PYXPCOM_EXPORT NS_IMPORT
#endif // BUILD_PYXPCOM
// An IID we treat as NULL when passing as a reference.
/*************************************************************************
**************************************************************************
Error and exception related function.
**************************************************************************
*************************************************************************/
#define NS_PYXPCOM_NO_SUCH_METHOD \
// The exception object (loaded from the xpcom .py code)
// Client related functions - generally called by interfaces before
// they return NULL back to Python to indicate the error.
// All these functions return NULL so interfaces can generally
// just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)"
// Used in gateways to handle the current Python exception
// NOTE: this function assumes it is operating within the Python context
// Write current exception and traceback to a string.
// Write specified exception and traceback to a string.
// being written to the console service.
// Log a warning for the user - something at runtime
// they may care about, but nothing that prevents us actually
// working.
// Log an error for the user - something that _has_ prevented
// us working. This is probably accompanied by a traceback.
// The raw one
#ifdef DEBUG
// Mainly designed for developers of the XPCOM package.
// Only enabled in debug builds.
#define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug
#else
#define PYXPCOM_LOG_DEBUG()
#endif // DEBUG
// Some utility converters
// moz strings to PyObject.
// PyObjects to moz strings. As per the moz string guide, we pass a reference
// to an abstract string
// Variants.
nsIVariant *v);
// Interfaces - these are the "official" functions
/*************************************************************************
**************************************************************************
Support for CALLING (ie, using) interfaces.
**************************************************************************
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// class PyXPCOM_TypeObject
// Base class for (most of) the type objects.
const char *name,
int typeSize,
struct PyMethodDef* methodList,
// Static methods for the Python type.
};
//////////////////////////////////////////////////////////////////////////
// class Py_nsISupports
// This class serves 2 purposes:
// * It is a base class for other interfaces we support "natively"
// * It is instantiated for _all_ other interfaces.
//
// This is different than win32com, where a PyIUnknown only
// ever holds an IUnknown - but here, we could be holding
// _any_ interface.
{
// Check if a Python object can safely be cast to an Py_nsISupports,
// and optionally check that the object is wrapping the specified
// interface.
return PR_FALSE;
return PR_TRUE;
}
// Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED
// Given an nsISupports and an Interface ID, create and return an object
// Does not QI the object - the caller must ensure the nsISupports object
// is really a pointer to an object identified by the IID (although
// debug builds should check this)
// PRBool bMakeNicePyObject indicates if we should call back into
// Python to wrap the object. This allows Python code to
// see the correct xpcom.client.Interface object even when calling
// xpcom functions directly from C++.
// NOTE: There used to be a bAddRef param to this as an internal
// optimization, but since removed. This function *always* takes a
// reference to the nsISupports.
// Given a Python object that is a registered COM type, return a given
// interface pointer on its underlying object, with a NEW REFERENCE ADDED.
// bTryAutoWrap indicates if a Python instance object should attempt to
// be automatically wrapped in an XPCOM object. This is really only
// provided to stop accidental recursion should the object returned by
// the wrap process itself be in instance (where it should already be
// a COM object.
// If |iid|==nsIVariant, then arbitary Python objects will be wrapped
// in an nsIVariant.
static PRBool InterfaceFromPyObject(
nsISupports **ppret,
// Given a Py_nsISupports, return an interface.
// Object *must* be Py_nsISupports - there is no
// "autowrap", no "None" support, etc
nsISupports **ppv);
// The Python methods
// Internal (sort-of) objects.
static PyObject *mapIIDToType;
static void InitType();
// A virtual function to sub-classes can customize the way
// nsISupports objects are returned from their methods.
// ps is a new object just obtained from some operation performed on us
}
// ctor is protected - must create objects via
// PyObjectFromInterface()
PyTypeObject *type);
// Make a default wrapper for an ISupports (which is an
// xpcom.client.Component instance)
};
{
}
return ob &&
}
}
static PyObject *
}
/* Python support */
};
///////////////////////////////////////////////////////
//
// Helper classes for managing arrays of variants.
int m_num_array;
int m_methodindex;
void **m_buffer_array;
};
/*************************************************************************
**************************************************************************
Support for IMPLEMENTING interfaces.
**************************************************************************
*************************************************************************/
#define NS_IINTERNALPYTHON_IID_STR "AC7459FC-E8AB-4f2e-9C4F-ADDC53393A20"
#define NS_IINTERNALPYTHON_IID \
{ 0xac7459fc, 0xe8ab, 0x4f2e, { 0x9c, 0x4f, 0xad, 0xdc, 0x53, 0x39, 0x3a, 0x20 } }
// This interface is needed primarily to give us a known vtable base.
// If we QI a Python object for this interface, we can safely cast the result
// to a PyG_Base. Any other interface, we do now know which vtable we will get.
// We also allow the underlying PyObject to be extracted
// Get the underlying Python object with new reference added
};
// This is roughly equivalent to PyGatewayBase in win32com
//
{
PyObject *UnwrapPythonObject(void);
// A static "constructor" - the real ctor is protected.
void **ppResult);
// A utility to auto-wrap an arbitary Python instance
// in a COM gateway.
nsISupports **ppret);
// A helper that creates objects to be passed for nsISupports
// objects. See extensive comments in PyG_Base.cpp.
int methodIndex = -1,
const XPTParamDescriptor *d = NULL,
int paramIndex = -1);
// A helper that ensures all casting and vtable offsetting etc
// done against this object happens in the one spot!
// Helpers for "native" interfaces.
// Not used by the generic stub interface.
// These data members used by the converter helper functions - hence public
// We keep a reference count on this object, and the object
// itself uses normal refcount rules - thus, it will only
// die when we die, and all external references are removed.
// This means that once we have created it (and while we
// are alive) it will never die.
#ifdef NS_BUILD_REFCNT_LOGGING
char refcntLogRepr[64]; // sigh - I wish I knew how to use the Moz string classes :( OK for debug only tho.
#endif
...
);
const char *szFormat,
);
...);
};
{
// call this method and return result
const nsXPTMethodInfo* info,
};
// For the Gateways we manually implement.
} \
// Weak Reference class. This is a true COM object, representing
// a weak reference to a Python object. For each Python XPCOM object,
// there is exactly zero or one corresponding weak reference instance.
// When both are alive, each holds a pointer to the other. When the main
// object dies due to XPCOM reference counting, it zaps the pointer
// in its corresponding weak reference object. Thus, the weak-reference
// can live beyond the object (possibly with a NULL pointer back to the
// "real" object, but as implemented, the weak reference will never be
// destroyed before the object
#ifdef NS_BUILD_REFCNT_LOGGING
char refcntLogRepr[41];
#endif
};
// Helpers classes for our gateways.
{
int methodIndex,
const nsXPTMethodInfo *info,
PyObject *MakePyArgs();
const nsXPTMethodInfo *m_info;
int m_method_index;
int m_num_type_descs;
};
// Misc converters.
// XPTTypeDescriptor derived from XPTType - latter is automatically processed via PyObject_FromXPTTypeDescriptor XPTTypeDescriptor
// DLL reference counting functions.
// Although we maintain the count, we never actually
// finalize Python when it hits zero!
void PyXPCOM_DLLAddRef();
void PyXPCOM_DLLRelease();
/*************************************************************************
**************************************************************************
LOCKING AND THREADING
**************************************************************************
*************************************************************************/
//
// We have 2 discrete locks in use (when no free-threaded is used, anyway).
// The first type of lock is the global Python lock. This is the standard lock
// in use by Python, and must be used as documented by Python. Specifically, no
// first having this thread lock.
//
// The second type of lock is a "global framework lock", and used whenever 2 threads
// of C code need access to global data. This is different than the Python
// lock - this lock is used when no Python code can ever be called by the
// threads, but the C code still needs thread-safety.
// We also supply helper classes which make the usage of these locks a one-liner.
// The "framework" lock, implemented as a PRLock
PYXPCOM_EXPORT void PyXPCOM_AcquireGlobalLock(void);
PYXPCOM_EXPORT void PyXPCOM_ReleaseGlobalLock(void);
// Helper class for the DLL global lock.
//
// This class magically waits for PyXPCOM framework global lock, and releases it
// when finished.
// NEVER new one of these objects - only use on the stack!
};
// Python thread-lock stuff. Free-threading patches use different semantics, but
// these are abstracted away here...
//#include <threadstate.h>
//
// This class magically waits for the Python global lock, and releases it
// when finished.
// Nested invocations will deadlock, so be careful.
// NEVER new one of these objects - only use on the stack!
// For 2.3, use the PyGILState_ calls
#if (PY_VERSION_HEX >= 0x02030000)
#define PYXPCOM_USE_PYGILSTATE
#endif
#ifdef PYXPCOM_USE_PYGILSTATE
state = PyGILState_Ensure();
// See "pending calls" comment below. We reach into the Python
// implementation to see if we are the first call on the stack.
}
}
~CEnterLeavePython() {
}
};
#else
// Pre 2.3 thread-state dances.
if (created) {
// If pending python calls are waiting as we enter Python,
// it will generally mean an asynch signal handler, etc.
// We can either call it here, or wait for Python to call it
// as part of its "even 'n' opcodes" check. If we wait for
// Python to check it and the pending call raises an exception,
// then it is _our_ code that will fail - this is unfair,
// as the signal was raised before we were entered - indeed,
// we may be directly responding to the signal!
// Thus, we flush all the pending calls here, and report any
// exceptions via our normal exception reporting mechanism.
// We can then execute our code in the knowledge that only
// signals raised _while_ we are executing will cause exceptions.
}
}
~CEnterLeavePython() {
// The interpreter state must be cleared
// _before_ we release the lock, as some of
// the sys. attributes cleared (eg, the current exception)
// may need the lock to invoke their destructors -
// specifically, when exc_value is a class instance, and
// the exception holds the last reference!
if ( created )
if ( created )
}
};
#endif // PYXPCOM_USE_PYGILSTATE
// Our classes.
// Hrm - So we can't have templates, eh??
// preprocessor to the rescue, I guess.
\
extern struct PyMethodDef Methods[]; \
\
{ \
public: \
} \
static void InitType() { \
#InterfaceName, \
Py_nsISupports::type, \
sizeof(ClassName), \
Methods, \
Constructor); \
} \
protected: \
/* The IID _must_ be the IID of the interface we are wrapping! */ \
} \
}; \
\
// End of PyXPCOM_INTERFACE_DECLARE macro
\
extern struct PyMethodDef Methods[]; \
\
{ \
public: \
static PyXPCOM_TypeObject *type; \
} \
static void InitType() { \
#InterfaceName, \
Py_nsISupports::type, \
sizeof(ClassName), \
Methods, \
Constructor); \
} \
protected: \
/* The IID _must_ be the IID of the interface we are wrapping! */ \
} \
}; \
\
// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro
// And the classes
PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
// deprecated, but retained for backward compatibility:
PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete)
#endif // __PYXPCOM_H__