/* Chrysalide - Outil d'analyse de fichiers binaires * bindings.c - éléments d'un socle commun aux fonctionnalités graphiques et non graphiques * * Copyright (C) 2024 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "bindings.h" #ifdef PYTHON_PACKAGE # include #endif #include #include #include #include #include // REMME ? #include // REMME ? #include "access.h" #include "constants.h" #include "helpers.h" #include "star.h" //#include "strenum.h" #include "struct.h" #include "analysis/module.h" #include "arch/module.h" #include "common/module.h" #include "core/module.h" #include "glibext/module.h" /* #include "debug/module.h" */ #include "format/module.h" /* #ifdef INCLUDE_GTK_SUPPORT */ /* # include "gtkext/module.h" */ /* # include "gui/module.h" */ /* #endif */ /* #include "mangling/module.h" */ #include "plugins/module.h" /* ------------------------ FONCTIONNALITES POUR CODE PYTHON ------------------------ */ #define PYCHRYSALIDE_NAME "pychrysalide" #define PYCHRYSALIDE_DOC \ "PyChrysalide is a module containing Chrysalide's features and designed for Python users.\n" \ "\n" \ "The whole API is defined in a single library named 'pychrysalide.so' and can be used in two ways:\n" \ "* either from the Chrysalide's GUI, by registering hooks or GLib signals;\n" \ "* or from a shell command line, by setting PYTHONPATH to point to the directory containing the library.\n" \ "\n" \ "In both cases, this is a good start point to have a look at already existing plugins to quickly learn " \ "how the API works.\n" \ "\n" \ "These plugins are located in the 'plugins/python' directory.\n" \ "\n" \ "The *pychrysalide* module imports the GLib module (version 2.0) from the GI repository at startup." /* Fournit la révision du programme global. */ static PyObject *py_chrysalide_revision(PyObject *, PyObject *); /* Fournit la version du programme global. */ static PyObject *py_chrysalide_version(PyObject *, PyObject *); /* Fournit la version du greffon pour Python. */ static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *); /* ------------------------ FONCTIONNALITES DE MISE EN PLACE ------------------------ */ /* Détermine si l'interpréteur lancé est celui pris en compte. */ static bool is_current_abi_suitable(void); /* Assure une pleine initialisation des objets de Python-GI. */ static bool install_metaclass_for_python_gobjects(void); /* Met en place un environnement pour l'extension Python. */ static bool setup_python_context(void); /* Assure la définition d'un type GObject pour Python adapté. */ static void ensure_native_pygobject_type(PyTypeObject **); /* Fournit la référence à un éventuel module déjà en place. */ static PyObject *get_existing_modules(void); /* Définit les différents modules du support Python. */ static PyObject *create_basic_modules(void); /* Inscrit les défintions des objets Python de Chrysalide. */ static bool populate_python_modules(const pyinit_details_t *); /* Restore une ancienne définition de type GObject au besoin. */ static void restore_original_pygobject_type(PyTypeObject *); /* ------------------------ FONCTIONS GLOBALES DE CHRYSALIDE ------------------------ */ /* Point de sortie pour l'initialisation de Python. */ static void PyExit_pychrysalide(void); /* ---------------------------------------------------------------------------------- */ /* FONCTIONNALITES POUR CODE PYTHON */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : self = NULL car méthode statique. * * args = non utilisé ici. * * * * Description : Fournit la révision du programme global. * * * * Retour : Numéro de révision. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_chrysalide_revision(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ #define PY_CHRYSALIDE_REVISION_METHOD PYTHON_METHOD_DEF \ ( \ revision, "/", \ METH_NOARGS, py_chrysalide, \ "Provide the revision number of Chrysalide.\n" \ "\n" \ "The returned value is provided as a string, for instance: 'r1665'." \ ) result = PyUnicode_FromString("r" XSTR(REVISION)); return result; } /****************************************************************************** * * * Paramètres : self = NULL car méthode statique. * * args = non utilisé ici. * * * * Description : Fournit la version du programme global. * * * * Retour : Numéro de version. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_chrysalide_version(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ int major; /* Numéro de version majeur */ int minor; /* Numéro de version mineur */ int revision; /* Numéro de révision */ char version[16]; /* Conservation temporaire */ #define PY_CHRYSALIDE_VERSION_METHOD PYTHON_METHOD_DEF \ ( \ version, "/", \ METH_NOARGS, py_chrysalide, \ "Provide the version number of Chrysalide.\n" \ "\n" \ "The returned value is provided as a string, for instance: '1.6.65'." \ ) major = REVISION / 1000; minor = (REVISION - (major * 1000)) / 100; revision = REVISION % 100; snprintf(version, sizeof(version), "%d.%d.%d", major, minor, revision); result = PyUnicode_FromString(version); return result; } /****************************************************************************** * * * Paramètres : self = NULL car méthode statique. * * args = non utilisé ici. * * * * Description : Fournit la version du greffon pour Python. * * * * Retour : Numéro de version. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_chrysalide_mod_version(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ char version[16]; /* Conservation temporaire */ #define PY_CHRYSALIDE_MOD_VERSION_METHOD PYTHON_METHOD_DEF \ ( \ mod_version, "/", \ METH_NOARGS, py_chrysalide, \ "Provide the version number of Chrysalide module for Python.\n" \ "\n" \ "The returned value is provided as a string, for instance: '0.1.0'." \ ) snprintf(version, sizeof(version), "%s", "x.x.x");// FIXME _chrysalide_plugin.version); result = PyUnicode_FromString(version); return result; } /* ---------------------------------------------------------------------------------- */ /* FONCTIONNALITES DE MISE EN PLACE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : - * * * * Description : Détermine si l'interpréteur lancé est celui pris en compte. * * * * Retour : true si l'exécution peut se poursuivre, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool is_current_abi_suitable(void) { bool result; int fds[2]; int ret; char cmds[128]; char content[64]; ssize_t got; #define GRAB_ABI_FLAGS_IN_PYTHON \ "import sys" "\n" \ "import os" "\n" \ "data = bytes(sys.abiflags, 'UTF-8') + b'\\0'" "\n" \ "os.write(%d, data)" "\n" result = false; ret = pipe(fds); if (ret == -1) { perror("pipe()"); goto exit; } snprintf(cmds, sizeof(cmds), GRAB_ABI_FLAGS_IN_PYTHON, fds[1]); ret = PyRun_SimpleString(cmds); if (ret != 0) goto exit_with_pipe; got = read(fds[0], content, sizeof(content)); if (got < 0) { perror("read()"); goto exit_with_pipe; } content[got] = '\0'; result = (strcmp(content, LIBPYTHON_ABI_FLAGS) == 0); exit_with_pipe: close(fds[0]); close(fds[1]); exit: if (!result) PyErr_SetString(PyExc_SystemError, "the ABI flags of the current interpreter do not match " \ "the ones of the Python library used during the module compilation."); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Assure une pleine initialisation des objets de Python-GI. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool install_metaclass_for_python_gobjects(void) { bool result; /* Bilan à retourner */ PyObject *gi_types_mod; /* Module Python-GObject */ /** * Les extensions Python sont chargées à partir de la fonction load_python_plugins(), * qui fait appel à create_python_plugin(). Une instance y est construite via un * appel à PyObject_CallFunction() avec la classe spécifiée par l'alias AutoLoad * dans le fichier __init__.py présent dans chaque module d'extension. * * Le constructeur py_plugin_module_new() renvoie in fine à la fonction générique * python_abstract_constructor_with_dynamic_gtype(), laquelle conduit à la fonction * pygobject_register_class() définie dans /gi/pygobject-object.c. * Le code de cette dernière comprend notamment la portion suivante : * * [...] * Py_SET_TYPE(type, PyGObject_MetaType); * [...] * if (PyType_Ready(type) < 0) { * g_warning ("couldn't make the type `%s' ready", type->tp_name); * return; * } * [...] * * La fonction PyType_Ready() est définie dans /Objects/typeobject.c * et commence par : * * int PyType_Ready(PyTypeObject *type) * { * if (type->tp_flags & Py_TPFLAGS_READY) { * assert(_PyType_CheckConsistency(type)); * return 0; * } * [...] * } * * La vérification de cohérencce commence par analyser le type et son propre * type : * * - cf. _PyType_CheckConsistency() dans /Objects/typeobject.c : * * int _PyType_CheckConsistency(PyTypeObject *type) * { * [...] * CHECK(!_PyObject_IsFreed((PyObject *)type)); * [...] * } * * - cf. _PyObject_IsFreed() dans /Objects/object.c : * * int _PyObject_IsFreed(PyObject *op) * { * if (_PyMem_IsPtrFreed(op) || _PyMem_IsPtrFreed(Py_TYPE(op))) { * return 1; * } * * La fonction _PyMem_IsPtrFreed() recherche entre autres la valeur NULL. * * Or le type du type est écrasé dans la fonction pygobject_register_class() * avec la valeur de la variable PyGObject_MetaType. Cette variable n'est * définie qu'à un seul endroit, dans /gi/gimodule.c : * * static PyObject * * pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) * { * Py_INCREF(metaclass); * PyGObject_MetaType = metaclass; * Py_INCREF(metaclass); * * Py_SET_TYPE(&PyGObject_Type, metaclass); * * Py_INCREF(Py_None); * return Py_None; * } * * Afin de valider la vérification de _PyType_CheckConsistency() pour les * modules externes qui entraînent un enregistrement tout en portant le drapeau * Py_TPFLAGS_READY (typiquement ceux du répertoire "plugins/python/", il faut * initialiser au besoin la variable PyGObject_MetaType. * * Une ligne suffit donc à enregistrer le type intermédiaire : * * from _gi import types * * On simule ici une déclaration similaire si nécessaire, selon la valeur * portée par PyGObject_Type.ob_base.ob_base.ob_type.tp_name : * - "type" (PyType_Type) : état initial ; * - "_GObjectMetaBase" : état revu. */ /** * PyGObject_Type.ob_base.ob_base.ob_type != &PyType_Type ? */ result = (PyType_CheckExact(&PyGObject_Type) == 0); if (!result) { gi_types_mod = PyImport_ImportModule("gi.types"); result = (PyErr_Occurred() == NULL); if (result) result = (PyType_CheckExact(&PyGObject_Type) == 0); Py_XDECREF(gi_types_mod); } #ifndef NDEBUG if (result) assert(strcmp(PyGObject_Type.ob_base.ob_base.ob_type->tp_name, "_GObjectMetaBase") == 0); #endif if (!result) PyErr_SetString(PyExc_SystemError, "unable to install metaclass for Python GObjects."); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Met en place un environnement pour l'extension Python. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool setup_python_context(void) { bool result; /* Bilan à retourner */ result = false; /** * Un message d'erreur doit être défini en cas d'échec de l'initialisation, * via un appel à PyErr_SetString(). */ if (!is_current_abi_suitable()) goto exit; if (pygobject_init(-1, -1, -1) == NULL) { PyErr_SetString(PyExc_SystemError, "unable to init GObject in Python."); goto exit; } if (!install_metaclass_for_python_gobjects()) goto exit; result = true; exit: return result; } /****************************************************************************** * * * Paramètres : namespace = module particulier à charger à partir de gi. * * version = idenfiant de la version à stipuler. * * * * Description : Charge un module GI dans Python avec une version attendue. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool import_namespace_from_gi_repository(const char *namespace, const char *version) { bool result; /* Bilan à retourner */ PyObject *module; /* Module Python-GObject */ PyObject *args; /* Arguments à fournir */ int ret; /* Bilan d'une mise en place */ result = false; /* Sélection d'une version */ module = PyImport_ImportModule("gi"); if (module != NULL) { args = Py_BuildValue("ss", namespace, version); run_python_method(module, "require_version", args); result = (PyErr_Occurred() == NULL); Py_DECREF(args); Py_DECREF(module); } /* Importation du module visé */ if (result) { args = PyTuple_New(1); ret = PyTuple_SetItem(args, 0, PyUnicode_FromString(namespace)); if (ret != 0) { result = false; goto args_error; } module = PyImport_ImportModuleEx("gi.repository", NULL, NULL, args); result = (module != NULL); Py_XDECREF(module); args_error: Py_DECREF(args); } // TODO : message d'erreur ? return result; } /****************************************************************************** * * * Paramètres : py_gobj_def = définition de type actuelle. [OUT] * * * * Description : Assure la définition d'un type GObject pour Python adapté. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void ensure_native_pygobject_type(PyTypeObject **py_gobj_def) { GQuark pygobject_class_key; /* Copie d'un accès GI interne */ /** * Les appels suivants procèdent à l'enregistrement de différents éléments * dans l'espace de noms Python pour Chrysalide. * * Une majeure partie de ces éléments est constituée d'objets dérivés de * GObject. Ce type d'objet (G_TYPE_OBJECT) est représenté par deux types * en Python : * * - gi._gi.GObject, mis en place lors de l'importation du module gi. * * Ce dernier lance automatiquement l'importation du module natif gi._gi, * lequel, via son initialisation dans la fonction PyInit__gi() * (cf. ./gi/gimodule.c) lance un appel à pyi_object_register_types() * qui procède à l'enregistrement du type "GObject" porté par la structure * PyGObject_Type en correspondance au type GLib G_TYPE_OBJECT (cf. appel * à pygobject_register_class() dans gi/pygobject-object.c). * * - gi.repository.GObject.Object, qui vient surclasser le type précédent * lors d'un appel d'initialisation : from gi.repository import GObject. * * Cette seconde définition est destinée à apporter une représentation * de l'introspection GObject de plus haut niveau pour l'utilisateur par * rapport à celle de bas niveau gi._gi. * * Il demeure que la seconde définition est entièrement implémentée en Python * et porte ainsi le fanion Py_TPFLAGS_HEAPTYPE, imposant cette même dernière * propriétée à tous les objets qui en dérivent. * * Les définitions de Chrysalide sont cependant toutes statiques et donc * incompatibles avec une définition gi.repository.GObject.Object, comme le * pointent les validations opérées par PyType_Ready(). * * Une solution consiste ici à restaurer au besoin la définition gi._gi.GObject * brute, effectuer les enregistrements de Chrysalide sur cette base, et * remettre en place la définition éventuellement remplacée ensuite. */ *py_gobj_def = pygobject_lookup_class(G_TYPE_OBJECT); if (*py_gobj_def != &PyGObject_Type) { Py_INCREF((PyObject *)*py_gobj_def); /* Définition récupérée de pyi_object_register_types() */ pygobject_class_key = g_quark_from_static_string("PyGObject::class"); g_type_set_qdata(G_TYPE_OBJECT, pygobject_class_key, &PyGObject_Type); } } /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit la référence à un éventuel module déjà en place. * * * * Retour : Pointeur vers le module mis en place. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *get_existing_modules(void) { PyObject *result; /* Module Python à retourner */ /** * Vérification préalable : dans le cas où on est embarqué directement dans * un interpréteur Python, le module se charge et termine par charger à leur * tour les différentes extensions trouvées, via load_remaning_plugins() puis * chrysalide_plugin_on_native_loaded(). * * Lesquelles vont très probablement charger le module pychrysalide. * * Comme le chargement de ce dernier n'est alors pas encore terminé, * Python va relancer cette procédure, et register_access_to_python_module() * va détecter un doublon. */ result = get_access_to_python_module(PYCHRYSALIDE_NAME); Py_XINCREF(result); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Définit les différents modules du support Python. * * * * Retour : Pointeur vers le module mis en place. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *create_basic_modules(void) { PyObject *result; /* Module Python à retourner */ bool status; /* Bilan des inclusions */ static PyMethodDef py_chrysalide_methods[] = { PY_CHRYSALIDE_REVISION_METHOD, PY_CHRYSALIDE_VERSION_METHOD, PY_CHRYSALIDE_MOD_VERSION_METHOD, { NULL } }; static PyModuleDef py_chrysalide_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = PYCHRYSALIDE_NAME, .m_doc = PYCHRYSALIDE_DOC, .m_size = -1, .m_methods = py_chrysalide_methods }; result = PyModule_Create(&py_chrysalide_module); register_access_to_python_module(py_chrysalide_module.m_name, result); status = true; /** * Réceptacle pour objets et constantes : à laisser en premier ajout donc. */ if (status) status = add_features_module(result); if (status) status = define_data_types_constants(result); if (status) status = add_analysis_module(result); if (status) status = add_arch_module(result); if (status) status = add_common_module(result); if (status) status = add_glibext_module(result); if (status) status = add_core_module(result); /* if (status) status = add_debug_module(result); */ if (status) status = add_format_module(result); /* #ifdef INCLUDE_GTK_SUPPORT if (status) status = add_gtkext_module(result); if (status) status = add_gui_module(result); #endif if (status) status = add_mangling_module(result); */ if (status) status = add_plugins_module(result); if (!status) { Py_DECREF(result); result = NULL; } return result; } /****************************************************************************** * * * Paramètres : details = précisions de chargement complémentaires. * * * * Description : Inscrit les défintions des objets Python de Chrysalide. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool populate_python_modules(const pyinit_details_t *details) { bool result; /* Bilan à retourner */ /** * Les chargements de types supplémentaires, apportés par la version UI, ne * peuvent être forcés depuis les mises en places des versions non-UI via * les classiques appels ensure_xxx(). * * L'assurance d'un chargement préalable est ainsi réalisée ici, via * un chargement préliminaire, si besoin est. */ if (details->populate_extra) result = details->populate_extra(); else result = true; /* if (result) result = ensure_python_string_enum_is_registered(); */ if (result) result = ensure_python_py_struct_is_registered(); if (result) result = populate_analysis_module(); if (result) result = populate_arch_module(); if (result) result = populate_glibext_module(); if (result) result = populate_common_module(); if (result) result = populate_core_module(); /* if (result) result = populate_debug_module(); */ if (result) result = populate_format_module(); /* #ifdef INCLUDE_GTK_SUPPORT if (result) result = populate_gtkext_module(); if (result) result = populate_gui_module(); #endif if (result) result = populate_mangling_module(); */ if (result) result = populate_plugins_module(); return result; } /****************************************************************************** * * * Paramètres : py_gobj_def = définition de type actuelle. [OUT] * * * * Description : Restore une ancienne définition de type GObject au besoin. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void restore_original_pygobject_type(PyTypeObject *py_gobj_def) { GQuark pygobject_class_key; /* Copie d'un accès GI interne */ if (py_gobj_def != &PyGObject_Type) { /* Définition récupérée de pyi_object_register_types() */ pygobject_class_key = g_quark_from_static_string("PyGObject::class"); g_type_set_qdata(G_TYPE_OBJECT, pygobject_class_key, py_gobj_def); Py_DECREF((PyObject *)py_gobj_def); } } /****************************************************************************** * * * Paramètres : details = précisions de chargement complémentaires. * * * * Description : Implémente le point d'entrée pour l'initialisation de Python.* * * * Retour : Module mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details) { PyObject *result; /* Module Python à retourner */ PyTypeObject *py_gobj_def; /* Définition GObject courante */ bool status; /* Bilan des inclusions */ result = get_existing_modules(); if (result != NULL) return result; if (!setup_python_context()) goto exit; /** * Le chargement forcé de l'espace GLib pour Python permet d'éviter un écueil, * à savoir des types convertis de façon incomplète. Par exemple, pour une * structure GChecksum, le type à l'exécution est : * * - sans module GLib : [, ] * * - avec module GLib : [, , , ] * * Par ailleurs, il est à noter que le message suivant n'apparaît qu'avec * la version debug de Python3 (version de python3-gi : 3.42.2-3) : * * :673: ImportWarning: DynamicImporter.exec_module() not found; falling back to load_module() * * Code de reproduction dans un interpréteur classique : * * import gi * gi.require_version('GLib', '2.0') * from gi.repository import GLib * */ if (!import_namespace_from_gi_repository("GLib", "2.0")) goto exit; /* Mise en place des fonctionnalités offertes */ ensure_native_pygobject_type(&py_gobj_def); result = create_basic_modules(); if (result == NULL) PyErr_SetString(PyExc_SystemError, "failed to create all PyChrysalide modules."); else { status = populate_python_modules(details); if (!status) PyErr_SetString(PyExc_SystemError, "failed to load all PyChrysalide components."); else if (details->standalone) status = do_global_init(); if (!status) { Py_DECREF(result); result = NULL; } } restore_original_pygobject_type(py_gobj_def); exit: if (result == NULL && !details->standalone) /*log_pychrysalide_exception("Loading failed")*/; return result; } /* ---------------------------------------------------------------------------------- */ /* FONCTIONS GLOBALES DE CHRYSALIDE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : py_gobj_def = définition de type actuelle. [OUT] * * * * Description : Restore une ancienne définition de type GObject au besoin. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool do_global_init(void) { return true; return false; #if 0 bool result; /* Bilan à retourner */ int ret; /* Bilan de préparatifs */ #ifdef PYTHON_PACKAGE Dl_info info; /* Informations dynamiques */ #endif GPluginModule *self; /* Représentation interne */ PluginStatusFlags self_flags; /* Fanions à mettre à jour */ ret = Py_AtExit(PyExit_pychrysalide); if (ret == -1) { PyErr_SetString(PyExc_SystemError, "failed to register a cleanup function."); goto exit_and_restore; } /** * Si cette extension pour Python est chargée depuis un dépôt Python, * elle ne se trouve pas dans le répertoire classique des extensions et * n'est donc pas chargée et enregistrée comme attendu. * * Cet enregistrement est donc forcé ici. */ #ifdef PYTHON_PACKAGE ret = dladdr(__FUNCTION__, &info); if (ret == 0) { LOG_ERROR_DL_N("dladdr"); // err msg Py_DECREF(result); result = NULL; goto exit_and_restore; } self = g_plugin_module_new(info.dli_fname); assert(self != NULL); register_plugin(self); #endif if (!load_core_components(ACC_GLOBAL_VARS)) { PyErr_SetString(PyExc_SystemError, "unable to load core components."); goto exit; } init_all_plugins(false); lock_plugin_list_for_reading(); self = get_plugin_by_name("PyChrysalide", NULL); assert(self != NULL); self_flags = g_plugin_module_get_flags(self); self_flags &= ~(PSF_FAILURE | PSF_LOADED); self_flags |= (status ? PSF_LOADED : PSF_FAILURE); g_plugin_module_override_flags(self, self_flags); unref_object(self); unlock_plugin_list_for_reading(); load_remaning_plugins(); done: return result; #endif } /****************************************************************************** * * * Paramètres : - * * * * Description : Point de sortie pour l'initialisation de Python. * * * * Retour : ? * * * * Remarques : - * * * ******************************************************************************/ static void PyExit_pychrysalide(void) { //assert(_standalone); /* extern void set_current_project(void *project); set_current_project(NULL); */ #ifdef TRACK_GOBJECT_LEAKS remember_gtypes_for_leaks(); #endif exit_all_plugins(); //unload_all_core_components(true); #ifdef TRACK_GOBJECT_LEAKS dump_remaining_gtypes(); #endif }