VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/python/src/PyXPCOM.h@ 98262

Last change on this file since 98262 was 86623, checked in by vboxsync, 5 years ago

xpcom/python: Update on PyUnicode_AsUTF8AndSize and Py_LIMITED_API. bugref:9840

  • Property svn:eol-style set to native
File size: 38.2 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Python XPCOM language bindings.
15 *
16 * The Initial Developer of the Original Code is
17 * ActiveState Tool Corp.
18 * Portions created by the Initial Developer are Copyright (C) 2000
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 * Mark Hammond <mhammond@skippinet.com.au> (original author)
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38// PyXPCOM.h - the main header file for the Python XPCOM support.
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#ifndef __PYXPCOM_H__
50#define __PYXPCOM_H__
51
52#include "nsIAllocator.h"
53#include "nsIWeakReference.h"
54#include "nsIInterfaceInfoManager.h"
55#include "nsIClassInfo.h"
56#include "nsIComponentManager.h"
57#include "nsIComponentManagerObsolete.h"
58#include "nsIServiceManager.h"
59#include "nsIInputStream.h"
60#include "nsIVariant.h"
61#include "nsIModule.h"
62
63#include "nsXPIDLString.h"
64#include "nsCRT.h"
65#include "xptcall.h"
66#include "xpt_xdr.h"
67
68#ifdef VBOX_DEBUG_LIFETIMES
69# include <iprt/critsect.h>
70# include <iprt/list.h>
71# include <iprt/once.h>
72#endif
73
74#ifdef HAVE_LONG_LONG
75 // Mozilla also defines this - we undefine it to
76 // prevent a compiler warning.
77# undef HAVE_LONG_LONG
78#endif // HAVE_LONG_LONG
79
80#ifdef _POSIX_C_SOURCE // Ditto here
81# undef _POSIX_C_SOURCE
82#endif // _POSIX_C_SOURCE
83
84#ifdef VBOX_PYXPCOM
85// unfortunatelly, if SOLARIS is defined Python porting layer
86// defines gethostname() in invalid fashion what kills compilation
87# ifdef SOLARIS
88# undef SOLARIS
89# define SOLARIS_WAS_DEFINED
90# endif
91
92// Python.h/pyconfig.h redefines _XOPEN_SOURCE on some hosts
93# ifdef _XOPEN_SOURCE
94# define VBOX_XOPEN_SOURCE_DEFINED _XOPEN_SOURCE
95# undef _XOPEN_SOURCE
96# endif
97
98#endif /* VBOX_PYXPCOM */
99
100#include <Python.h>
101
102#ifdef VBOX_PYXPCOM
103
104# ifdef SOLARIS_WAS_DEFINED
105# define SOLARIS
106# undef SOLARIS_WAS_DEFINED
107# endif
108
109// restore the old value of _XOPEN_SOURCE if not defined by Python.h/pyconfig.h
110# if !defined(_XOPEN_SOURCE) && defined(VBOX_XOPEN_SOURCE_DEFINED)
111# define _XOPEN_SOURCE VBOX_XOPEN_SOURCE_DEFINED
112# endif
113# undef VBOX_XOPEN_SOURCE_DEFINED
114
115# if (PY_VERSION_HEX <= 0x02040000)
116// although in more recent versions of Python this type is ssize_t, earlier
117// it was used as int
118typedef int Py_ssize_t;
119# endif
120
121# if (PY_VERSION_HEX <= 0x02030000)
122// this one not defined before
123inline PyObject *PyBool_FromLong(long ok)
124{
125 PyObject *result;
126 if (ok)
127 result = Py_True;
128 else
129 result = Py_False;
130 Py_INCREF(result);
131 return result;
132}
133# endif
134
135# if PY_MAJOR_VERSION >= 3
136# define PyInt_FromLong(l) PyLong_FromLong(l)
137# define PyInt_Check(o) PyLong_Check(o)
138# define PyInt_AsLong(o) PyLong_AsLong(o)
139# define PyNumber_Int(o) PyNumber_Long(o)
140# if !defined(Py_LIMITED_API) && PY_VERSION_HEX <= 0x03030000 /* 3.3 added PyUnicode_AsUTF8AndSize */
141# ifndef PyUnicode_AsUTF8
142# define PyUnicode_AsUTF8(o) _PyUnicode_AsString(o)
143# endif
144# ifndef PyUnicode_AsUTF8AndSize
145# define PyUnicode_AsUTF8AndSize(o,s) _PyUnicode_AsStringAndSize(o,s)
146# endif
147# endif
148typedef struct PyMethodChain
149{
150 PyMethodDef *methods;
151 struct PyMethodChain *link;
152} PyMethodChain;
153# endif
154
155#endif /* VBOX_PYXPCOM */
156
157#ifdef BUILD_PYXPCOM
158 /* We are building the main dll */
159# define PYXPCOM_EXPORT NS_EXPORT
160#else
161 /* This module uses the dll */
162# define PYXPCOM_EXPORT NS_IMPORT
163#endif // BUILD_PYXPCOM
164
165// An IID we treat as NULL when passing as a reference.
166extern PYXPCOM_EXPORT nsIID Py_nsIID_NULL;
167
168class Py_nsISupports;
169
170
171/** @name VBox limited API hacks:
172 * @{ */
173#ifndef Py_LIMITED_API
174
175# define PyXPCOM_ObTypeName(obj) (Py_TYPE(obj)->tp_name)
176
177#else /* Py_LIMITED_API */
178
179# if PY_VERSION_HEX <= 0x03030000
180# error "Py_LIMITED_API mode only works for Python 3.3 and higher."
181# endif
182
183const char *PyXPCOMGetObTypeName(PyTypeObject *pTypeObj);
184# define PyXPCOM_ObTypeName(obj) PyXPCOMGetObTypeName(Py_TYPE(obj))
185
186# if Py_LIMITED_API < 0x030A0000
187/* Note! While we should not technically be using PyUnicode_AsUTF8AndSize, it was
188 made part of the limited API in 3.10 (see https://bugs.python.org/issue41784 and
189 https://github.com/python/cpython/commit/a05195ac61f1908ac5990cccb5aa82442bdaf15d). */
190extern "C" PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize(PyObject *, Py_ssize_t *);
191# endif
192
193/* PyUnicode_AsUTF8 is just PyUnicode_AsUTF8AndSize without returning a size. */
194# define PyUnicode_AsUTF8(o) PyUnicode_AsUTF8AndSize(o, NULL)
195
196DECLINLINE(int) PyRun_SimpleString(const char *pszCode)
197{
198 /* Get the main mode dictionary: */
199 PyObject *pMainMod = PyImport_AddModule("__main__");
200 if (pMainMod) {
201 PyObject *pMainModDict = PyModule_GetDict(pMainMod);
202
203 /* Compile and run the code. */
204 PyObject *pCodeObject = Py_CompileString(pszCode, "PyXPCOM", Py_file_input);
205 if (pCodeObject) {
206 PyObject *pResult = PyEval_EvalCode(pCodeObject, pMainModDict, pMainModDict);
207 Py_DECREF(pCodeObject);
208 if (pResult) {
209 Py_DECREF(pResult);
210 return 0;
211 }
212 PyErr_Print();
213 }
214 }
215 return -1;
216}
217
218DECLINLINE(PyObject *) PyTuple_GET_ITEM(PyObject *pTuple, Py_ssize_t idx)
219{
220 return PyTuple_GetItem(pTuple, idx);
221}
222
223DECLINLINE(int) PyTuple_SET_ITEM(PyObject *pTuple, Py_ssize_t idx, PyObject *pItem)
224{
225 int rc = PyTuple_SetItem(pTuple, idx, pItem); /* Steals pItem ref, just like PyTuple_SET_ITEM. */
226 Assert(rc == 0);
227 return rc;
228}
229
230DECLINLINE(int) PyList_SET_ITEM(PyObject *pList, Py_ssize_t idx, PyObject *pItem)
231{
232 int rc = PyList_SetItem(pList, idx, pItem); /* Steals pItem ref, just like PyList_SET_ITEM. */
233 Assert(rc == 0);
234 return rc;
235}
236
237DECLINLINE(Py_ssize_t) PyBytes_GET_SIZE(PyObject *pBytes)
238{
239 return PyBytes_Size(pBytes);
240}
241
242DECLINLINE(const char *) PyBytes_AS_STRING(PyObject *pBytes)
243{
244 return PyBytes_AsString(pBytes);
245}
246
247DECLINLINE(Py_ssize_t) PyUnicode_GET_SIZE(PyObject *pUnicode)
248{
249 /* Note! Currently only used for testing for zero or 1 codepoints, so we don't
250 really need to deal with the different way these two treats surrogate pairs. */
251# if Py_LIMITED_API >= 0x03030000
252 return PyUnicode_GetLength(pUnicode);
253# else
254 return PyUnicode_GetSize(pUnicode);
255# endif
256}
257
258# define PyObject_CheckBuffer(pAllegedBuffer) PyObject_CheckReadBuffer(pAllegedBuffer)
259
260# include <iprt/asm.h>
261DECLINLINE(Py_hash_t) _Py_HashPointer(void *p)
262{
263 Py_hash_t uHash = (Py_hash_t)RT_CONCAT(ASMRotateRightU,ARCH_BITS)((uintptr_t)p, 4);
264 return uHash != -1 ? uHash : -2;
265}
266
267#endif /* Py_LIMITED_API */
268/** @} */
269
270
271/*************************************************************************
272**************************************************************************
273
274 Error and exception related function.
275
276**************************************************************************
277*************************************************************************/
278
279#define NS_PYXPCOM_NO_SUCH_METHOD \
280 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_PYXPCOM, 0)
281
282// The exception object (loaded from the xpcom .py code)
283extern PYXPCOM_EXPORT PyObject *PyXPCOM_Error;
284
285// Client related functions - generally called by interfaces before
286// they return NULL back to Python to indicate the error.
287// All these functions return NULL so interfaces can generally
288// just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)"
289PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res);
290
291#ifdef VBOX
292// Build human readable error message out of XPCOM error
293PYXPCOM_EXPORT PyObject *PyXPCOM_BuildErrorMessage(nsresult r);
294#endif
295
296// Used in gateways to handle the current Python exception
297// NOTE: this function assumes it is operating within the Python context
298PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException();
299
300// Write current exception and traceback to a string.
301PYXPCOM_EXPORT PRBool PyXPCOM_FormatCurrentException(nsCString &streamout);
302// Write specified exception and traceback to a string.
303PYXPCOM_EXPORT PRBool PyXPCOM_FormatGivenException(nsCString &streamout,
304 PyObject *exc_typ, PyObject *exc_val,
305 PyObject *exc_tb);
306
307// A couple of logging/error functions. These probably end up
308// being written to the console service.
309
310// Log a warning for the user - something at runtime
311// they may care about, but nothing that prevents us actually
312// working.
313// As it's designed for user error/warning, it exists in non-debug builds.
314PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...);
315
316// Log an error for the user - something that _has_ prevented
317// us working. This is probably accompanied by a traceback.
318// As it's designed for user error/warning, it exists in non-debug builds.
319PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...);
320
321// The raw one
322PYXPCOM_EXPORT void PyXPCOM_Log(const char *level, const nsCString &msg);
323
324#ifdef DEBUG
325// Mainly designed for developers of the XPCOM package.
326// Only enabled in debug builds.
327PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...);
328#define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug
329#else
330#define PYXPCOM_LOG_DEBUG()
331#endif // DEBUG
332
333// Some utility converters
334// moz strings to PyObject.
335PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsACString &s,
336 PRBool bAssumeUTF8 = PR_FALSE );
337PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsAString &s );
338PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const PRUnichar *s,
339 PRUint32 len = (PRUint32)-1);
340
341// PyObjects to moz strings. As per the moz string guide, we pass a reference
342// to an abstract string
343PYXPCOM_EXPORT PRBool PyObject_AsNSString( PyObject *ob, nsAString &aStr);
344
345// Variants.
346PYXPCOM_EXPORT nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet);
347PYXPCOM_EXPORT PyObject *PyObject_FromVariant( Py_nsISupports *parent,
348 nsIVariant *v);
349
350// Interfaces - these are the "official" functions
351PYXPCOM_EXPORT PyObject *PyObject_FromNSInterface( nsISupports *aInterface,
352 const nsIID &iid,
353 PRBool bMakeNicePyObject = PR_TRUE);
354
355/*************************************************************************
356**************************************************************************
357
358 Support for CALLING (ie, using) interfaces.
359
360**************************************************************************
361*************************************************************************/
362
363typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &);
364
365//////////////////////////////////////////////////////////////////////////
366// class PyXPCOM_TypeObject
367// Base class for (most of) the type objects.
368
369#ifndef Py_LIMITED_API
370class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyTypeObject {
371#else
372class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyObject {
373#endif
374public:
375 PyXPCOM_TypeObject(
376 const char *name,
377 PyXPCOM_TypeObject *pBaseType,
378 int typeSize,
379 struct PyMethodDef* methodList,
380 PyXPCOM_I_CTOR ctor);
381 ~PyXPCOM_TypeObject();
382
383 PyMethodChain chain;
384 PyXPCOM_TypeObject *baseType;
385 PyXPCOM_I_CTOR ctor;
386
387 static PRBool IsType(PyTypeObject *t);
388 // Static methods for the Python type.
389 static void Py_dealloc(PyObject *ob);
390 static PyObject *Py_repr(PyObject *ob);
391 static PyObject *Py_str(PyObject *ob);
392 static PyObject *Py_getattr(PyObject *self, char *name);
393 static int Py_setattr(PyObject *op, char *name, PyObject *v);
394 static int Py_cmp(PyObject *ob1, PyObject *ob2);
395 static PyObject *Py_richcmp(PyObject *ob1, PyObject *ob2, int op);
396#if PY_VERSION_HEX >= 0x03020000
397 static Py_hash_t Py_hash(PyObject *self);
398#else
399 static long Py_hash(PyObject *self);
400#endif
401#ifdef Py_LIMITED_API
402 PyTypeObject *m_pTypeObj; /**< The python type object we wrap. */
403#endif
404};
405
406//////////////////////////////////////////////////////////////////////////
407// class Py_nsISupports
408// This class serves 2 purposes:
409// * It is a base class for other interfaces we support "natively"
410// * It is instantiated for _all_ other interfaces.
411//
412// This is different than win32com, where a PyIUnknown only
413// ever holds an IUnknown - but here, we could be holding
414// _any_ interface.
415class PYXPCOM_EXPORT Py_nsISupports : public PyObject
416{
417public:
418 // Check if a Python object can safely be cast to an Py_nsISupports,
419 // and optionally check that the object is wrapping the specified
420 // interface.
421 static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) {
422 Py_nsISupports *self = static_cast<Py_nsISupports *>(ob);
423 if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type ))
424 return PR_FALSE;
425 if (!checkIID.Equals(Py_nsIID_NULL))
426 return self->m_iid.Equals(checkIID) != 0;
427 return PR_TRUE;
428 }
429 // Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED
430 static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL);
431 nsCOMPtr<nsISupports> m_obj;
432 nsIID m_iid;
433#ifdef Py_LIMITED_API
434 /** Because PyXPCOM_TypeObject cannot inherit from PyTypeObject in
435 * Py_LIMITED_API mode, we cannot use ob_type to get to the method list.
436 * Instead of we store it here. */
437 PyXPCOM_TypeObject *m_pMyTypeObj;
438#endif
439
440 // Given an nsISupports and an Interface ID, create and return an object
441 // Does not QI the object - the caller must ensure the nsISupports object
442 // is really a pointer to an object identified by the IID (although
443 // debug builds should check this)
444 // PRBool bMakeNicePyObject indicates if we should call back into
445 // Python to wrap the object. This allows Python code to
446 // see the correct xpcom.client.Interface object even when calling
447 // xpcom functions directly from C++.
448 // NOTE: There used to be a bAddRef param to this as an internal
449 // optimization, but since removed. This function *always* takes a
450 // reference to the nsISupports.
451 static PyObject *PyObjectFromInterface(nsISupports *ps,
452 const nsIID &iid,
453 PRBool bMakeNicePyObject = PR_TRUE,
454 PRBool bIsInternalCall = PR_FALSE);
455
456 // Given a Python object that is a registered COM type, return a given
457 // interface pointer on its underlying object, with a NEW REFERENCE ADDED.
458 // bTryAutoWrap indicates if a Python instance object should attempt to
459 // be automatically wrapped in an XPCOM object. This is really only
460 // provided to stop accidental recursion should the object returned by
461 // the wrap process itself be in instance (where it should already be
462 // a COM object.
463 // If |iid|==nsIVariant, then arbitary Python objects will be wrapped
464 // in an nsIVariant.
465 static PRBool InterfaceFromPyObject(
466 PyObject *ob,
467 const nsIID &iid,
468 nsISupports **ppret,
469 PRBool bNoneOK,
470 PRBool bTryAutoWrap = PR_TRUE);
471
472 // Given a Py_nsISupports, return an interface.
473 // Object *must* be Py_nsISupports - there is no
474 // "autowrap", no "None" support, etc
475 static PRBool InterfaceFromPyISupports(PyObject *ob,
476 const nsIID &iid,
477 nsISupports **ppv);
478
479 static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid);
480 // The Python methods
481 static PyObject *QueryInterface(PyObject *self, PyObject *args);
482
483 // Internal (sort-of) objects.
484 static NS_EXPORT_STATIC_MEMBER_(PyXPCOM_TypeObject) *type;
485 static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[];
486 static PyObject *mapIIDToType;
487 static void SafeRelease(Py_nsISupports *ob);
488#ifndef Py_LIMITED_API
489 static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
490#else
491 static void RegisterInterface( const nsIID &iid, PyXPCOM_TypeObject *t);
492#endif
493 static void InitType();
494#ifdef VBOX_DEBUG_LIFETIMES
495 static void dumpList(void);
496 static void dumpListToStdOut(void);
497#endif
498
499 virtual ~Py_nsISupports();
500 virtual PyObject *getattr(const char *name);
501 virtual int setattr(const char *name, PyObject *val);
502 // A virtual function to sub-classes can customize the way
503 // nsISupports objects are returned from their methods.
504 // ps is a new object just obtained from some operation performed on us
505 virtual PyObject *MakeInterfaceResult(nsISupports *ps, const nsIID &iid,
506 PRBool bMakeNicePyObject = PR_TRUE) {
507 return PyObjectFromInterface(ps, iid, bMakeNicePyObject);
508 }
509
510protected:
511 // ctor is protected - must create objects via
512 // PyObjectFromInterface()
513 Py_nsISupports(nsISupports *p,
514 const nsIID &iid,
515#ifndef Py_LIMITED_API
516 PyTypeObject *type);
517#else
518 PyXPCOM_TypeObject *type);
519#endif
520
521 // Make a default wrapper for an ISupports (which is an
522 // xpcom.client.Component instance)
523 static PyObject *MakeDefaultWrapper(PyObject *pyis, const nsIID &iid);
524
525#ifdef VBOX_DEBUG_LIFETIMES
526 static DECLCALLBACK(int32_t) initOnceCallback(void *pvUser1);
527
528 RTLISTNODE m_ListEntry; /**< List entry. */
529
530 static RTONCE g_Once; /**< Init list and critsect once. */
531 static RTCRITSECT g_CritSect; /**< Critsect protecting the list. */
532 static RTLISTANCHOR g_List; /**< List of live interfaces.*/
533#endif
534};
535
536// Python/XPCOM IID support
537class PYXPCOM_EXPORT Py_nsIID : public PyObject
538{
539public:
540 Py_nsIID(const nsIID &riid);
541 nsIID m_iid;
542
543 PRBool
544 IsEqual(const nsIID &riid) {
545 return m_iid.Equals(riid);
546 }
547
548 PRBool
549 IsEqual(PyObject *ob) {
550 return ob &&
551#ifndef Py_LIMITED_API
552 ob->ob_type== &type &&
553#else
554 ob->ob_type == s_pType &&
555#endif
556 m_iid.Equals(((Py_nsIID *)ob)->m_iid);
557 }
558
559 PRBool
560 IsEqual(Py_nsIID &iid) {
561 return m_iid.Equals(iid.m_iid);
562 }
563
564 static PyObject *
565 PyObjectFromIID(const nsIID &iid) {
566 return new Py_nsIID(iid);
567 }
568
569 static PRBool IIDFromPyObject(PyObject *ob, nsIID *pRet);
570 /* Python support */
571 static PyObject *PyTypeMethod_getattr(PyObject *self, char *name);
572#if PY_MAJOR_VERSION <= 2
573 static int PyTypeMethod_compare(PyObject *self, PyObject *ob);
574#endif
575 static PyObject *PyTypeMethod_richcompare(PyObject *self, PyObject *ob, int op);
576 static PyObject *PyTypeMethod_repr(PyObject *self);
577#if PY_VERSION_HEX >= 0x03020000
578 static Py_hash_t PyTypeMethod_hash(PyObject *self);
579#else
580 static long PyTypeMethod_hash(PyObject *self);
581#endif
582 static PyObject *PyTypeMethod_str(PyObject *self);
583 static void PyTypeMethod_dealloc(PyObject *self);
584#ifndef Py_LIMITED_API
585 static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type;
586#else
587 static NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) s_pType;
588 static PyTypeObject *GetTypeObject(void);
589#endif
590 static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[];
591};
592
593///////////////////////////////////////////////////////
594//
595// Helper classes for managing arrays of variants.
596class PythonTypeDescriptor; // Forward declare.
597
598class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper {
599public:
600 PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent, int methodindex);
601 ~PyXPCOM_InterfaceVariantHelper();
602 PRBool Init(PyObject *obParams);
603 PRBool FillArray();
604
605 PyObject *MakePythonResult();
606
607 nsXPTCVariant *m_var_array;
608 int m_num_array;
609 int m_methodindex;
610protected:
611 PyObject *MakeSinglePythonResult(int index);
612 PRBool FillInVariant(const PythonTypeDescriptor &, int, int);
613 PRBool PrepareOutVariant(const PythonTypeDescriptor &td, int value_index);
614 PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size);
615 PRUint32 GetSizeIs( int var_index, PRBool is_arg1);
616
617 PyObject *m_pyparams; // sequence of actual params passed (ie, not including hidden)
618 PyObject *m_typedescs; // desc of _all_ params, including hidden.
619 PythonTypeDescriptor *m_python_type_desc_array;
620 void **m_buffer_array;
621 Py_nsISupports *m_parent;
622
623};
624
625/*************************************************************************
626**************************************************************************
627
628 Support for IMPLEMENTING interfaces.
629
630**************************************************************************
631*************************************************************************/
632#define NS_IINTERNALPYTHON_IID_STR "AC7459FC-E8AB-4f2e-9C4F-ADDC53393A20"
633#define NS_IINTERNALPYTHON_IID \
634 { 0xac7459fc, 0xe8ab, 0x4f2e, { 0x9c, 0x4f, 0xad, 0xdc, 0x53, 0x39, 0x3a, 0x20 } }
635
636class PyXPCOM_GatewayWeakReference;
637
638// This interface is needed primarily to give us a known vtable base.
639// If we QI a Python object for this interface, we can safely cast the result
640// to a PyG_Base. Any other interface, we do now know which vtable we will get.
641// We also allow the underlying PyObject to be extracted
642class nsIInternalPython : public nsISupports {
643public:
644 NS_DEFINE_STATIC_IID_ACCESSOR(NS_IINTERNALPYTHON_IID)
645 // Get the underlying Python object with new reference added
646 virtual PyObject *UnwrapPythonObject(void) = 0;
647};
648
649// This is roughly equivalent to PyGatewayBase in win32com
650//
651class PYXPCOM_EXPORT PyG_Base : public nsIInternalPython, public nsISupportsWeakReference
652{
653public:
654 NS_DECL_ISUPPORTS
655 NS_DECL_NSISUPPORTSWEAKREFERENCE
656 PyObject *UnwrapPythonObject(void);
657
658 // A static "constructor" - the real ctor is protected.
659 static nsresult CreateNew(PyObject *pPyInstance,
660 const nsIID &iid,
661 void **ppResult);
662
663 // A utility to auto-wrap an arbitary Python instance
664 // in a COM gateway.
665 static PRBool AutoWrapPythonInstance(PyObject *ob,
666 const nsIID &iid,
667 nsISupports **ppret);
668
669
670 // A helper that creates objects to be passed for nsISupports
671 // objects. See extensive comments in PyG_Base.cpp.
672 PyObject *MakeInterfaceParam(nsISupports *pis,
673 const nsIID *piid,
674 int methodIndex = -1,
675 const XPTParamDescriptor *d = NULL,
676 int paramIndex = -1);
677
678 // A helper that ensures all casting and vtable offsetting etc
679 // done against this object happens in the one spot!
680 virtual void *ThisAsIID( const nsIID &iid ) = 0;
681
682 // Helpers for "native" interfaces.
683 // Not used by the generic stub interface.
684 nsresult HandleNativeGatewayError(const char *szMethodName);
685
686 // These data members used by the converter helper functions - hence public
687 nsIID m_iid;
688 PyObject * m_pPyObject;
689 // We keep a reference count on this object, and the object
690 // itself uses normal refcount rules - thus, it will only
691 // die when we die, and all external references are removed.
692 // This means that once we have created it (and while we
693 // are alive) it will never die.
694 nsCOMPtr<nsIWeakReference> m_pWeakRef;
695#ifdef NS_BUILD_REFCNT_LOGGING
696 char refcntLogRepr[64]; // sigh - I wish I knew how to use the Moz string classes :( OK for debug only tho.
697#endif
698protected:
699 PyG_Base(PyObject *instance, const nsIID &iid);
700 virtual ~PyG_Base();
701 PyG_Base *m_pBaseObject; // A chain to implement identity rules.
702 nsresult InvokeNativeViaPolicy( const char *szMethodName,
703 PyObject **ppResult = NULL,
704 const char *szFormat = NULL,
705 ...
706 );
707 nsresult InvokeNativeViaPolicyInternal( const char *szMethodName,
708 PyObject **ppResult,
709 const char *szFormat,
710 va_list va);
711 nsresult InvokeNativeGetViaPolicy(const char *szPropertyName,
712 PyObject **ppResult = NULL
713 );
714 nsresult InvokeNativeSetViaPolicy(const char *szPropertyName,
715 ...);
716};
717
718class PYXPCOM_EXPORT PyXPCOM_XPTStub : public PyG_Base, public nsXPTCStubBase
719{
720friend class PyG_Base;
721public:
722 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \
723 {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \
724 NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \
725 NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \
726
727 NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info);
728 // call this method and return result
729 NS_IMETHOD CallMethod(PRUint16 methodIndex,
730 const nsXPTMethodInfo* info,
731 nsXPTCMiniVariant* params);
732
733 virtual void *ThisAsIID(const nsIID &iid);
734protected:
735 PyXPCOM_XPTStub(PyObject *instance, const nsIID &iid) : PyG_Base(instance, iid) {;}
736private:
737};
738
739// For the Gateways we manually implement.
740#define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \
741 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \
742 {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \
743 NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \
744 NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \
745 virtual void *ThisAsIID(const nsIID &iid) { \
746 if (iid.Equals(NS_GET_IID(INTERFACE))) return (INTERFACE *)this; \
747 return GATEWAY_BASE::ThisAsIID(iid); \
748 } \
749
750extern PYXPCOM_EXPORT void AddDefaultGateway(PyObject *instance, nsISupports *gateway);
751
752extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetGatewayCount(void);
753extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetInterfaceCount(void);
754#ifdef VBOX_DEBUG_LIFETIMES
755extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_DumpInterfaces(void);
756#endif
757
758
759// Weak Reference class. This is a true COM object, representing
760// a weak reference to a Python object. For each Python XPCOM object,
761// there is exactly zero or one corresponding weak reference instance.
762// When both are alive, each holds a pointer to the other. When the main
763// object dies due to XPCOM reference counting, it zaps the pointer
764// in its corresponding weak reference object. Thus, the weak-reference
765// can live beyond the object (possibly with a NULL pointer back to the
766// "real" object, but as implemented, the weak reference will never be
767// destroyed before the object
768class PYXPCOM_EXPORT PyXPCOM_GatewayWeakReference : public nsIWeakReference {
769public:
770 PyXPCOM_GatewayWeakReference(PyG_Base *base);
771 virtual ~PyXPCOM_GatewayWeakReference();
772 NS_DECL_ISUPPORTS
773 NS_DECL_NSIWEAKREFERENCE
774 PyG_Base *m_pBase; // NO REF COUNT!!!
775#ifdef NS_BUILD_REFCNT_LOGGING
776 char refcntLogRepr[41];
777#endif
778};
779
780
781// Helpers classes for our gateways.
782class PYXPCOM_EXPORT PyXPCOM_GatewayVariantHelper
783{
784public:
785 PyXPCOM_GatewayVariantHelper( PyG_Base *gateway,
786 int methodIndex,
787 const nsXPTMethodInfo *info,
788 nsXPTCMiniVariant* params );
789 ~PyXPCOM_GatewayVariantHelper();
790 PyObject *MakePyArgs();
791 nsresult ProcessPythonResult(PyObject *ob);
792 PyG_Base *m_gateway;
793private:
794 nsresult BackFillVariant( PyObject *ob, int index);
795 PyObject *MakeSingleParam(int index, PythonTypeDescriptor &td);
796 PRBool GetIIDForINTERFACE_ID(int index, const nsIID **ppret);
797 nsresult GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **ppiid);
798 PRUint32 GetSizeIs( int var_index, PRBool is_arg1);
799 PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size);
800 PRBool CanSetSizeIs( int var_index, PRBool is_arg1 );
801 nsIInterfaceInfo *GetInterfaceInfo(); // NOTE: no ref count on result.
802
803
804 nsXPTCMiniVariant* m_params;
805 const nsXPTMethodInfo *m_info;
806 int m_method_index;
807 PythonTypeDescriptor *m_python_type_desc_array;
808 int m_num_type_descs;
809 nsCOMPtr<nsIInterfaceInfo> m_interface_info;
810};
811
812// Misc converters.
813PyObject *PyObject_FromXPTType( const nsXPTType *d);
814// XPTTypeDescriptor derived from XPTType - latter is automatically processed via PyObject_FromXPTTypeDescriptor XPTTypeDescriptor
815PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d);
816
817PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d);
818PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d);
819PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d);
820
821// DLL reference counting functions.
822// Although we maintain the count, we never actually
823// finalize Python when it hits zero!
824void PyXPCOM_DLLAddRef();
825void PyXPCOM_DLLRelease();
826
827/*************************************************************************
828**************************************************************************
829
830 LOCKING AND THREADING
831
832**************************************************************************
833*************************************************************************/
834
835//
836// We have 2 discrete locks in use (when no free-threaded is used, anyway).
837// The first type of lock is the global Python lock. This is the standard lock
838// in use by Python, and must be used as documented by Python. Specifically, no
839// 2 threads may _ever_ call _any_ Python code (including INCREF/DECREF) without
840// first having this thread lock.
841//
842// The second type of lock is a "global framework lock", and used whenever 2 threads
843// of C code need access to global data. This is different than the Python
844// lock - this lock is used when no Python code can ever be called by the
845// threads, but the C code still needs thread-safety.
846
847// We also supply helper classes which make the usage of these locks a one-liner.
848
849// The "framework" lock, implemented as a PRLock
850PYXPCOM_EXPORT void PyXPCOM_AcquireGlobalLock(void);
851PYXPCOM_EXPORT void PyXPCOM_ReleaseGlobalLock(void);
852
853// Helper class for the DLL global lock.
854//
855// This class magically waits for PyXPCOM framework global lock, and releases it
856// when finished.
857// NEVER new one of these objects - only use on the stack!
858class CEnterLeaveXPCOMFramework {
859public:
860 CEnterLeaveXPCOMFramework() {PyXPCOM_AcquireGlobalLock();}
861 ~CEnterLeaveXPCOMFramework() {PyXPCOM_ReleaseGlobalLock();}
862};
863
864// Python thread-lock stuff. Free-threading patches use different semantics, but
865// these are abstracted away here...
866//#include <threadstate.h>
867
868// Helper class for Enter/Leave Python
869//
870// This class magically waits for the Python global lock, and releases it
871// when finished.
872
873// Nested invocations will deadlock, so be careful.
874
875// NEVER new one of these objects - only use on the stack!
876
877PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls();
878PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure();
879
880// For 2.3, use the PyGILState_ calls
881#if (PY_VERSION_HEX >= 0x02030000)
882#define PYXPCOM_USE_PYGILSTATE
883#endif
884
885#ifdef PYXPCOM_USE_PYGILSTATE
886class CEnterLeavePython {
887public:
888 CEnterLeavePython() {
889 state = PyGILState_Ensure();
890 // See "pending calls" comment below. We reach into the Python
891 // implementation to see if we are the first call on the stack.
892# ifndef Py_LIMITED_API
893 if (PyThreadState_Get()->gilstate_counter==1) {
894# else
895 if (state == PyGILState_UNLOCKED) {
896# endif
897 PyXPCOM_MakePendingCalls();
898 }
899 }
900 ~CEnterLeavePython() {
901 PyGILState_Release(state);
902 }
903 PyGILState_STATE state;
904};
905#else
906
907extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState;
908PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure();
909PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free();
910PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear();
911PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire();
912PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release();
913
914// Pre 2.3 thread-state dances.
915class CEnterLeavePython {
916public:
917 CEnterLeavePython() {
918 created = PyXPCOM_ThreadState_Ensure();
919 PyXPCOM_InterpreterLock_Acquire();
920 if (created) {
921 // If pending python calls are waiting as we enter Python,
922 // it will generally mean an asynch signal handler, etc.
923 // We can either call it here, or wait for Python to call it
924 // as part of its "even 'n' opcodes" check. If we wait for
925 // Python to check it and the pending call raises an exception,
926 // then it is _our_ code that will fail - this is unfair,
927 // as the signal was raised before we were entered - indeed,
928 // we may be directly responding to the signal!
929 // Thus, we flush all the pending calls here, and report any
930 // exceptions via our normal exception reporting mechanism.
931 // We can then execute our code in the knowledge that only
932 // signals raised _while_ we are executing will cause exceptions.
933 PyXPCOM_MakePendingCalls();
934 }
935 }
936 ~CEnterLeavePython() {
937 // The interpreter state must be cleared
938 // _before_ we release the lock, as some of
939 // the sys. attributes cleared (eg, the current exception)
940 // may need the lock to invoke their destructors -
941 // specifically, when exc_value is a class instance, and
942 // the exception holds the last reference!
943 if ( created )
944 PyXPCOM_ThreadState_Clear();
945 PyXPCOM_InterpreterLock_Release();
946 if ( created )
947 PyXPCOM_ThreadState_Free();
948 }
949private:
950 PRBool created;
951};
952#endif // PYXPCOM_USE_PYGILSTATE
953
954// Our classes.
955// Hrm - So we can't have templates, eh??
956// preprocessor to the rescue, I guess.
957#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \
958 \
959extern struct PyMethodDef Methods[]; \
960 \
961class ClassName : public Py_nsISupports \
962{ \
963public: \
964 static PYXPCOM_EXPORT PyXPCOM_TypeObject *type; \
965 static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
966 return new ClassName(pInitObj, iid); \
967 } \
968 static void InitType() { \
969 type = new PyXPCOM_TypeObject( \
970 #InterfaceName, \
971 Py_nsISupports::type, \
972 sizeof(ClassName), \
973 Methods, \
974 Constructor); \
975 const nsIID &iid = NS_GET_IID(InterfaceName); \
976 RegisterInterface(iid, type); \
977 } \
978protected: \
979 ClassName(nsISupports *p, const nsIID &iid) : \
980 Py_nsISupports(p, iid, type) { \
981 /* The IID _must_ be the IID of the interface we are wrapping! */ \
982 NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
983 } \
984}; \
985 \
986// End of PyXPCOM_INTERFACE_DECLARE macro
987
988#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\
989 \
990extern struct PyMethodDef Methods[]; \
991 \
992class ClassName : public Py_nsISupports \
993{ \
994public: \
995 static PyXPCOM_TypeObject *type; \
996 static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
997 return new ClassName(pInitObj, iid); \
998 } \
999 static void InitType() { \
1000 type = new PyXPCOM_TypeObject( \
1001 #InterfaceName, \
1002 Py_nsISupports::type, \
1003 sizeof(ClassName), \
1004 Methods, \
1005 Constructor); \
1006 const nsIID &iid = NS_GET_IID(InterfaceName); \
1007 RegisterInterface(iid, type); \
1008} \
1009 virtual PyObject *getattr(const char *name); \
1010 virtual int setattr(const char *name, PyObject *val); \
1011protected: \
1012 ClassName(nsISupports *p, const nsIID &iid) : \
1013 Py_nsISupports(p, iid, type) { \
1014 /* The IID _must_ be the IID of the interface we are wrapping! */ \
1015 NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
1016 } \
1017}; \
1018 \
1019// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro
1020
1021#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \
1022PyXPCOM_TypeObject *ClassName::type = NULL;
1023
1024
1025// And the classes
1026PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
1027PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
1028PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
1029PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
1030PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
1031PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
1032PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
1033PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIVariant, nsIVariant, PyMethods_IVariant)
1034// deprecated, but retained for backward compatibility:
1035PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete)
1036#endif // __PYXPCOM_H__
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette