Add interface flattening to Python XPCOM bindings.

Not part of the build, but a=drivers@mozilla.org anyway!


git-svn-id: svn://10.0.0.236/trunk@95969 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
markh%activestate.com
2001-05-27 02:51:18 +00:00
parent fe15e59b3c
commit 031bf2a05c
24 changed files with 649 additions and 199 deletions

View File

@@ -171,7 +171,7 @@ PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **p
obIID = Py_nsIID::PyObjectFromIID(iid);
if (obIID==NULL) goto done;
args = Py_BuildValue("OO", ob, obIID);
args = Py_BuildValue("OOzi", ob, obIID, NULL, 0);
if (args==NULL) goto done;
wrap_ret = PyEval_CallObject(func, args);
if (wrap_ret==NULL) goto done;

View File

@@ -0,0 +1,159 @@
/*
* 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 http://www.mozilla.org/MPL/
*
* 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 ActiveState Tool Corp. are Copyright (C) 2001
* ActiveState Tool Corp. All Rights Reserved.
*
* Contributor(s): Mark Hammond <MarkH@ActiveState.com> (original author)
*
*/
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2001 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2001, ActiveState corp.
#include "PyXPCOM_std.h"
#include "nsIClassInfo.h"
static nsIClassInfo *_GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIClassInfo);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIClassInfo *)Py_nsISupports::GetI(self);
}
static PyObject *PyGetInterfaces(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIClassInfo *pI = _GetI(self);
if (pI==NULL)
return NULL;
nsIID** iidArray = nsnull;
PRUint32 iidCount = 0;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetInterfaces(&iidCount, &iidArray);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ret = PyTuple_New(iidCount);
if (ret==NULL)
return NULL;
for (PRUint32 i=0;i<iidCount;i++)
PyTuple_SET_ITEM( ret, i, Py_nsIID::PyObjectFromIID(*(iidArray[i])) );
return ret;
}
static PyObject *PyGetHelperForLanguage(PyObject *self, PyObject *args)
{
PRUint32 language = nsIProgrammingLanguage::PYTHON;
if (!PyArg_ParseTuple(args, "|i", &language))
return NULL;
nsIClassInfo *pI = _GetI(self);
if (pI==NULL)
return NULL;
nsresult r;
nsISupports *pi;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetHelperForLanguage(language, &pi);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports), PR_FALSE);
}
static PyObject *MakeStringOrNone(char *v)
{
if (v)
return PyString_FromString(v);
Py_INCREF(Py_None);
return Py_None;
}
#define GETATTR_CHECK_RESULT(nr) if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr)
PyObject *
Py_nsIClassInfo::getattr(const char *name)
{
nsIClassInfo *pI = _GetI(this);
if (pI==NULL)
return NULL;
nsresult nr;
PyObject *ret = NULL;
if (strcmp(name, "contractID")==0) {
char *str_ret;
Py_BEGIN_ALLOW_THREADS;
nr = pI->GetContractID(&str_ret);
Py_END_ALLOW_THREADS;
GETATTR_CHECK_RESULT(nr);
ret = MakeStringOrNone(str_ret);
nsAllocator::Free(str_ret);
} else if (strcmp(name, "classDescription")==0) {
char *str_ret;
Py_BEGIN_ALLOW_THREADS;
nr = pI->GetClassDescription(&str_ret);
Py_END_ALLOW_THREADS;
GETATTR_CHECK_RESULT(nr);
ret = MakeStringOrNone(str_ret);
nsAllocator::Free(str_ret);
} else if (strcmp(name, "classID")==0) {
nsIID *iid;
Py_BEGIN_ALLOW_THREADS;
nr = pI->GetClassID(&iid);
Py_END_ALLOW_THREADS;
GETATTR_CHECK_RESULT(nr);
ret = Py_nsIID::PyObjectFromIID(*iid);
nsAllocator::Free(iid);
} else if (strcmp(name, "implementationLanguage")==0) {
PRUint32 i;
Py_BEGIN_ALLOW_THREADS;
nr = pI->GetImplementationLanguage(&i);
Py_END_ALLOW_THREADS;
GETATTR_CHECK_RESULT(nr);
ret = PyInt_FromLong(i);
} else {
ret = Py_nsISupports::getattr(name);
}
return ret;
}
int
Py_nsIClassInfo::setattr(const char *name, PyObject *v)
{
return Py_nsISupports::setattr(name, v);
}
struct PyMethodDef
PyMethods_IClassInfo[] =
{
{ "getInterfaces", PyGetInterfaces, 1},
{ "GetInterfaces", PyGetInterfaces, 1},
{ "getHelperForLanguage", PyGetHelperForLanguage, 1},
{ "GetHelperForLanguage", PyGetHelperForLanguage, 1},
{NULL}
};

View File

@@ -70,7 +70,7 @@ static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args)
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE);
}
static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args)

View File

@@ -117,7 +117,7 @@ static PyObject *PyGetParent(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE, PR_FALSE);
}
static PyObject *PyGetMethodCount(PyObject *self, PyObject *args)

View File

