cpython/Modules/_ctypes/callbacks.c

#ifndef Py_BUILD_CORE_BUILTIN
#define Py_BUILD_CORE_MODULE
#endif

#include "Python.h"
// windows.h must be included before pycore internal headers
#ifdef MS_WIN32
#  include <windows.h>
#endif

#include "pycore_call.h"          // _PyObject_CallNoArgs()
#include "pycore_runtime.h"       // _Py_ID()

#include <stdbool.h>

#ifdef MS_WIN32
#  include <malloc.h>
#endif

#include <ffi.h>
#include "ctypes.h"

#ifdef HAVE_ALLOCA_H
/* AIX needs alloca.h for alloca() */
#include <alloca.h>
#endif

/**************************************************************/

static int
CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg)
{}

static int
CThunkObject_clear(PyObject *myself)
{}

static void
CThunkObject_dealloc(PyObject *myself)
{}

static PyType_Slot cthunk_slots[] =;

PyType_Spec cthunk_spec =;

/**************************************************************/

static void
PrintError(const char *msg, ...)
{}


#ifdef MS_WIN32
/*
 * We must call AddRef() on non-NULL COM pointers we receive as arguments
 * to callback functions - these functions are COM method implementations.
 * The Python instances we create have a __del__ method which calls Release().
 *
 * The presence of a class attribute named '_needs_com_addref_' triggers this
 * behaviour.  It would also be possible to call the AddRef() Python method,
 * after checking for PyObject_IsTrue(), but this would probably be somewhat
 * slower.
 */
static void
TryAddRef(PyObject *cnv, CDataObject *obj)
{
    IUnknown *punk;
    PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv);
    if (!attrdict) {
        return;
    }
    int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_));
    if (r <= 0) {
        if (r < 0) {
            PrintError("getting _needs_com_addref_");
        }
        return;
    }

    punk = *(IUnknown **)obj->b_ptr;
    if (punk)
        punk->lpVtbl->AddRef(punk);
    return;
}
#endif

/******************************************************************************
 *
 * Call the python object with all arguments
 *
 */

// BEWARE: The GIL needs to be held throughout the function
static void _CallPythonObject(ctypes_state *st,
                              void *mem,
                              ffi_type *restype,
                              SETFUNC setfunc,
                              PyObject *callable,
                              PyObject *converters,
                              int flags,
                              void **pArgs)
{}

static void closure_fcn(ffi_cif *cif,
                        void *resp,
                        void **args,
                        void *userdata)
{}

static CThunkObject* CThunkObject_new(ctypes_state *st, Py_ssize_t nargs)
{}

CThunkObject *_ctypes_alloc_callback(ctypes_state *st,
                                    PyObject *callable,
                                    PyObject *converters,
                                    PyObject *restype,
                                    int flags)
{}

#ifdef MS_WIN32

static void LoadPython(void)
{
    if (!Py_IsInitialized()) {
        Py_Initialize();
    }
}

/******************************************************************/

long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
    PyObject *func, *result;
    long retval;
    static PyObject *context;

    if (context == NULL)
        context = PyUnicode_InternFromString("_ctypes.DllGetClassObject");

    func = _PyImport_GetModuleAttrString("ctypes", "DllGetClassObject");
    if (!func) {
        PyErr_WriteUnraisable(context ? context : Py_None);
        /* There has been a warning before about this already */
        return E_FAIL;
    }

    {
        PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid);
        if (py_rclsid == NULL) {
            Py_DECREF(func);
            PyErr_WriteUnraisable(context ? context : Py_None);
            return E_FAIL;
        }
        PyObject *py_riid = PyLong_FromVoidPtr((void *)riid);
        if (py_riid == NULL) {
            Py_DECREF(func);
            Py_DECREF(py_rclsid);
            PyErr_WriteUnraisable(context ? context : Py_None);
            return E_FAIL;
        }
        PyObject *py_ppv = PyLong_FromVoidPtr(ppv);
        if (py_ppv == NULL) {
            Py_DECREF(py_rclsid);
            Py_DECREF(py_riid);
            Py_DECREF(func);
            PyErr_WriteUnraisable(context ? context : Py_None);
            return E_FAIL;
        }
        result = PyObject_CallFunctionObjArgs(func,
                                              py_rclsid,
                                              py_riid,
                                              py_ppv,
                                              NULL);
        Py_DECREF(py_rclsid);
        Py_DECREF(py_riid);
        Py_DECREF(py_ppv);
    }
    Py_DECREF(func);
    if (!result) {
        PyErr_WriteUnraisable(context ? context : Py_None);
        return E_FAIL;
    }

    retval = PyLong_AsLong(result);
    if (PyErr_Occurred()) {
        PyErr_WriteUnraisable(context ? context : Py_None);
        retval = E_FAIL;
    }
    Py_DECREF(result);
    return retval;
}

STDAPI DllGetClassObject(REFCLSID rclsid,
                         REFIID riid,
                         LPVOID *ppv)
{
    long result;
    PyGILState_STATE state;

    LoadPython();
    state = PyGILState_Ensure();
    result = Call_GetClassObject(rclsid, riid, ppv);
    PyGILState_Release(state);
    return result;
}

long Call_CanUnloadNow(void)
{
    PyObject *mod, *func, *result;
    long retval;
    static PyObject *context;

    if (context == NULL)
        context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow");

    mod = PyImport_ImportModule("ctypes");
    if (!mod) {
/*              OutputDebugString("Could not import ctypes"); */
        /* We assume that this error can only occur when shutting
           down, so we silently ignore it */
        PyErr_Clear();
        return E_FAIL;
    }
    /* Other errors cannot be raised, but are printed to stderr */
    func = PyObject_GetAttrString(mod, "DllCanUnloadNow");
    Py_DECREF(mod);
    if (!func) {
        PyErr_WriteUnraisable(context ? context : Py_None);
        return E_FAIL;
    }

    result = _PyObject_CallNoArgs(func);
    Py_DECREF(func);
    if (!result) {
        PyErr_WriteUnraisable(context ? context : Py_None);
        return E_FAIL;
    }

    retval = PyLong_AsLong(result);
    if (PyErr_Occurred()) {
        PyErr_WriteUnraisable(context ? context : Py_None);
        retval = E_FAIL;
    }
    Py_DECREF(result);
    return retval;
}

/*
  DllRegisterServer and DllUnregisterServer still missing
*/

STDAPI DllCanUnloadNow(void)
{
    long result;
    PyGILState_STATE state = PyGILState_Ensure();
    result = Call_CanUnloadNow();
    PyGILState_Release(state);
    return result;
}

#ifndef Py_NO_ENABLE_SHARED
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes)
{
    switch(fdwReason) {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hinstDLL);
        break;
    }
    return TRUE;
}
#endif

#endif

/*
 Local Variables:
 compile-command: "cd .. && python setup.py -q build_ext"
 End:
*/