diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/libs/xpcom18a4/python/src/module/_xpcom.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libs/xpcom18a4/python/src/module/_xpcom.cpp')
-rw-r--r-- | src/libs/xpcom18a4/python/src/module/_xpcom.cpp | 950 |
1 files changed, 950 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/python/src/module/_xpcom.cpp b/src/libs/xpcom18a4/python/src/module/_xpcom.cpp new file mode 100644 index 00000000..d40d2b52 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/module/_xpcom.cpp @@ -0,0 +1,950 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * 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 the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond <mhammond@skippinet.com.au> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsIFile.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIConsoleService.h" +#include "nspr.h" // PR_fprintf +#ifdef VBOX +# include "nsEventQueueUtils.h" +#endif + +#ifdef XP_WIN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "windows.h" +#endif + +#include "nsIEventQueue.h" +#include "nsIProxyObjectManager.h" + +#define LOADER_LINKS_WITH_PYTHON + +#ifndef PYXPCOM_USE_PYGILSTATE +extern PYXPCOM_EXPORT void PyXPCOM_InterpreterState_Ensure(); +#endif + +#ifdef VBOX_PYXPCOM +# include <iprt/cdefs.h> +# include <VBox/com/com.h> +# ifndef MODULE_NAME_SUFFIX +# define MANGLE_MODULE_NAME(a_szName) a_szName +# define MANGLE_MODULE_INIT(a_Name) a_Name +# else +# define MANGLE_MODULE_NAME(a_szName) a_szName RT_XSTR(MODULE_NAME_SUFFIX) +# define MANGLE_MODULE_INIT(a_Name) RT_CONCAT(a_Name, MODULE_NAME_SUFFIX) +# endif +# if defined(VBOX_PYXPCOM_VERSIONED) && !defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# if PY_VERSION_HEX >= 0x030a0000 && PY_VERSION_HEX < 0x030b0000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_10") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_10) + +# elif PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_9") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_9) + +# elif PY_VERSION_HEX >= 0x03080000 && PY_VERSION_HEX < 0x03090000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_8") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_8) + +# elif PY_VERSION_HEX >= 0x03070000 && PY_VERSION_HEX < 0x03080000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_7") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_7) + +# elif PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x03070000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_6") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_6) + +# elif PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03060000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_5") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_5) + +# elif PY_VERSION_HEX >= 0x03040000 && PY_VERSION_HEX < 0x03050000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_4") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_4) + +# elif PY_VERSION_HEX >= 0x03030000 && PY_VERSION_HEX < 0x03040000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_3") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_3) + +# elif PY_VERSION_HEX >= 0x03020000 && PY_VERSION_HEX < 0x03030000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_2") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_2) + +# elif PY_VERSION_HEX >= 0x03010000 && PY_VERSION_HEX < 0x03020000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_1") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_1) + +# elif PY_VERSION_HEX >= 0x02080000 && PY_VERSION_HEX < 0x02090000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_8") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_8) + +# elif PY_VERSION_HEX >= 0x02070000 && PY_VERSION_HEX < 0x02080000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_7") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_7) + +# elif PY_VERSION_HEX >= 0x02060000 && PY_VERSION_HEX < 0x02070000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_6") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_6) +# else +# error "Fix module versioning. This Python version is not recognized." +# endif +# else +# if PY_MAJOR_VERSION <= 2 && defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2) +# elif PY_MAJOR_VERSION <= 2 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython) +# elif defined(Py_LIMITED_API) || defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3) +# else +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython) +# endif +# endif +#else +#define MODULE_NAME "_xpcom" +#endif + +// "boot-strap" methods - interfaces we need to get the base +// interface support! + +#ifndef VBOX +/* deprecated, included for backward compatibility */ +static PyObject * +PyXPCOMMethod_NS_GetGlobalComponentManager(PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "Use GetComponentManager instead") < 0) + return NULL; + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr<nsIComponentManager> cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentManager(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + nsCOMPtr<nsIComponentManagerObsolete> ocm(do_QueryInterface(cm, &rv)); + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(ocm, NS_GET_IID(nsIComponentManagerObsolete), PR_FALSE); +} +#endif + +static PyObject * +PyXPCOMMethod_GetComponentManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr<nsIComponentManager> cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentManager(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_FALSE); +} + +// No xpcom callable way to get at the registrar, even though the interface +// is scriptable. +static PyObject * +PyXPCOMMethod_GetComponentRegistrar(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr<nsIComponentRegistrar> cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentRegistrar(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsISupports), PR_FALSE); +} + +static PyObject * +PyXPCOMMethod_GetServiceManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr<nsIServiceManager> sm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetServiceManager(getter_AddRefs(sm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + // Return a type based on the IID. + return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager)); +} + +#ifndef VBOX +/* deprecated, included for backward compatibility */ +static PyObject * +PyXPCOMMethod_GetGlobalServiceManager(PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "Use GetServiceManager instead") < 0) + return NULL; + + return PyXPCOMMethod_GetComponentManager(self, args); +} +#endif + +static PyObject * +PyXPCOMMethod_XPTI_GetInterfaceInfoManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsIInterfaceInfoManager* im; + Py_BEGIN_ALLOW_THREADS; + im = XPTI_GetInterfaceInfoManager(); + Py_END_ALLOW_THREADS; + if ( im == nsnull ) + return PyXPCOM_BuildPyException(NS_ERROR_FAILURE); + + /* Return a type based on the IID (with no extra ref) */ + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + PyObject *ret = Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_FALSE); + NS_IF_RELEASE(im); + return ret; +} + +static PyObject * +PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args) +{ + PyObject *obIS, *obParams; + nsCOMPtr<nsISupports> pis; + int index; + + // We no longer rely on PyErr_Occurred() for our error state, + // but keeping this assertion can't hurt - it should still always be true! + NS_WARN_IF_FALSE(!PyErr_Occurred(), "Should be no pending Python error!"); + + if (!PyArg_ParseTuple(args, "OiO", &obIS, &index, &obParams)) + return NULL; + + if (!Py_nsISupports::Check(obIS)) { + return PyErr_Format(PyExc_TypeError, + "First param must be a native nsISupports wrapper (got %s)", + PyXPCOM_ObTypeName(obIS)); + } + // Ack! We must ask for the "native" interface supported by + // the object, not specifically nsISupports, else we may not + // back the same pointer (eg, Python, following identity rules, + // will return the "original" gateway when QI'd for nsISupports) + if (!Py_nsISupports::InterfaceFromPyObject( + obIS, + Py_nsIID_NULL, + getter_AddRefs(pis), + PR_FALSE)) + return NULL; + + PyXPCOM_InterfaceVariantHelper arg_helper((Py_nsISupports *)obIS, index); + if (!arg_helper.Init(obParams)) + return NULL; + + if (!arg_helper.FillArray()) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = XPTC_InvokeByIndex(pis, index, arg_helper.m_num_array, arg_helper.m_var_array); +/** @todo bird: Maybe we could processing pending XPCOM events here to make + * life a bit simpler inside python? */ + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return arg_helper.MakePythonResult(); +} + +static PyObject * +PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) +{ + PyObject *ob, *obIID; + int bWrapClient = 1; + if (!PyArg_ParseTuple(args, "OO|i", &ob, &obIID, &bWrapClient)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr<nsISupports> ret; + nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, getter_AddRefs(ret)); + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + // _ALL_ wrapped objects are associated with a weak-ref + // to their "main" instance. + AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance. + + // Now wrap it in an interface. + return Py_nsISupports::PyObjectFromInterface(ret, iid, bWrapClient); +} + +static PyObject * +PyXPCOMMethod_UnwrapObject(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O", &ob)) + return NULL; + + nsISupports *uob = NULL; + nsIInternalPython *iob = NULL; + PyObject *ret = NULL; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + &uob, + PR_FALSE)) + goto done; + if (NS_FAILED(uob->QueryInterface(NS_GET_IID(nsIInternalPython), reinterpret_cast<void **>(&iob)))) { + PyErr_SetString(PyExc_ValueError, "This XPCOM object is not implemented by Python"); + goto done; + } + ret = iob->UnwrapPythonObject(); +done: + Py_BEGIN_ALLOW_THREADS; + NS_IF_RELEASE(uob); + NS_IF_RELEASE(iob); + Py_END_ALLOW_THREADS; + return ret; +} + +// @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance +static PyObject * +PyXPCOMMethod_GetInterfaceCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":_GetInterfaceCount")) + return NULL; + return PyInt_FromLong(_PyXPCOM_GetInterfaceCount()); + // @comm If is occasionally a good idea to call this function before your Python program + // terminates. If this function returns non-zero, then you still have PythonCOM objects + // alive in your program (possibly in global variables). +} + +#ifdef VBOX_DEBUG_LIFETIMES +// @pymethod int|pythoncom|_DumpInterfaces|Dumps the interfaces still in existance to standard output +static PyObject * +PyXPCOMMethod_DumpInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":_DumpInterfaces")) + return NULL; + return PyInt_FromLong(_PyXPCOM_DumpInterfaces()); +} +#endif + +// @pymethod int|pythoncom|_GetGatewayCount|Retrieves the number of gateway objects currently in existance +static PyObject * +PyXPCOMMethod_GetGatewayCount(PyObject *self, PyObject *args) +{ + // @comm This is the number of Python object that implement COM servers which + // are still alive (ie, serving a client). The only way to reduce this count + // is to have the process which uses these PythonCOM servers release its references. + if (!PyArg_ParseTuple(args, ":_GetGatewayCount")) + return NULL; + return PyInt_FromLong(_PyXPCOM_GetGatewayCount()); +} + +static PyObject * +PyXPCOMMethod_NS_ShutdownXPCOM(PyObject *self, PyObject *args) +{ + // @comm This is the number of Python object that implement COM servers which + // are still alive (ie, serving a client). The only way to reduce this count + // is to have the process which uses these PythonCOM servers release its references. + if (!PyArg_ParseTuple(args, ":NS_ShutdownXPCOM")) + return NULL; + nsresult nr; + Py_BEGIN_ALLOW_THREADS; + nr = NS_ShutdownXPCOM(nsnull); + Py_END_ALLOW_THREADS; + +#ifdef VBOX_DEBUG_LIFETIME + Py_nsISupports::dumpList(); +#endif + + // Dont raise an exception - as we are probably shutting down + // and dont really case - just return the status + return PyInt_FromLong(nr); +} + +static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); + +// A hack to work around their magic constants! +static PyObject * +PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args) +{ + PyObject *obQueue, *obIID, *obOb; + int flags; + if (!PyArg_ParseTuple(args, "OOOi", &obQueue, &obIID, &obOb, &flags)) + return NULL; + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsCOMPtr<nsISupports> pob; + if (!Py_nsISupports::InterfaceFromPyObject(obOb, iid, getter_AddRefs(pob), PR_FALSE)) + return NULL; + nsIEventQueue *pQueue = NULL; + nsIEventQueue *pQueueRelease = NULL; + + if (PyInt_Check(obQueue)) { + pQueue = (nsIEventQueue *)PyInt_AsLong(obQueue); + } else { + if (!Py_nsISupports::InterfaceFromPyObject(obQueue, NS_GET_IID(nsIEventQueue), (nsISupports **)&pQueue, PR_TRUE)) + return NULL; + pQueueRelease = pQueue; + } + + nsresult rv_proxy; + nsCOMPtr<nsISupports> presult; + Py_BEGIN_ALLOW_THREADS; + nsCOMPtr<nsIProxyObjectManager> proxyMgr = + do_GetService(kProxyObjectManagerCID, &rv_proxy); + + if ( NS_SUCCEEDED(rv_proxy) ) { + rv_proxy = proxyMgr->GetProxyForObject(pQueue, + iid, + pob, + flags, + getter_AddRefs(presult)); + } + if (pQueueRelease) + pQueueRelease->Release(); + Py_END_ALLOW_THREADS; + + PyObject *result; + if (NS_SUCCEEDED(rv_proxy) ) { + result = Py_nsISupports::PyObjectFromInterface(presult, iid); + } else { + result = PyXPCOM_BuildPyException(rv_proxy); + } + return result; +} + +static PyObject * +PyXPCOMMethod_MakeVariant(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O:MakeVariant", &ob)) + return NULL; + nsCOMPtr<nsIVariant> pVar; + nsresult nr = PyObject_AsVariant(ob, getter_AddRefs(pVar)); + if (NS_FAILED(nr)) + return PyXPCOM_BuildPyException(nr); + if (pVar == nsnull) { + NS_ERROR("PyObject_AsVariant worked but returned a NULL ptr!"); + return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + } + return Py_nsISupports::PyObjectFromInterface(pVar, NS_GET_IID(nsIVariant)); +} + +static PyObject * +PyXPCOMMethod_GetVariantValue(PyObject *self, PyObject *args) +{ + PyObject *ob, *obParent = NULL; + if (!PyArg_ParseTuple(args, "O|O:GetVariantValue", &ob, &obParent)) + return NULL; + + nsCOMPtr<nsIVariant> var; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + getter_AddRefs(var), + PR_FALSE)) + return PyErr_Format(PyExc_ValueError, + "Object is not an nsIVariant (got %s)", + PyXPCOM_ObTypeName(ob)); + + Py_nsISupports *parent = nsnull; + if (obParent && obParent != Py_None) { + if (!Py_nsISupports::Check(obParent)) { + PyErr_SetString(PyExc_ValueError, + "Object not an nsISupports wrapper"); + return NULL; + } + parent = (Py_nsISupports *)obParent; + } + return PyObject_FromVariant(parent, var); +} + +PyObject *PyGetSpecialDirectory(PyObject *self, PyObject *args) +{ + char *dirname; + if (!PyArg_ParseTuple(args, "s:GetSpecialDirectory", &dirname)) + return NULL; + nsCOMPtr<nsIFile> file; + nsresult r = NS_GetSpecialDirectory(dirname, getter_AddRefs(file)); + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + // returned object swallows our reference. + return Py_nsISupports::PyObjectFromInterface(file, NS_GET_IID(nsIFile)); +} + +PyObject *AllocateBuffer(PyObject *self, PyObject *args) +{ + int bufSize; + if (!PyArg_ParseTuple(args, "i", &bufSize)) + return NULL; +#if PY_MAJOR_VERSION <= 2 + return PyBuffer_New(bufSize); +#else + return PyBytes_FromStringAndSize(NULL, bufSize); +#endif +} + +// Writes a message to the console service. This could be done via pure +// Python code, but is useful when the logging code is actually the +// xpcom .py framework itself (ie, we don't want our logging framework to +// call back into the very code generating the log messages! +PyObject *LogConsoleMessage(PyObject *self, PyObject *args) +{ + char *msg; + if (!PyArg_ParseTuple(args, "s", &msg)) + return NULL; + + nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + else { + // This either means no such service, or in shutdown - hardly worth + // the warning, and not worth reporting an error to Python about - its + // log handler would just need to catch and ignore it. + // And as this is only called by this logging setup, any messages should + // still go to stderr or a logfile. + NS_WARNING("pyxpcom can't log console message."); + } + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef VBOX + +# include <VBox/com/NativeEventQueue.h> +# include <iprt/err.h> + +static PyObject * +PyXPCOMMethod_WaitForEvents(PyObject *self, PyObject *args) +{ + long lTimeout; + if (!PyArg_ParseTuple(args, "l", &lTimeout)) + return NULL; + + int rc; + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + { + PyErr_SetString(PyExc_TypeError, "the main event queue is NULL"); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + + RTMSINTERVAL cMsTimeout = (RTMSINTERVAL)lTimeout; + if (lTimeout < 0 || (long)cMsTimeout != lTimeout) + cMsTimeout = RT_INDEFINITE_WAIT; + rc = aEventQ->processEventQueue(cMsTimeout); + + Py_END_ALLOW_THREADS + if (RT_SUCCESS(rc)) + return PyInt_FromLong(0); + + if ( rc == VERR_TIMEOUT + || rc == VERR_INTERRUPTED) + return PyInt_FromLong(1); + + if (rc == VERR_INVALID_CONTEXT) + { + PyErr_SetString(PyExc_Exception, "wrong thread, use the main thread"); + return NULL; + } + + return PyInt_FromLong(2); +} + +static PyObject* +PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args) +{ + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + return NULL; + + int rc = aEventQ->interruptEventQueueProcessing(); + return PyBool_FromLong(RT_SUCCESS(rc)); +} + +static nsresult deinitVBoxPython(); + +static PyObject* +PyXPCOMMethod_DeinitCOM(PyObject *self, PyObject *args) +{ + nsresult nr; + Py_BEGIN_ALLOW_THREADS; + nr = deinitVBoxPython(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(nr); +} + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +static PyObject* +PyXPCOMMethod_AttachThread(PyObject *self, PyObject *args) +{ + nsresult rv; + PRInt32 result = 0; + nsCOMPtr<nsIEventQueueService> eqs; + + // Create the Event Queue for this thread... + Py_BEGIN_ALLOW_THREADS; + eqs = + do_GetService(kEventQueueServiceCID, &rv); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 1; + goto done; + } + + Py_BEGIN_ALLOW_THREADS; + rv = eqs->CreateThreadEventQueue(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 2; + goto done; + } + + done: + /** @todo: better throw an exception on error */ + return PyInt_FromLong(result); +} + +static PyObject* +PyXPCOMMethod_DetachThread(PyObject *self, PyObject *args) +{ + nsresult rv; + PRInt32 result = 0; + nsCOMPtr<nsIEventQueueService> eqs; + + // Destroy the Event Queue for this thread... + Py_BEGIN_ALLOW_THREADS; + eqs = + do_GetService(kEventQueueServiceCID, &rv); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 1; + goto done; + } + + Py_BEGIN_ALLOW_THREADS; + rv = eqs->DestroyThreadEventQueue(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 2; + goto done; + } + + done: + /** @todo: better throw an exception on error */ + return PyInt_FromLong(result); +} + +#endif /* VBOX */ + +extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args); + +static struct PyMethodDef xpcom_methods[]= +{ + {"GetComponentManager", PyXPCOMMethod_GetComponentManager, 1}, + {"GetComponentRegistrar", PyXPCOMMethod_GetComponentRegistrar, 1}, +#ifndef VBOX + {"NS_GetGlobalComponentManager", PyXPCOMMethod_NS_GetGlobalComponentManager, 1}, // deprecated +#endif + {"XPTI_GetInterfaceInfoManager", PyXPCOMMethod_XPTI_GetInterfaceInfoManager, 1}, + {"XPTC_InvokeByIndex", PyXPCOMMethod_XPTC_InvokeByIndex, 1}, + {"GetServiceManager", PyXPCOMMethod_GetServiceManager, 1}, +#ifndef VBOX + {"GetGlobalServiceManager", PyXPCOMMethod_GetGlobalServiceManager, 1}, // deprecated + {"IID", PyXPCOMMethod_IID, 1}, // IID is wrong - deprecated - not just IID, but CID, etc. +#endif + {"ID", PyXPCOMMethod_IID, 1}, // This is the official name. + {"NS_ShutdownXPCOM", PyXPCOMMethod_NS_ShutdownXPCOM, 1}, + {"WrapObject", PyXPCOMMethod_WrapObject, 1}, + {"UnwrapObject", PyXPCOMMethod_UnwrapObject, 1}, + {"_GetInterfaceCount", PyXPCOMMethod_GetInterfaceCount, 1}, + {"_GetGatewayCount", PyXPCOMMethod_GetGatewayCount, 1}, + {"getProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, + {"GetProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, + {"GetSpecialDirectory", PyGetSpecialDirectory, 1}, + {"AllocateBuffer", AllocateBuffer, 1}, + {"LogConsoleMessage", LogConsoleMessage, 1, "Write a message to the xpcom console service"}, + {"MakeVariant", PyXPCOMMethod_MakeVariant, 1}, + {"GetVariantValue", PyXPCOMMethod_GetVariantValue, 1}, +#ifdef VBOX + {"WaitForEvents", PyXPCOMMethod_WaitForEvents, 1}, + {"InterruptWait", PyXPCOMMethod_InterruptWait, 1}, + {"DeinitCOM", PyXPCOMMethod_DeinitCOM, 1}, + {"AttachThread", PyXPCOMMethod_AttachThread, 1}, + {"DetachThread", PyXPCOMMethod_DetachThread, 1}, +#endif +#ifdef VBOX_DEBUG_LIFETIMES + {"_DumpInterfaces", PyXPCOMMethod_DumpInterfaces, 1}, +#endif + // These should no longer be used - just use the logging.getLogger('pyxpcom')... + /* bird: The above comment refers to LogWarning and LogError. Both now removed. */ + { NULL } +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef xpcom_module = +{ + PyModuleDef_HEAD_INIT, + MODULE_NAME, /* name of module */ + NULL, /* module documentation */ + -1, /* size of per-interpreter state or -1 if using globals */ + xpcom_methods +}; +#endif + + +#define REGISTER_IID(t) { \ + PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \ + PyDict_SetItemString(dict, "IID_"#t, iid_ob); \ + Py_DECREF(iid_ob); \ + } + +#define REGISTER_INT(val) { \ + PyObject *ob = PyInt_FromLong(val); \ + PyDict_SetItemString(dict, #val, ob); \ + Py_DECREF(ob); \ + } + + +//////////////////////////////////////////////////////////// +// The module init code. +// +#if PY_MAJOR_VERSION <= 2 +extern "C" NS_EXPORT +void +#else +PyObject * +#endif +init_xpcom() { + PyObject *oModule; + + // ensure the framework has valid state to work with. + if (!PyXPCOM_Globals_Ensure()) +#if PY_MAJOR_VERSION <= 2 + return; +#else + return NULL; +#endif + + // Must force Python to start using thread locks + PyEval_InitThreads(); + + // Create the module and add the functions +#if PY_MAJOR_VERSION <= 2 + oModule = Py_InitModule(MODULE_NAME, xpcom_methods); +#else + oModule = PyModule_Create(&xpcom_module); +#endif + + PyObject *dict = PyModule_GetDict(oModule); + PyObject *pycom_Error = PyXPCOM_Error; + if (pycom_Error == NULL || PyDict_SetItemString(dict, "error", pycom_Error) != 0) + { + PyErr_SetString(PyExc_MemoryError, "can't define error"); +#if PY_MAJOR_VERSION <= 2 + return; +#else + return NULL; +#endif + } +#ifndef Py_LIMITED_API + PyDict_SetItemString(dict, "IIDType", (PyObject *)&Py_nsIID::type); +#else + PyDict_SetItemString(dict, "IIDType", (PyObject *)Py_nsIID::GetTypeObject()); +#endif + + REGISTER_IID(nsISupports); + REGISTER_IID(nsISupportsCString); + REGISTER_IID(nsISupportsString); + REGISTER_IID(nsIModule); + REGISTER_IID(nsIFactory); + REGISTER_IID(nsIWeakReference); + REGISTER_IID(nsISupportsWeakReference); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIServiceManager); + REGISTER_IID(nsIComponentRegistrar); + + // Register our custom interfaces. + REGISTER_IID(nsIComponentManager); + REGISTER_IID(nsIInterfaceInfoManager); + REGISTER_IID(nsIEnumerator); + REGISTER_IID(nsISimpleEnumerator); + REGISTER_IID(nsIInterfaceInfo); + REGISTER_IID(nsIInputStream); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIVariant); + // for backward compatibility: + REGISTER_IID(nsIComponentManagerObsolete); + + // No good reason not to expose this impl detail, and tests can use it + REGISTER_IID(nsIInternalPython); + // We have special support for proxies - may as well add their constants! + REGISTER_INT(PROXY_SYNC); + REGISTER_INT(PROXY_ASYNC); + REGISTER_INT(PROXY_ALWAYS); + // Build flags that may be useful. + PyObject *ob = PyBool_FromLong( +#ifdef NS_DEBUG + 1 +#else + 0 +#endif + ); + PyDict_SetItemString(dict, "NS_DEBUG", ob); + Py_DECREF(ob); +#if PY_MAJOR_VERSION >= 3 + return oModule; +#endif +} + +#ifdef VBOX_PYXPCOM +# include <VBox/com/com.h> +using namespace com; + +# include <iprt/initterm.h> +# include <iprt/string.h> +# include <iprt/alloca.h> +# include <iprt/stream.h> + +/** Set if NS_ShutdownXPCOM has been called successfully already and we don't + * need to do it again during module termination. This avoids assertion in the + * VBoxCOM glue code. */ +static bool g_fComShutdownAlready = true; + +# if PY_MAJOR_VERSION <= 2 +extern "C" NS_EXPORT +void +# else +/** @todo r=klaus this is hacky, but as Python3 doesn't deal with ELF + * visibility, assuming that all globals are visible (which is ugly and not + * true in our case). */ +# undef PyMODINIT_FUNC +# define PyMODINIT_FUNC extern "C" NS_EXPORT PyObject* +PyMODINIT_FUNC +# endif +initVBoxPython() { /* NOTE! This name is redefined at the top of the file! */ + static bool s_vboxInited = false; + if (!s_vboxInited) { + int rc = 0; /* Error handling in this code is NON-EXISTING. Sigh. */ + +# if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); +# else + const char *home = getenv("VBOX_PROGRAM_PATH"); + if (home) { + size_t len = strlen(home); + char *exepath = (char *)alloca(len + 32); + memcpy(exepath, home, len); + memcpy(exepath + len, "/pythonfake", sizeof("/pythonfake")); + rc = RTR3InitEx(RTR3INIT_VER_CUR, RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_UNOBTRUSIVE, 0, NULL, exepath); + } else { + rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + } +# endif + + rc = com::Initialize(); + g_fComShutdownAlready = false; + +# if PY_MAJOR_VERSION <= 2 + init_xpcom(); +# else + return init_xpcom(); +# endif + } +# if PY_MAJOR_VERSION >= 3 + return NULL; +# endif +} + +static +nsresult deinitVBoxPython() +{ + nsresult nr; + if (!g_fComShutdownAlready) + { + nr = com::Shutdown(); + if (!NS_FAILED(nr)) + g_fComShutdownAlready = true; + } + else + nr = NS_ERROR_NOT_INITIALIZED; + return nr; +} + +#endif /* VBOX_PYXPCOM */ |