@@ -93,6 +93,25 @@ Py_nsISupports::SafeRelease(Py_nsISupports *ob)
}
}
/* virtual */ PyObject *
Py_nsISupports::getattr(const char *name)
{
if (strcmp(name, "IID")==0)
return Py_nsIID::PyObjectFromIID( m_iid );
PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type;
return Py_FindMethodInChain(&this_type->chain, this, (char *)name);
}
/* virtual */ int
Py_nsISupports::setattr(const char *name, PyObject *v)
{
char buf[128];
sprintf(buf, "%s has read-only attributes", ob_type->tp_name );
PyErr_SetString(PyExc_TypeError, buf);
return -1;
}
/*static*/ Py_nsISupports *
Py_nsISupports::Constructor(nsISupports *pInitObj, const nsIID &iid)
{
@@ -287,7 +306,7 @@ Py_nsISupports::MakeInterfaceResult(PyObject *pyis,
done:
if (PyErr_Occurred()) {
NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
PyXPCOM_LogError("Creating an interface object to be used as a parameter failed\n");
PyXPCOM_LogError("Creating an interface object to be used as a result failed\n");
PyErr_Clear();
}
Py_XDECREF(mod);

View File

@@ -206,7 +206,9 @@ public:
static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
static void InitType();
~Py_nsISupports();
virtual ~Py_nsISupports();
virtual PyObject *getattr(const char *name);
virtual int setattr(const char *name, PyObject *val);
protected:
// ctor is protected - must create objects via
// PyObjectFromInterface()
@@ -398,7 +400,7 @@ protected:
private:
};
// For the Gateways me manually implement.
// For the Gateways we manually implement.
#define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \
{return PyG_Base::QueryInterface(aIID, aInstancePtr);} \
@@ -570,4 +572,91 @@ private:
PRBool created;
};
// Our classes.
// Hrm - So we can't have templates, eh??
// preprocessor to the rescue, I guess.
#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \
\
extern struct PyMethodDef Methods[]; \
\
class ClassName : public Py_nsISupports \
{ \
public: \
static PyXPCOM_TypeObject *type; \
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
return new ClassName(pInitObj, iid); \
} \
static void InitType(PyObject *iidNameDict) { \
type = new PyXPCOM_TypeObject( \
#InterfaceName, \
Py_nsISupports::type, \
sizeof(ClassName), \
Methods, \
Constructor); \
const nsIID &iid = NS_GET_IID(InterfaceName); \
RegisterInterface(iid, type); \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
Py_DECREF(iid_ob); \
} \
protected: \
ClassName(nsISupports *p, const nsIID &iid) : \
Py_nsISupports(p, iid, type) { \
/* The IID _must_ be the IID of the interface we are wrapping! */ \
NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
} \
}; \
\
// End of PyXPCOM_INTERFACE_DECLARE macro
#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\
\
extern struct PyMethodDef Methods[]; \
\
class ClassName : public Py_nsISupports \
{ \
public: \
static PyXPCOM_TypeObject *type; \
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
return new ClassName(pInitObj, iid); \
} \
static void InitType(PyObject *iidNameDict) { \
type = new PyXPCOM_TypeObject( \
#InterfaceName, \
Py_nsISupports::type, \
sizeof(ClassName), \
Methods, \
Constructor); \
const nsIID &iid = NS_GET_IID(InterfaceName); \
RegisterInterface(iid, type); \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
Py_DECREF(iid_ob); \
} \
virtual PyObject *getattr(const char *name); \
virtual int setattr(const char *name, PyObject *val); \
protected: \
ClassName(nsISupports *p, const nsIID &iid) : \
Py_nsISupports(p, iid, type) { \
/* The IID _must_ be the IID of the interface we are wrapping! */ \
NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
} \
}; \
\
// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro
#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \
PyXPCOM_TypeObject *ClassName::type = NULL;
// And the classes
PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
PyXPCOM_INTERFACE_DECLARE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager)
PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
#endif // __PYXPCOM_H__

View File

@@ -34,12 +34,19 @@
// Main Mozilla cross-platform declarations.
#include "xp_core.h"
#include <nsIAllocator.h>
#include <nsIWeakReference.h>
#include <nsXPIDLString.h>
#include <nsCRT.h>
#include <xptcall.h>
#include <xpt_xdr.h>
#include "nsIAllocator.h"
#include "nsIWeakReference.h"
#include "nsIInterfaceInfoManager.h"
#include "nsIClassInfo.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsXPIDLString.h"
#include "nsCRT.h"
#include "xptcall.h"
#include "xpt_xdr.h"
// This header is considered internal - hence
// we can use it to trigger "exports"

View File

@@ -70,20 +70,13 @@ PyXPCOM_TypeObject::IsType(PyTypeObject *t)
/*static*/PyObject *
PyXPCOM_TypeObject::Py_getattr(PyObject *self, char *name)
{
if (strcmp(name, "IID")==0)
return Py_nsIID::PyObjectFromIID( ((Py_nsISupports *)self)->m_iid );
PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)self->ob_type;
return Py_FindMethodInChain(&this_type->chain, self, name);
return ((Py_nsISupports *)self)->getattr(name);
}
/*static*/int
PyXPCOM_TypeObject::Py_setattr(PyObject *op, char *name, PyObject *v)
{
char buf[128];
sprintf(buf, "%s has read-only attributes", op->ob_type->tp_name );
PyErr_SetString(PyExc_TypeError, buf);
return -1;
return ((Py_nsISupports *)op)->setattr(name, v);
}
// @pymethod int|Py_nsISupports|__cmp__|Implements XPCOM rules for object identity.

