LCOV - code coverage report
Current view: | top level - Modules/_ctypes - callbacks.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 0 | 155 | 0.0 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 0 | 8 | 0.0 %
|  |  | Branches: | 0 | 88 | 0.0 %

               Branch data     Line data    Source code
           1                 :            : #ifndef Py_BUILD_CORE_BUILTIN
           2                 :            : #  define Py_BUILD_CORE_MODULE 1
           3                 :            : #endif
           4                 :            :
           5                 :            : #include "Python.h"
           6                 :            : // windows.h must be included before pycore internal headers
           7                 :            : #ifdef MS_WIN32
           8                 :            : #  include <windows.h>
           9                 :            : #endif
          10                 :            :
          11                 :            : #include "pycore_call.h"            // _PyObject_CallNoArgs()
          12                 :            : #include "pycore_runtime.h"         // _PyRuntime
          13                 :            : #include "pycore_global_objects.h"  // _Py_ID()
          14                 :            :
          15                 :            : #include <stdbool.h>
          16                 :            :
          17                 :            : #ifdef MS_WIN32
          18                 :            : #  include <malloc.h>
          19                 :            : #endif
          20                 :            :
          21                 :            : #include <ffi.h>
          22                 :            : #include "ctypes.h"
          23                 :            :
          24                 :            : #ifdef HAVE_ALLOCA_H
          25                 :            : /* AIX needs alloca.h for alloca() */
          26                 :            : #include <alloca.h>
          27                 :            : #endif
          28                 :            :
          29                 :            : /**************************************************************/
          30                 :            :
          31                 :            : static void
          32                 :          0 : CThunkObject_dealloc(PyObject *myself)
          33                 :            : {
          34                 :          0 :     CThunkObject *self = (CThunkObject *)myself;
          35                 :          0 :     PyObject_GC_UnTrack(self);
          36                 :          0 :     Py_XDECREF(self->converters);
          37                 :          0 :     Py_XDECREF(self->callable);
          38                 :          0 :     Py_XDECREF(self->restype);
          39         [ #  # ]:          0 :     if (self->pcl_write)
          40                 :          0 :         Py_ffi_closure_free(self->pcl_write);
          41                 :          0 :     PyObject_GC_Del(self);
          42                 :          0 : }
          43                 :            :
          44                 :            : static int
          45                 :          0 : CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg)
          46                 :            : {
          47                 :          0 :     CThunkObject *self = (CThunkObject *)myself;
          48   [ #  #  #  # ]:          0 :     Py_VISIT(self->converters);
          49   [ #  #  #  # ]:          0 :     Py_VISIT(self->callable);
          50   [ #  #  #  # ]:          0 :     Py_VISIT(self->restype);
          51                 :          0 :     return 0;
          52                 :            : }
          53                 :            :
          54                 :            : static int
          55                 :          0 : CThunkObject_clear(PyObject *myself)
          56                 :            : {
          57                 :          0 :     CThunkObject *self = (CThunkObject *)myself;
          58         [ #  # ]:          0 :     Py_CLEAR(self->converters);
          59         [ #  # ]:          0 :     Py_CLEAR(self->callable);
          60         [ #  # ]:          0 :     Py_CLEAR(self->restype);
          61                 :          0 :     return 0;
          62                 :            : }
          63                 :            :
          64                 :            : PyTypeObject PyCThunk_Type = {
          65                 :            :     PyVarObject_HEAD_INIT(NULL, 0)
          66                 :            :     "_ctypes.CThunkObject",
          67                 :            :     sizeof(CThunkObject),                       /* tp_basicsize */
          68                 :            :     sizeof(ffi_type),                           /* tp_itemsize */
          69                 :            :     CThunkObject_dealloc,                       /* tp_dealloc */
          70                 :            :     0,                                          /* tp_vectorcall_offset */
          71                 :            :     0,                                          /* tp_getattr */
          72                 :            :     0,                                          /* tp_setattr */
          73                 :            :     0,                                          /* tp_as_async */
          74                 :            :     0,                                          /* tp_repr */
          75                 :            :     0,                                          /* tp_as_number */
          76                 :            :     0,                                          /* tp_as_sequence */
          77                 :            :     0,                                          /* tp_as_mapping */
          78                 :            :     0,                                          /* tp_hash */
          79                 :            :     0,                                          /* tp_call */
          80                 :            :     0,                                          /* tp_str */
          81                 :            :     0,                                          /* tp_getattro */
          82                 :            :     0,                                          /* tp_setattro */
          83                 :            :     0,                                          /* tp_as_buffer */
          84                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,                            /* tp_flags */
          85                 :            :     PyDoc_STR("CThunkObject"),                  /* tp_doc */
          86                 :            :     CThunkObject_traverse,                      /* tp_traverse */
          87                 :            :     CThunkObject_clear,                         /* tp_clear */
          88                 :            :     0,                                          /* tp_richcompare */
          89                 :            :     0,                                          /* tp_weaklistoffset */
          90                 :            :     0,                                          /* tp_iter */
          91                 :            :     0,                                          /* tp_iternext */
          92                 :            :     0,                                          /* tp_methods */
          93                 :            :     0,                                          /* tp_members */
          94                 :            : };
          95                 :            :
          96                 :            : /**************************************************************/
          97                 :            :
          98                 :            : static void
          99                 :          0 : PrintError(const char *msg, ...)
         100                 :            : {
         101                 :            :     char buf[512];
         102                 :          0 :     PyObject *f = PySys_GetObject("stderr");
         103                 :            :     va_list marker;
         104                 :            :
         105                 :          0 :     va_start(marker, msg);
         106                 :          0 :     PyOS_vsnprintf(buf, sizeof(buf), msg, marker);
         107                 :          0 :     va_end(marker);
         108   [ #  #  #  # ]:          0 :     if (f != NULL && f != Py_None)
         109                 :          0 :         PyFile_WriteString(buf, f);
         110                 :          0 :     PyErr_Print();
         111                 :          0 : }
         112                 :            :
         113                 :            :
         114                 :            : #ifdef MS_WIN32
         115                 :            : /*
         116                 :            :  * We must call AddRef() on non-NULL COM pointers we receive as arguments
         117                 :            :  * to callback functions - these functions are COM method implementations.
         118                 :            :  * The Python instances we create have a __del__ method which calls Release().
         119                 :            :  *
         120                 :            :  * The presence of a class attribute named '_needs_com_addref_' triggers this
         121                 :            :  * behaviour.  It would also be possible to call the AddRef() Python method,
         122                 :            :  * after checking for PyObject_IsTrue(), but this would probably be somewhat
         123                 :            :  * slower.
         124                 :            :  */
         125                 :            : static void
         126                 :            : TryAddRef(StgDictObject *dict, CDataObject *obj)
         127                 :            : {
         128                 :            :     IUnknown *punk;
         129                 :            :     int r = PyDict_Contains((PyObject *)dict, &_Py_ID(_needs_com_addref_));
         130                 :            :     if (r <= 0) {
         131                 :            :         if (r < 0) {
         132                 :            :             PrintError("getting _needs_com_addref_");
         133                 :            :         }
         134                 :            :         return;
         135                 :            :     }
         136                 :            :
         137                 :            :     punk = *(IUnknown **)obj->b_ptr;
         138                 :            :     if (punk)
         139                 :            :         punk->lpVtbl->AddRef(punk);
         140                 :            :     return;
         141                 :            : }
         142                 :            : #endif
         143                 :            :
         144                 :            : /******************************************************************************
         145                 :            :  *
         146                 :            :  * Call the python object with all arguments
         147                 :            :  *
         148                 :            :  */
         149                 :          0 : static void _CallPythonObject(void *mem,
         150                 :            :                               ffi_type *restype,
         151                 :            :                               SETFUNC setfunc,
         152                 :            :                               PyObject *callable,
         153                 :            :                               PyObject *converters,
         154                 :            :                               int flags,
         155                 :            :                               void **pArgs)
         156                 :            : {
         157                 :          0 :     PyObject *result = NULL;
         158                 :          0 :     Py_ssize_t i = 0, j = 0, nargs = 0;
         159                 :          0 :     PyObject *error_object = NULL;
         160                 :            :     int *space;
         161                 :          0 :     PyGILState_STATE state = PyGILState_Ensure();
         162                 :            :
         163                 :            :     assert(PyTuple_Check(converters));
         164                 :          0 :     nargs = PyTuple_GET_SIZE(converters);
         165                 :            :     assert(nargs <= CTYPES_MAX_ARGCOUNT);
         166                 :          0 :     PyObject **args = alloca(nargs * sizeof(PyObject *));
         167         [ #  # ]:          0 :     PyObject **cnvs = PySequence_Fast_ITEMS(converters);
         168         [ #  # ]:          0 :     for (i = 0; i < nargs; i++) {
         169                 :          0 :         PyObject *cnv = cnvs[i]; // borrowed ref
         170                 :            :         StgDictObject *dict;
         171                 :          0 :         dict = PyType_stgdict(cnv);
         172                 :            :
         173   [ #  #  #  #  :          0 :         if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
                       #  # ]
         174                 :          0 :             PyObject *v = dict->getfunc(*pArgs, dict->size);
         175         [ #  # ]:          0 :             if (!v) {
         176                 :          0 :                 PrintError("create argument %zd:\n", i);
         177                 :          0 :                 goto Done;
         178                 :            :             }
         179                 :          0 :             args[i] = v;
         180                 :            :             /* XXX XXX XX
         181                 :            :                We have the problem that c_byte or c_short have dict->size of
         182                 :            :                1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
         183                 :            :                BTW, the same problem occurs when they are pushed as parameters
         184                 :            :             */
         185         [ #  # ]:          0 :         } else if (dict) {
         186                 :            :             /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
         187                 :          0 :             CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv);
         188         [ #  # ]:          0 :             if (!obj) {
         189                 :          0 :                 PrintError("create argument %zd:\n", i);
         190                 :          0 :                 goto Done;
         191                 :            :             }
         192         [ #  # ]:          0 :             if (!CDataObject_Check(obj)) {
         193                 :          0 :                 Py_DECREF(obj);
         194                 :          0 :                 PrintError("unexpected result of create argument %zd:\n", i);
         195                 :          0 :                 goto Done;
         196                 :            :             }
         197                 :          0 :             memcpy(obj->b_ptr, *pArgs, dict->size);
         198                 :          0 :             args[i] = (PyObject *)obj;
         199                 :            : #ifdef MS_WIN32
         200                 :            :             TryAddRef(dict, obj);
         201                 :            : #endif
         202                 :            :         } else {
         203                 :          0 :             PyErr_SetString(PyExc_TypeError,
         204                 :            :                             "cannot build parameter");
         205                 :          0 :             PrintError("Parsing argument %zd\n", i);
         206                 :          0 :             goto Done;
         207                 :            :         }
         208                 :            :         /* XXX error handling! */
         209                 :          0 :         pArgs++;
         210                 :            :     }
         211                 :            :
         212         [ #  # ]:          0 :     if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
         213                 :          0 :         error_object = _ctypes_get_errobj(&space);
         214         [ #  # ]:          0 :         if (error_object == NULL)
         215                 :          0 :             goto Done;
         216         [ #  # ]:          0 :         if (flags & FUNCFLAG_USE_ERRNO) {
         217                 :          0 :             int temp = space[0];
         218                 :          0 :             space[0] = errno;
         219                 :          0 :             errno = temp;
         220                 :            :         }
         221                 :            : #ifdef MS_WIN32
         222                 :            :         if (flags & FUNCFLAG_USE_LASTERROR) {
         223                 :            :             int temp = space[1];
         224                 :            :             space[1] = GetLastError();
         225                 :            :             SetLastError(temp);
         226                 :            :         }
         227                 :            : #endif
         228                 :            :     }
         229                 :            :
         230                 :          0 :     result = PyObject_Vectorcall(callable, args, nargs, NULL);
         231         [ #  # ]:          0 :     if (result == NULL) {
         232                 :          0 :         _PyErr_WriteUnraisableMsg("on calling ctypes callback function",
         233                 :            :                                   callable);
         234                 :            :     }
         235                 :            :
         236                 :            : #ifdef MS_WIN32
         237                 :            :     if (flags & FUNCFLAG_USE_LASTERROR) {
         238                 :            :         int temp = space[1];
         239                 :            :         space[1] = GetLastError();
         240                 :            :         SetLastError(temp);
         241                 :            :     }
         242                 :            : #endif
         243         [ #  # ]:          0 :     if (flags & FUNCFLAG_USE_ERRNO) {
         244                 :          0 :         int temp = space[0];
         245                 :          0 :         space[0] = errno;
         246                 :          0 :         errno = temp;
         247                 :            :     }
         248                 :          0 :     Py_XDECREF(error_object);
         249                 :            :
         250   [ #  #  #  # ]:          0 :     if (restype != &ffi_type_void && result) {
         251                 :            :         assert(setfunc);
         252                 :            :
         253                 :            : #ifdef WORDS_BIGENDIAN
         254                 :            :         /* See the corresponding code in _ctypes_callproc():
         255                 :            :            in callproc.c, around line 1219. */
         256                 :            :         if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) {
         257                 :            :             mem = (char *)mem + sizeof(ffi_arg) - restype->size;
         258                 :            :         }
         259                 :            : #endif
         260                 :            :
         261                 :            :         /* keep is an object we have to keep alive so that the result
         262                 :            :            stays valid.  If there is no such object, the setfunc will
         263                 :            :            have returned Py_None.
         264                 :            :
         265                 :            :            If there is such an object, we have no choice than to keep
         266                 :            :            it alive forever - but a refcount and/or memory leak will
         267                 :            :            be the result.  EXCEPT when restype is py_object - Python
         268                 :            :            itself knows how to manage the refcount of these objects.
         269                 :            :         */
         270                 :          0 :         PyObject *keep = setfunc(mem, result, 0);
         271                 :            :
         272         [ #  # ]:          0 :         if (keep == NULL) {
         273                 :            :             /* Could not convert callback result. */
         274                 :          0 :             _PyErr_WriteUnraisableMsg("on converting result "
         275                 :            :                                       "of ctypes callback function",
         276                 :            :                                       callable);
         277                 :            :         }
         278         [ #  # ]:          0 :         else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) {
         279         [ #  # ]:          0 :             if (keep == Py_None) {
         280                 :            :                 /* Nothing to keep */
         281                 :          0 :                 Py_DECREF(keep);
         282                 :            :             }
         283         [ #  # ]:          0 :             else if (PyErr_WarnEx(PyExc_RuntimeWarning,
         284                 :            :                                   "memory leak in callback function.",
         285                 :            :                                   1) == -1) {
         286                 :          0 :                 _PyErr_WriteUnraisableMsg("on converting result "
         287                 :            :                                           "of ctypes callback function",
         288                 :            :                                           callable);
         289                 :            :             }
         290                 :            :         }
         291                 :            :     }
         292                 :            :
         293                 :          0 :     Py_XDECREF(result);
         294                 :            :
         295                 :          0 :   Done:
         296         [ #  # ]:          0 :     for (j = 0; j < i; j++) {
         297                 :          0 :         Py_DECREF(args[j]);
         298                 :            :     }
         299                 :          0 :     PyGILState_Release(state);
         300                 :          0 : }
         301                 :            :
         302                 :          0 : static void closure_fcn(ffi_cif *cif,
         303                 :            :                         void *resp,
         304                 :            :                         void **args,
         305                 :            :                         void *userdata)
         306                 :            : {
         307                 :          0 :     CThunkObject *p = (CThunkObject *)userdata;
         308                 :            :
         309                 :          0 :     _CallPythonObject(resp,
         310                 :            :                       p->ffi_restype,
         311                 :            :                       p->setfunc,
         312                 :            :                       p->callable,
         313                 :            :                       p->converters,
         314                 :            :                       p->flags,
         315                 :            :                       args);
         316                 :          0 : }
         317                 :            :
         318                 :          0 : static CThunkObject* CThunkObject_new(Py_ssize_t nargs)
         319                 :            : {
         320                 :            :     CThunkObject *p;
         321                 :            :     Py_ssize_t i;
         322                 :            :
         323                 :          0 :     p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs);
         324         [ #  # ]:          0 :     if (p == NULL) {
         325                 :          0 :         return NULL;
         326                 :            :     }
         327                 :            :
         328                 :          0 :     p->pcl_write = NULL;
         329                 :          0 :     p->pcl_exec = NULL;
         330                 :          0 :     memset(&p->cif, 0, sizeof(p->cif));
         331                 :          0 :     p->flags = 0;
         332                 :          0 :     p->converters = NULL;
         333                 :          0 :     p->callable = NULL;
         334                 :          0 :     p->restype = NULL;
         335                 :          0 :     p->setfunc = NULL;
         336                 :          0 :     p->ffi_restype = NULL;
         337                 :            :
         338         [ #  # ]:          0 :     for (i = 0; i < nargs + 1; ++i)
         339                 :          0 :         p->atypes[i] = NULL;
         340                 :          0 :     PyObject_GC_Track((PyObject *)p);
         341                 :          0 :     return p;
         342                 :            : }
         343                 :            :
         344                 :          0 : CThunkObject *_ctypes_alloc_callback(PyObject *callable,
         345                 :            :                                     PyObject *converters,
         346                 :            :                                     PyObject *restype,
         347                 :            :                                     int flags)
         348                 :            : {
         349                 :            :     int result;
         350                 :            :     CThunkObject *p;
         351                 :            :     Py_ssize_t nargs, i;
         352                 :            :     ffi_abi cc;
         353                 :            :
         354                 :            :     assert(PyTuple_Check(converters));
         355                 :          0 :     nargs = PyTuple_GET_SIZE(converters);
         356                 :          0 :     p = CThunkObject_new(nargs);
         357         [ #  # ]:          0 :     if (p == NULL)
         358                 :          0 :         return NULL;
         359                 :            :
         360                 :            :     assert(CThunk_CheckExact((PyObject *)p));
         361                 :            :
         362                 :          0 :     p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
         363         [ #  # ]:          0 :     if (p->pcl_write == NULL) {
         364                 :          0 :         PyErr_NoMemory();
         365                 :          0 :         goto error;
         366                 :            :     }
         367                 :            :
         368                 :          0 :     p->flags = flags;
         369         [ #  # ]:          0 :     PyObject **cnvs = PySequence_Fast_ITEMS(converters);
         370         [ #  # ]:          0 :     for (i = 0; i < nargs; ++i) {
         371                 :          0 :         PyObject *cnv = cnvs[i]; // borrowed ref
         372                 :          0 :         p->atypes[i] = _ctypes_get_ffi_type(cnv);
         373                 :            :     }
         374                 :          0 :     p->atypes[i] = NULL;
         375                 :            :
         376                 :          0 :     p->restype = Py_NewRef(restype);
         377         [ #  # ]:          0 :     if (restype == Py_None) {
         378                 :          0 :         p->setfunc = NULL;
         379                 :          0 :         p->ffi_restype = &ffi_type_void;
         380                 :            :     } else {
         381                 :          0 :         StgDictObject *dict = PyType_stgdict(restype);
         382   [ #  #  #  # ]:          0 :         if (dict == NULL || dict->setfunc == NULL) {
         383                 :          0 :           PyErr_SetString(PyExc_TypeError,
         384                 :            :                           "invalid result type for callback function");
         385                 :          0 :           goto error;
         386                 :            :         }
         387                 :          0 :         p->setfunc = dict->setfunc;
         388                 :          0 :         p->ffi_restype = &dict->ffi_type_pointer;
         389                 :            :     }
         390                 :            :
         391                 :          0 :     cc = FFI_DEFAULT_ABI;
         392                 :            : #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64) && !defined(_M_ARM)
         393                 :            :     if ((flags & FUNCFLAG_CDECL) == 0)
         394                 :            :         cc = FFI_STDCALL;
         395                 :            : #endif
         396                 :          0 :     result = ffi_prep_cif(&p->cif, cc,
         397                 :            :                           Py_SAFE_DOWNCAST(nargs, Py_ssize_t, int),
         398                 :            :                           p->ffi_restype,
         399                 :            :                           &p->atypes[0]);
         400         [ #  # ]:          0 :     if (result != FFI_OK) {
         401                 :          0 :         PyErr_Format(PyExc_RuntimeError,
         402                 :            :                      "ffi_prep_cif failed with %d", result);
         403                 :          0 :         goto error;
         404                 :            :     }
         405                 :            :
         406                 :            :
         407                 :            : #if HAVE_FFI_PREP_CLOSURE_LOC
         408                 :            : #   ifdef USING_APPLE_OS_LIBFFI
         409                 :            : #    ifdef HAVE_BUILTIN_AVAILABLE
         410                 :            : #      define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
         411                 :            : #    else
         412                 :            : #      define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME (ffi_prep_closure_loc != NULL)
         413                 :            : #    endif
         414                 :            : #   else
         415                 :            : #      define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME 1
         416                 :            : #   endif
         417                 :            :     if (HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME) {
         418                 :          0 :         result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn,
         419                 :            :                                     p,
         420                 :            :                                     p->pcl_exec);
         421                 :            :     } else
         422                 :            : #endif
         423                 :            :     {
         424                 :            : #if defined(USING_APPLE_OS_LIBFFI) && defined(__arm64__)
         425                 :            :         PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing");
         426                 :            :         goto error;
         427                 :            : #else
         428                 :            : #if defined(__clang__)
         429                 :            :         #pragma clang diagnostic push
         430                 :            :         #pragma clang diagnostic ignored "-Wdeprecated-declarations"
         431                 :            : #endif
         432                 :            : #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
         433                 :            :         #pragma GCC diagnostic push
         434                 :            :         #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
         435                 :            : #endif
         436                 :            :         result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p);
         437                 :            :
         438                 :            : #if defined(__clang__)
         439                 :            :         #pragma clang diagnostic pop
         440                 :            : #endif
         441                 :            : #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
         442                 :            :         #pragma GCC diagnostic pop
         443                 :            : #endif
         444                 :            :
         445                 :            : #endif
         446                 :            :     }
         447         [ #  # ]:          0 :     if (result != FFI_OK) {
         448                 :          0 :         PyErr_Format(PyExc_RuntimeError,
         449                 :            :                      "ffi_prep_closure failed with %d", result);
         450                 :          0 :         goto error;
         451                 :            :     }
         452                 :            :
         453                 :          0 :     p->converters = Py_NewRef(converters);
         454                 :          0 :     p->callable = Py_NewRef(callable);
         455                 :          0 :     return p;
         456                 :            :
         457                 :          0 :   error:
         458                 :          0 :     Py_XDECREF(p);
         459                 :          0 :     return NULL;
         460                 :            : }
         461                 :            :
         462                 :            : #ifdef MS_WIN32
         463                 :            :
         464                 :            : static void LoadPython(void)
         465                 :            : {
         466                 :            :     if (!Py_IsInitialized()) {
         467                 :            :         Py_Initialize();
         468                 :            :     }
         469                 :            : }
         470                 :            :
         471                 :            : /******************************************************************/
         472                 :            :
         473                 :            : long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
         474                 :            : {
         475                 :            :     PyObject *func, *result;
         476                 :            :     long retval;
         477                 :            :     static PyObject *context;
         478                 :            :
         479                 :            :     if (context == NULL)
         480                 :            :         context = PyUnicode_InternFromString("_ctypes.DllGetClassObject");
         481                 :            :
         482                 :            :     func = _PyImport_GetModuleAttrString("ctypes", "DllGetClassObject");
         483                 :            :     if (!func) {
         484                 :            :         PyErr_WriteUnraisable(context ? context : Py_None);
         485                 :            :         /* There has been a warning before about this already */
         486                 :            :         return E_FAIL;
         487                 :            :     }
         488                 :            :
         489                 :            :     {
         490                 :            :         PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid);
         491                 :            :         PyObject *py_riid = PyLong_FromVoidPtr((void *)riid);
         492                 :            :         PyObject *py_ppv = PyLong_FromVoidPtr(ppv);
         493                 :            :         if (!py_rclsid || !py_riid || !py_ppv) {
         494                 :            :             Py_XDECREF(py_rclsid);
         495                 :            :             Py_XDECREF(py_riid);
         496                 :            :             Py_XDECREF(py_ppv);
         497                 :            :             Py_DECREF(func);
         498                 :            :             PyErr_WriteUnraisable(context ? context : Py_None);
         499                 :            :             return E_FAIL;
         500                 :            :         }
         501                 :            :         result = PyObject_CallFunctionObjArgs(func,
         502                 :            :                                               py_rclsid,
         503                 :            :                                               py_riid,
         504                 :            :                                               py_ppv,
         505                 :            :                                               NULL);
         506                 :            :         Py_DECREF(py_rclsid);
         507                 :            :         Py_DECREF(py_riid);
         508                 :            :         Py_DECREF(py_ppv);
         509                 :            :     }
         510                 :            :     Py_DECREF(func);
         511                 :            :     if (!result) {
         512                 :            :         PyErr_WriteUnraisable(context ? context : Py_None);
         513                 :            :         return E_FAIL;
         514                 :            :     }
         515                 :            :
         516                 :            :     retval = PyLong_AsLong(result);
         517                 :            :     if (PyErr_Occurred()) {
         518                 :            :         PyErr_WriteUnraisable(context ? context : Py_None);
         519                 :            :         retval = E_FAIL;
         520                 :            :     }
         521                 :            :     Py_DECREF(result);
         522                 :            :     return retval;
         523                 :            : }
         524                 :            :
         525                 :            : STDAPI DllGetClassObject(REFCLSID rclsid,
         526                 :            :                          REFIID riid,
         527                 :            :                          LPVOID *ppv)
         528                 :            : {
         529                 :            :     long result;
         530                 :            :     PyGILState_STATE state;
         531                 :            :
         532                 :            :     LoadPython();
         533                 :            :     state = PyGILState_Ensure();
         534                 :            :     result = Call_GetClassObject(rclsid, riid, ppv);
         535                 :            :     PyGILState_Release(state);
         536                 :            :     return result;
         537                 :            : }
         538                 :            :
         539                 :            : long Call_CanUnloadNow(void)
         540                 :            : {
         541                 :            :     PyObject *mod, *func, *result;
         542                 :            :     long retval;
         543                 :            :     static PyObject *context;
         544                 :            :
         545                 :            :     if (context == NULL)
         546                 :            :         context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow");
         547                 :            :
         548                 :            :     mod = PyImport_ImportModule("ctypes");
         549                 :            :     if (!mod) {
         550                 :            : /*              OutputDebugString("Could not import ctypes"); */
         551                 :            :         /* We assume that this error can only occur when shutting
         552                 :            :            down, so we silently ignore it */
         553                 :            :         PyErr_Clear();
         554                 :            :         return E_FAIL;
         555                 :            :     }
         556                 :            :     /* Other errors cannot be raised, but are printed to stderr */
         557                 :            :     func = PyObject_GetAttrString(mod, "DllCanUnloadNow");
         558                 :            :     Py_DECREF(mod);
         559                 :            :     if (!func) {
         560                 :            :         PyErr_WriteUnraisable(context ? context : Py_None);
         561                 :            :         return E_FAIL;
         562                 :            :     }
         563                 :            :
         564                 :            :     result = _PyObject_CallNoArgs(func);
         565                 :            :     Py_DECREF(func);
         566                 :            :     if (!result) {
         567                 :            :         PyErr_WriteUnraisable(context ? context : Py_None);
         568                 :            :         return E_FAIL;
         569                 :            :     }
         570                 :            :
         571                 :            :     retval = PyLong_AsLong(result);
         572                 :            :     if (PyErr_Occurred()) {
         573                 :            :         PyErr_WriteUnraisable(context ? context : Py_None);
         574                 :            :         retval = E_FAIL;
         575                 :            :     }
         576                 :            :     Py_DECREF(result);
         577                 :            :     return retval;
         578                 :            : }
         579                 :            :
         580                 :            : /*
         581                 :            :   DllRegisterServer and DllUnregisterServer still missing
         582                 :            : */
         583                 :            :
         584                 :            : STDAPI DllCanUnloadNow(void)
         585                 :            : {
         586                 :            :     long result;
         587                 :            :     PyGILState_STATE state = PyGILState_Ensure();
         588                 :            :     result = Call_CanUnloadNow();
         589                 :            :     PyGILState_Release(state);
         590                 :            :     return result;
         591                 :            : }
         592                 :            :
         593                 :            : #ifndef Py_NO_ENABLE_SHARED
         594                 :            : BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes)
         595                 :            : {
         596                 :            :     switch(fdwReason) {
         597                 :            :     case DLL_PROCESS_ATTACH:
         598                 :            :         DisableThreadLibraryCalls(hinstDLL);
         599                 :            :         break;
         600                 :            :     }
         601                 :            :     return TRUE;
         602                 :            : }
         603                 :            : #endif
         604                 :            :
         605                 :            : #endif
         606                 :            :
         607                 :            : /*
         608                 :            :  Local Variables:
         609                 :            :  compile-command: "cd .. && python setup.py -q build_ext"
         610                 :            :  End:
         611                 :            : */

Generated by: LCOV version 1.14