VirtualBox

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

Last change on this file was 103176, checked in by vboxsync, 4 months ago

libs/xpcom/python: Some cleanup, bugref:3409

  • Property svn:eol-style set to native
File size: 36.6 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 "nsIWeakReference.h"
53#include "nsIInterfaceInfoManager.h"
54#include "nsIClassInfo.h"
55#include "nsIComponentManager.h"
56#include "nsIComponentManagerObsolete.h"
57#include "nsIServiceManager.h"
58#include "nsIInputStream.h"
59#include "nsIVariant.h"
60#include "nsIModule.h"
61
62#include "nsXPIDLString.h"
63#include "nsCRT.h"
64#include "xptcall.h"
65#include "xpt_xdr.h"
66
67#ifdef VBOX_DEBUG_LIFETIMES
68# include <iprt/critsect.h>
69# include <iprt/list.h>
70# include <iprt/once.h>
71#endif
72
73#ifdef HAVE_LONG_LONG
74 // Mozilla also defines this - we undefine it to
75 // prevent a compiler warning.
76# undef HAVE_LONG_LONG
77#endif // HAVE_LONG_LONG
78
79#ifdef _POSIX_C_SOURCE // Ditto here
80# undef _POSIX_C_SOURCE
81#endif // _POSIX_C_SOURCE
82
83#ifdef VBOX_PYXPCOM
84// unfortunatelly, if SOLARIS is defined Python porting layer
85// defines gethostname() in invalid fashion what kills compilation
86# ifdef SOLARIS
87# undef SOLARIS
88# define SOLARIS_WAS_DEFINED
89# endif
90
91// Python.h/pyconfig.h redefines _XOPEN_SOURCE on some hosts
92# ifdef _XOPEN_SOURCE
93# define VBOX_XOPEN_SOURCE_DEFINED _XOPEN_SOURCE
94# undef _XOPEN_SOURCE
95# endif
96
97#endif /* VBOX_PYXPCOM */
98
99#include <Python.h>
100
101#ifdef VBOX_PYXPCOM
102
103# ifdef SOLARIS_WAS_DEFINED
104# define SOLARIS
105# undef SOLARIS_WAS_DEFINED
106# endif
107
108// restore the old value of _XOPEN_SOURCE if not defined by Python.h/pyconfig.h
109# if !defined(_XOPEN_SOURCE) && defined(VBOX_XOPEN_SOURCE_DEFINED)
110# define _XOPEN_SOURCE VBOX_XOPEN_SOURCE_DEFINED
111# endif
112# undef VBOX_XOPEN_SOURCE_DEFINED
113
114# if (PY_VERSION_HEX <= 0x02040000)
115// although in more recent versions of Python this type is ssize_t, earlier
116// it was used as int
117typedef int Py_ssize_t;
118# endif
119
120# if (PY_VERSION_HEX <= 0x02030000)
121// this one not defined before
122inline PyObject *PyBool_FromLong(long ok)
123{
124 PyObject *result;
125 if (ok)
126 result = Py_True;
127 else
128 result = Py_False;
129 Py_INCREF(result);
130 return result;
131}
132# endif
133
134# if PY_MAJOR_VERSION >= 3
135# define PyInt_FromLong(l) PyLong_FromLong(l)
136# define PyInt_Check(o) PyLong_Check(o)
137# define PyInt_AsLong(o) PyLong_AsLong(o)
138# define PyNumber_Int(o) PyNumber_Long(o)
139# if !defined(Py_LIMITED_API) && PY_VERSION_HEX <= 0x03030000 /* 3.3 added PyUnicode_AsUTF8AndSize */
140# ifndef PyUnicode_AsUTF8
141# define PyUnicode_AsUTF8(o) _PyUnicode_AsString(o)
142# endif
143# ifndef PyUnicode_AsUTF8AndSize
144# define PyUnicode_AsUTF8AndSize(o,s) _PyUnicode_AsStringAndSize(o,s)
145# endif
146# endif
147typedef struct PyMethodChain
148{
149 PyMethodDef *methods;
150 struct PyMethodChain *link;
151} PyMethodChain;
152# endif
153
154#endif /* VBOX_PYXPCOM */
155
156#ifdef BUILD_PYXPCOM
157 /* We are building the main dll */
158# define PYXPCOM_EXPORT NS_EXPORT
159#else
160 /* This module uses the dll */
161# define PYXPCOM_EXPORT NS_IMPORT
162#endif // BUILD_PYXPCOM
163
164// An IID we treat as NULL when passing as a reference.
165extern PYXPCOM_EXPORT nsIID Py_nsIID_NULL;
166
167class Py_nsISupports;
168
169
170/** @name VBox limited API hacks:
171 * @{ */
172#ifndef Py_LIMITED_API
173
174# define PyXPCOM_ObTypeName(obj) (Py_TYPE(obj)->tp_name)
175
176#else /* Py_LIMITED_API */
177
178# if PY_VERSION_HEX <= 0x03030000
179# error "Py_LIMITED_API mode only works for Python 3.3 and higher."
180# endif
181
182const char *PyXPCOMGetObTypeName(PyTypeObject *pTypeObj);
183# define PyXPCOM_ObTypeName(obj) PyXPCOMGetObTypeName(Py_TYPE(obj))
184
185# if Py_LIMITED_API < 0x030A0000
186/* Note! While we should not technically be using PyUnicode_AsUTF8AndSize, it was
187 made part of the limited API in 3.10 (see https://bugs.python.org/issue41784 and
188 https://github.com/python/cpython/commit/a05195ac61f1908ac5990cccb5aa82442bdaf15d). */
189extern "C" PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize(PyObject *, Py_ssize_t *);
190# endif
191
192/* PyUnicode_AsUTF8 is just PyUnicode_AsUTF8AndSize without returning a size. */
193# define PyUnicode_AsUTF8(o) PyUnicode_AsUTF8AndSize(o, NULL)
194
195DECLINLINE(int) PyRun_SimpleString(const char *pszCode)
196{
197 /* Get the main mode dictionary: */
198 PyObject *pMainMod = PyImport_AddModule("__main__");
199 if (pMainMod) {
200 PyObject *pMainModDict = PyModule_GetDict(pMainMod);
201
202 /* Compile and run the code. */
203 PyObject *pCodeObject = Py_CompileString(pszCode, "PyXPCOM", Py_file_input);
204 if (pCodeObject) {
205 PyObject *pResult = PyEval_EvalCode(pCodeObject, pMainModDict, pMainModDict);
206 Py_DECREF(pCodeObject);
207 if (pResult) {
208 Py_DECREF(pResult);
209 return 0;
210 }
211 PyErr_Print();
212 }
213 }
214 return -1;
215}
216
217DECLINLINE(PyObject *) PyTuple_GET_ITEM(PyObject *pTuple, Py_ssize_t idx)
218{
219 return PyTuple_GetItem(pTuple, idx);
220}
221
222DECLINLINE(int) PyTuple_SET_ITEM(PyObject *pTuple, Py_ssize_t idx, PyObject *pItem)
223{
224 int rc = PyTuple_SetItem(pTuple, idx, pItem); /* Steals pItem ref, just like PyTuple_SET_ITEM. */
225 Assert(rc == 0);
226 return rc;
227}
228
229DECLINLINE(int) PyList_SET_ITEM(PyObject *pList, Py_ssize_t idx, PyObject *pItem)
230{
231 int rc = PyList_SetItem(pList, idx, pItem); /* Steals pItem ref, just like PyList_SET_ITEM. */
232 Assert(rc == 0);
233 return rc;
234}
235
236DECLINLINE(Py_ssize_t) PyBytes_GET_SIZE(PyObject *pBytes)
237{
238 return PyBytes_Size(pBytes);
239}
240
241DECLINLINE(const char *) PyBytes_AS_STRING(PyObject *pBytes)
242{
243 return PyBytes_AsString(pBytes);
244}
245
246DECLINLINE(Py_ssize_t) PyUnicode_GET_SIZE(PyObject *pUnicode)
247{
248 /* Note! Currently only used for testing for zero or 1 codepoints, so we don't
249 really need to deal with the different way these two treats surrogate pairs. */
250# if Py_LIMITED_API >= 0x03030000
251 return PyUnicode_GetLength(pUnicode);
252# else
253 return PyUnicode_GetSize(pUnicode);
254# endif
255}
256
257# define PyObject_CheckBuffer(pAllegedBuffer) PyObject_CheckReadBuffer(pAllegedBuffer)
258
259# include <iprt/asm.h>
260DECLINLINE(Py_hash_t) _Py_HashPointer(void *p)
261{
262 Py_hash_t uHash = (Py_hash_t)RT_CONCAT(ASMRotateRightU,ARCH_BITS)((uintptr_t)p, 4);
263 return uHash != -1 ? uHash : -2;
264}
265
266#endif /* Py_LIMITED_API */
267/** @} */
268
269
270/*************************************************************************
271**************************************************************************
272
273 Error and exception related function.
274
275**************************************************************************
276*************************************************************************/
277
278#define NS_PYXPCOM_NO_SUCH_METHOD \
279 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_PYXPCOM, 0)
280
281// The exception object (loaded from the xpcom .py code)
282extern PYXPCOM_EXPORT PyObject *PyXPCOM_Error;
283
284// Client related functions - generally called by interfaces before
285// they return NULL back to Python to indicate the error.
286// All these functions return NULL so interfaces can generally
287// just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)"
288PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res);
289
290#ifdef VBOX
291// Build human readable error message out of XPCOM error
292PYXPCOM_EXPORT PyObject *PyXPCOM_BuildErrorMessage(nsresult r);
293#endif
294
295// Used in gateways to handle the current Python exception
296// NOTE: this function assumes it is operating within the Python context
297PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException();
298
299// Write current exception and traceback to a string.
300PYXPCOM_EXPORT bool PyXPCOM_FormatCurrentException(nsCString &streamout);
301// Write specified exception and traceback to a string.
302PYXPCOM_EXPORT bool PyXPCOM_FormatGivenException(nsCString &streamout,
303 PyObject *exc_typ, PyObject *exc_val,
304 PyObject *exc_tb);
305
306// A couple of logging/error functions. These probably end up
307// being written to the console service.
308
309// Log a warning for the user - something at runtime
310// they may care about, but nothing that prevents us actually
311// working.
312// As it's designed for user error/warning, it exists in non-debug builds.
313PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...);
314
315// Log an error for the user - something that _has_ prevented
316// us working. This is probably accompanied by a traceback.
317// As it's designed for user error/warning, it exists in non-debug builds.
318PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...);
319
320// The raw one
321PYXPCOM_EXPORT void PyXPCOM_Log(const char *level, const nsCString &msg);
322
323#ifdef DEBUG
324// Mainly designed for developers of the XPCOM package.
325// Only enabled in debug builds.
326PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...);
327#define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug
328#else
329#define PYXPCOM_LOG_DEBUG()
330#endif // DEBUG
331
332// Some utility converters
333// moz strings to PyObject.
334PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsACString &s,
335 PRBool bAssumeUTF8 = PR_FALSE );
336PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsAString &s );
337PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const PRUnichar *s,
338 PRUint32 len = (PRUint32)-1);
339
340// PyObjects to moz strings. As per the moz string guide, we pass a reference
341// to an abstract string
342PYXPCOM_EXPORT PRBool PyObject_AsNSString( PyObject *ob, nsAString &aStr);
343
344// Variants.
345PYXPCOM_EXPORT nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet);
346PYXPCOM_EXPORT PyObject *PyObject_FromVariant( Py_nsISupports *parent,
347 nsIVariant *v);
348
349// Interfaces - these are the "official" functions
350PYXPCOM_EXPORT PyObject *PyObject_FromNSInterface( nsISupports *aInterface,
351 const nsIID &iid,
352 PRBool bMakeNicePyObject = PR_TRUE);
353
354/*************************************************************************
355**************************************************************************
356
357 Support for CALLING (ie, using) interfaces.
358
359**************************************************************************
360*************************************************************************/
361
362typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &);
363
364//////////////////////////////////////////////////////////////////////////
365// class PyXPCOM_TypeObject
366// Base class for (most of) the type objects.
367
368#ifndef Py_LIMITED_API
369class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyTypeObject {
370#else
371class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyObject {
372#endif
373public:
374 PyXPCOM_TypeObject(
375 const char *name,
376 PyXPCOM_TypeObject *pBaseType,
377 int typeSize,
378 struct PyMethodDef* methodList,
379 PyXPCOM_I_CTOR ctor);
380 ~PyXPCOM_TypeObject();
381
382 PyMethodChain chain;
383 PyXPCOM_TypeObject *baseType;
384 PyXPCOM_I_CTOR ctor;
385
386 static PRBool IsType(PyTypeObject *t);
387 // Static methods for the Python type.
388 static void Py_dealloc(PyObject *ob);
389 static PyObject *Py_repr(PyObject *ob);
390 static PyObject *Py_str(PyObject *ob);
391 static PyObject *Py_getattr(PyObject *self, char *name);
392 static int Py_setattr(PyObject *op, char *name, PyObject *v);
393 static int Py_cmp(PyObject *ob1, PyObject *ob2);
394 static PyObject *Py_richcmp(PyObject *ob1, PyObject *ob2, int op);
395#if PY_VERSION_HEX >= 0x03020000
396 static Py_hash_t Py_hash(PyObject *self);
397#else
398 static long Py_hash(PyObject *self);
399#endif
400#ifdef Py_LIMITED_API
401 PyTypeObject *m_pTypeObj; /**< The python type object we wrap. */
402#endif
403};
404
405//////////////////////////////////////////////////////////////////////////
406// class Py_nsISupports
407// This class serves 2 purposes:
408// * It is a base class for other interfaces we support "natively"
409// * It is instantiated for _all_ other interfaces.
410//
411// This is different than win32com, where a PyIUnknown only
412// ever holds an IUnknown - but here, we could be holding
413// _any_ interface.
414class PYXPCOM_EXPORT Py_nsISupports : public PyObject
415{
416public:
417 // Check if a Python object can safely be cast to an Py_nsISupports,
418 // and optionally check that the object is wrapping the specified
419 // interface.
420 static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) {
421 Py_nsISupports *self = static_cast<Py_nsISupports *>(ob);
422 if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type ))
423 return PR_FALSE;
424 if (!checkIID.Equals(Py_nsIID_NULL))
425 return self->m_iid.Equals(checkIID) != 0;
426 return PR_TRUE;
427 }
428 // Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED
429 static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL);
430 nsCOMPtr<nsISupports> m_obj;
431 nsIID m_iid;
432#ifdef Py_LIMITED_API
433 /** Because PyXPCOM_TypeObject cannot inherit from PyTypeObject in
434 * Py_LIMITED_API mode, we cannot use ob_type to get to the method list.
435 * Instead of we store it here. */
436 PyXPCOM_TypeObject *m_pMyTypeObj;
437#endif
438
439 // Given an nsISupports and an Interface ID, create and return an object
440 // Does not QI the object - the caller must ensure the nsISupports object
441 // is really a pointer to an object identified by the IID (although
442 // debug builds should check this)
443 // PRBool bMakeNicePyObject indicates if we should call back into
444 // Python to wrap the object. This allows Python code to
445 // see the correct xpcom.client.Interface object even when calling
446 // xpcom functions directly from C++.
447 // NOTE: There used to be a bAddRef param to this as an internal
448 // optimization, but since removed. This function *always* takes a
449 // reference to the nsISupports.
450 static PyObject *PyObjectFromInterface(nsISupports *ps,
451 const nsIID &iid,
452 PRBool bMakeNicePyObject = PR_TRUE,
453 PRBool bIsInternalCall = PR_FALSE);
454
455 // Given a Python object that is a registered COM type, return a given
456 // interface pointer on its underlying object, with a NEW REFERENCE ADDED.
457 // bTryAutoWrap indicates if a Python instance object should attempt to
458 // be automatically wrapped in an XPCOM object. This is really only
459 // provided to stop accidental recursion should the object returned by
460 // the wrap process itself be in instance (where it should already be
461 // a COM object.
462 // If |iid|==nsIVariant, then arbitary Python objects will be wrapped
463 // in an nsIVariant.
464 static PRBool InterfaceFromPyObject(
465 PyObject *ob,
466 const nsIID &iid,
467 nsISupports **ppret,
468 PRBool bNoneOK,
469 PRBool bTryAutoWrap = PR_TRUE);
470
471 // Given a Py_nsISupports, return an interface.
472 // Object *must* be Py_nsISupports - there is no
473 // "autowrap", no "None" support, etc
474 static PRBool InterfaceFromPyISupports(PyObject *ob,
475 const nsIID &iid,
476 nsISupports **ppv);
477
478 static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid);
479 // The Python methods
480 static PyObject *QueryInterface(PyObject *self, PyObject *args);
481
482 // Internal (sort-of) objects.
483 static NS_EXPORT_STATIC_MEMBER_(PyXPCOM_TypeObject) *type;
484 static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[];
485 static PyObject *mapIIDToType;
486 static void SafeRelease(Py_nsISupports *ob);
487#ifndef Py_LIMITED_API
488 static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
489#else
490 static void RegisterInterface( const nsIID &iid, PyXPCOM_TypeObject *t);
491#endif
492 static void InitType();
493#ifdef VBOX_DEBUG_LIFETIMES
494 static void dumpList(void);
495 static void dumpListToStdOut(void);
496#endif
497
498 virtual ~Py_nsISupports();
499 virtual PyObject *getattr(const char *name);
500 virtual int setattr(const char *name, PyObject *val);
501 // A virtual function to sub-classes can customize the way
502 // nsISupports objects are returned from their methods.
503 // ps is a new object just obtained from some operation performed on us
504 virtual PyObject *MakeInterfaceResult(nsISupports *ps, const nsIID &iid,
505 PRBool bMakeNicePyObject = PR_TRUE) {
506 return PyObjectFromInterface(ps, iid, bMakeNicePyObject);
507 }
508
509protected:
510 // ctor is protected - must create objects via
511 // PyObjectFromInterface()
512 Py_nsISupports(nsISupports *p,
513 const nsIID &iid,
514#ifndef Py_LIMITED_API
515 PyTypeObject *type);
516#else
517 PyXPCOM_TypeObject *type);
518#endif
519
520 // Make a default wrapper for an ISupports (which is an
521 // xpcom.client.Component instance)
522 static PyObject *MakeDefaultWrapper(PyObject *pyis, const nsIID &iid);
523
524#ifdef VBOX_DEBUG_LIFETIMES
525 static DECLCALLBACK(int32_t) initOnceCallback(void *pvUser1);
526
527 RTLISTNODE m_ListEntry; /**< List entry. */
528
529 static RTONCE g_Once; /**< Init list and critsect once. */
530 static RTCRITSECT g_CritSect; /**< Critsect protecting the list. */
531 static RTLISTANCHOR g_List; /**< List of live interfaces.*/
532#endif
533};
534
535// Python/XPCOM IID support
536class PYXPCOM_EXPORT Py_nsIID : public PyObject
537{
538public:
539 Py_nsIID(const nsIID &riid);
540 nsIID m_iid;
541
542 PRBool
543 IsEqual(const nsIID &riid) {
544 return m_iid.Equals(riid);
545 }
546
547 PRBool
548 IsEqual(PyObject *ob) {
549 return ob &&
550#ifndef Py_LIMITED_API
551 ob->ob_type== &type &&
552#else
553 ob->ob_type == s_pType &&
554#endif
555 m_iid.Equals(((Py_nsIID *)ob)->m_iid);
556 }
557
558 PRBool
559 IsEqual(Py_nsIID &iid) {
560 return m_iid.Equals(iid.m_iid);
561 }
562
563 static PyObject *
564 PyObjectFromIID(const nsIID &iid) {
565 return new Py_nsIID(iid);
566 }
567
568 static PRBool IIDFromPyObject(PyObject *ob, nsIID *pRet);
569 /* Python support */
570 static PyObject *PyTypeMethod_getattr(PyObject *self, char *name);
571#if PY_MAJOR_VERSION <= 2
572 static int PyTypeMethod_compare(PyObject *self, PyObject *ob);
573#endif
574 static PyObject *PyTypeMethod_richcompare(PyObject *self, PyObject *ob, int op);
575 static PyObject *PyTypeMethod_repr(PyObject *self);
576#if PY_VERSION_HEX >= 0x03020000
577 static Py_hash_t PyTypeMethod_hash(PyObject *self);
578#else
579 static long PyTypeMethod_hash(PyObject *self);
580#endif
581 static PyObject *PyTypeMethod_str(PyObject *self);
582 static void PyTypeMethod_dealloc(PyObject *self);
583#ifndef Py_LIMITED_API
584 static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type;
585#else
586 static NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) s_pType;
587 static PyTypeObject *GetTypeObject(void);
588 static int PyTypeMethod_is_gc(PyObject *self);
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 uint32_t _PyXPCOM_GetGatewayCount(void);
753extern PYXPCOM_EXPORT uint32_t _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
880class CEnterLeavePython {
881public:
882 CEnterLeavePython() {
883 state = PyGILState_Ensure();
884 // See "pending calls" comment below. We reach into the Python
885 // implementation to see if we are the first call on the stack.
886# ifndef Py_LIMITED_API
887 if (PyThreadState_Get()->gilstate_counter==1) {
888# else
889 if (state == PyGILState_UNLOCKED) {
890# endif
891 PyXPCOM_MakePendingCalls();
892 }
893 }
894 ~CEnterLeavePython() {
895 PyGILState_Release(state);
896 }
897 PyGILState_STATE state;
898};
899
900// Our classes.
901// Hrm - So we can't have templates, eh??
902// preprocessor to the rescue, I guess.
903#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \
904 \
905extern struct PyMethodDef Methods[]; \
906 \
907class ClassName : public Py_nsISupports \
908{ \
909public: \
910 static PYXPCOM_EXPORT PyXPCOM_TypeObject *type; \
911 static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
912 return new ClassName(pInitObj, iid); \
913 } \
914 static void InitType() { \
915 type = new PyXPCOM_TypeObject( \
916 #InterfaceName, \
917 Py_nsISupports::type, \
918 sizeof(ClassName), \
919 Methods, \
920 Constructor); \
921 const nsIID &iid = NS_GET_IID(InterfaceName); \
922 RegisterInterface(iid, type); \
923 } \
924protected: \
925 ClassName(nsISupports *p, const nsIID &iid) : \
926 Py_nsISupports(p, iid, type) { \
927 /* The IID _must_ be the IID of the interface we are wrapping! */ \
928 NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
929 } \
930}; \
931 \
932// End of PyXPCOM_INTERFACE_DECLARE macro
933
934#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\
935 \
936extern struct PyMethodDef Methods[]; \
937 \
938class ClassName : public Py_nsISupports \
939{ \
940public: \
941 static PyXPCOM_TypeObject *type; \
942 static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
943 return new ClassName(pInitObj, iid); \
944 } \
945 static void InitType() { \
946 type = new PyXPCOM_TypeObject( \
947 #InterfaceName, \
948 Py_nsISupports::type, \
949 sizeof(ClassName), \
950 Methods, \
951 Constructor); \
952 const nsIID &iid = NS_GET_IID(InterfaceName); \
953 RegisterInterface(iid, type); \
954} \
955 virtual PyObject *getattr(const char *name); \
956 virtual int setattr(const char *name, PyObject *val); \
957protected: \
958 ClassName(nsISupports *p, const nsIID &iid) : \
959 Py_nsISupports(p, iid, type) { \
960 /* The IID _must_ be the IID of the interface we are wrapping! */ \
961 NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
962 } \
963}; \
964 \
965// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro
966
967#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \
968PyXPCOM_TypeObject *ClassName::type = NULL;
969
970
971// And the classes
972PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
973PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
974PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
975PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
976PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
977PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
978PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
979PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIVariant, nsIVariant, PyMethods_IVariant)
980// deprecated, but retained for backward compatibility:
981PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete)
982
983
984/* VariantUtils.cpp. */
985DECLHIDDEN(PyObject *) PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v);
986
987/* PyGModule.cpp */
988DECLHIDDEN(PyG_Base *) MakePyG_nsIComponentLoader(PyObject *instance);
989DECLHIDDEN(PyG_Base *) MakePyG_nsIModule(PyObject *instance);
990
991/* PyGInputStream.cpp */
992DECLHIDDEN(PyG_Base *) MakePyG_nsIInputStream(PyObject *instance);
993
994
995#endif // __PYXPCOM_H__
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use