View File

@@ -129,6 +129,9 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
LogError("Python initialization failed!\n");
return NS_ERROR_FAILURE;
}
#ifndef NS_DEBUG
Py_OptimizeFlag = 1;
#endif
AddStandardPaths();
PyObject *mod = PyImport_ImportModule("xpcom._xpcom");
if (mod==NULL) {

View File

@@ -40,6 +40,7 @@ CPP_OBJS= \
.\$(OBJDIR)\PyGStub.obj \
.\$(OBJDIR)\PyGInputStream.obj \
.\$(OBJDIR)\PyGWeakReference.obj \
.\$(OBJDIR)\PyIClassInfo.obj \
.\$(OBJDIR)\PyIComponentManager.obj \
.\$(OBJDIR)\PyIInputStream.obj \
.\$(OBJDIR)\PyIEnumerator.obj \
@@ -64,6 +65,7 @@ CPPSRCS = \
PyGStub.cpp \
PyGInputStream.cpp \
PyGWeakReference.cpp \
PyIClassInfo.cpp \
PyIComponentManager.cpp \
PyIInputStream.cpp \
PyIEnumerator.cpp \

View File

@@ -28,21 +28,19 @@
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIInterfaceInfoManager.h>
#include <nsIFileSpec.h>
#include <nsSpecialSystemDirectory.h>
#include <nsIThread.h>
#include <nsISupportsPrimitives.h>
#include <nsIModule.h>
#include <nsIInputStream.h>
#include "nsIFileSpec.h"
#include "nsSpecialSystemDirectory.h"
#include "nsIThread.h"
#include "nsISupportsPrimitives.h"
#include "nsIModule.h"
#ifdef XP_WIN
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#include <nsIEventQueue.h>
#include <nsIProxyObjectManager.h>
#include "nsIEventQueue.h"
#include "nsIProxyObjectManager.h"
PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL;
extern void PyXPCOM_InterpreterState_Ensure();
@@ -58,6 +56,15 @@ extern void PyXPCOM_InterpreterState_Ensure();
#endif // XP_WIN
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
PyXPCOM_INTERFACE_DEFINE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
////////////////////////////////////////////////////////////
// This is the main entry point called by the Python component
// loader.
@@ -114,53 +121,6 @@ done:
return nr;
}
// Hrm - So we can't have templates, eh??
// preprocessor to the rescue, I guess.
#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \
\
extern struct PyMethodDef Methods[]; \
\
class ClassName : public Py_nsISupports \
{ \
public: \
static PyXPCOM_TypeObject *type; \
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
return new ClassName(pInitObj, iid); \
} \
static void InitType(PyObject *iidNameDict) { \
type = new PyXPCOM_TypeObject( \
#InterfaceName, \
Py_nsISupports::type, \
sizeof(ClassName), \
Methods, \
Constructor); \
const nsIID &iid = NS_GET_IID(InterfaceName); \
RegisterInterface(iid, type); \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
Py_DECREF(iid_ob); \
} \
protected: \
ClassName(nsISupports *p, const nsIID &iid) : \
Py_nsISupports(p, iid, type) { \
/* The IID _must_ be the IID of the interface we are wrapping! */ \
NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
} \
}; \
\
PyXPCOM_TypeObject *ClassName::type = NULL; \
\
// End of PyXPCOM_INTERFACE_DEFINE macro
// And the classes
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
PyXPCOM_INTERFACE_DEFINE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
// "boot-strap" methods - interfaces we need to get the base
// interface support!
@@ -302,7 +262,8 @@ static PyObject *
PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
{
PyObject *ob, *obIID;
if (!PyArg_ParseTuple(args, "OO", &ob, &obIID))
int bWrapClient = 1;
if (!PyArg_ParseTuple(args, "OO|i", &ob, &obIID, &bWrapClient))
return NULL;
nsIID iid;
@@ -319,7 +280,7 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance.
// Now wrap it in an interface.
return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE, bWrapClient);
}
// @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance
@@ -600,6 +561,7 @@ init_xpcom() {
REGISTER_IID(nsIFactory);
REGISTER_IID(nsIWeakReference);
REGISTER_IID(nsISupportsWeakReference);
REGISTER_IID(nsIClassInfo);
// Register our custom interfaces.
Py_nsISupports::InitType();
@@ -610,6 +572,7 @@ init_xpcom() {
Py_nsIInterfaceInfo::InitType(dict);
Py_nsIServiceManager::InitType(dict);
Py_nsIInputStream::InitType(dict);
Py_nsIClassInfo::InitType(dict);
// We have special support for proxies - may as well add their constants!
REGISTER_INT(PROXY_SYNC);