From baa854bfcc969022a00617b58a661e37f345cab5 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 12 Jan 2025 15:23:01 +0100
Subject: Rewrite the plugin system.

---
 plugins/pe/core-int.h                     |   56 ++
 plugins/pe/core.c                         |  280 +++++-
 plugins/pe/core.h                         |   14 +-
 plugins/pychrysalide/Makefile.am          |   22 +-
 plugins/pychrysalide/bindings.c           | 1090 +++++++++++++++++++++
 plugins/pychrysalide/bindings.h           |   68 ++
 plugins/pychrysalide/core-int.h           |   58 ++
 plugins/pychrysalide/core-ui-int.h        |   56 ++
 plugins/pychrysalide/core-ui.c            |  318 +++++++
 plugins/pychrysalide/core-ui.h            |   64 ++
 plugins/pychrysalide/core.c               | 1469 +++++++++--------------------
 plugins/pychrysalide/core.h               |   30 +-
 plugins/pychrysalide/helpers.c            |  150 +++
 plugins/pychrysalide/helpers.h            |   38 +
 plugins/pychrysalide/plugins/Makefile.am  |    4 +-
 plugins/pychrysalide/plugins/module.c     |   11 +-
 plugins/pychrysalide/plugins/plugin.c     |  958 ++++++++-----------
 plugins/pychrysalide/plugins/plugin.h     |    7 -
 plugins/pychrysalide/plugins/python-int.h |   58 ++
 plugins/pychrysalide/plugins/python.c     |  489 ++++++++++
 plugins/pychrysalide/plugins/python.h     |   57 ++
 src/common/compiler.h                     |   16 +-
 src/common/cpp.h                          |    8 +-
 src/plugins/Makefile.am                   |   16 +-
 src/plugins/dt.c                          |    2 +-
 src/plugins/manager-int.h                 |   54 ++
 src/plugins/manager.c                     |  113 +++
 src/plugins/manager.h                     |   61 ++
 src/plugins/native-int.h                  |   62 ++
 src/plugins/native.c                      |  278 ++++++
 src/plugins/native.h                      |   39 +
 src/plugins/pglist.c                      |  355 ++++---
 src/plugins/pglist.h                      |   63 +-
 src/plugins/plugin-def.h                  |   16 +-
 src/plugins/plugin-int.h                  |   88 +-
 src/plugins/plugin.c                      |  970 ++++---------------
 src/plugins/plugin.h                      |   41 +-
 src/plugins/self.h                        |   99 +-
 tests/plugins/plugin.py                   |  219 +----
 tests/plugins/python.py                   |   27 +
 40 files changed, 4995 insertions(+), 2829 deletions(-)
 create mode 100644 plugins/pe/core-int.h
 create mode 100644 plugins/pychrysalide/bindings.c
 create mode 100644 plugins/pychrysalide/bindings.h
 create mode 100644 plugins/pychrysalide/core-int.h
 create mode 100644 plugins/pychrysalide/core-ui-int.h
 create mode 100644 plugins/pychrysalide/core-ui.c
 create mode 100644 plugins/pychrysalide/core-ui.h
 create mode 100644 plugins/pychrysalide/plugins/python-int.h
 create mode 100644 plugins/pychrysalide/plugins/python.c
 create mode 100644 plugins/pychrysalide/plugins/python.h
 create mode 100644 src/plugins/manager-int.h
 create mode 100644 src/plugins/manager.c
 create mode 100644 src/plugins/manager.h
 create mode 100644 src/plugins/native-int.h
 create mode 100644 src/plugins/native.c
 create mode 100644 src/plugins/native.h
 create mode 100644 tests/plugins/python.py

diff --git a/plugins/pe/core-int.h b/plugins/pe/core-int.h
new file mode 100644
index 0000000..1d1b817
--- /dev/null
+++ b/plugins/pe/core-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-int.h - prototypes internes pour l'intégration du support du format PE
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_PE_CORE_INT_H
+#define _PLUGINS_PE_CORE_INT_H
+
+
+#include "core.h"
+
+
+#include <plugins/native-int.h>
+
+
+
+/* Greffon natif pour le support du format PE (instance) */
+struct _GPePlugin
+{
+    GNativePlugin parent;                   /* A laisser en premier        */
+
+};
+
+
+/* Greffon natif pour le support du format PE (classe) */
+struct _GPePluginClass
+{
+    GNativePluginClass parent;              /* A laisser en premier        */
+
+};
+
+
+/* Met en place un module pour un greffon de support PE. */
+bool g_pe_plugin_create(GPePlugin *, GModule *);
+
+
+
+#endif  /* _PLUGINS_PE_CORE_INT_H */
diff --git a/plugins/pe/core.c b/plugins/pe/core.c
index e8e6f5e..42f712d 100644
--- a/plugins/pe/core.c
+++ b/plugins/pe/core.c
@@ -24,35 +24,244 @@
 #include "core.h"
 
 
-#include <core/global.h>
+//#include <core/global.h>
 #include <plugins/self.h>
 
 
+#include "core-int.h"
 #include "format.h"
 #ifdef INCLUDE_PYTHON3_BINDINGS
 #   include "python/module.h"
 #endif
 
 
+
+/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
+
+
+/* Initialise la classe des greffons de support PE. */
+static void g_pe_plugin_class_init(GPePluginClass *);
+
+/* Procède à l'initialisation de l'interface de gestion. */
+//static void g_pe_plugin_plugin_manager_interface_init(GPluginManagerInterface *);
+
+/* Initialise une instance de greffon de support PE. */
+static void g_pe_plugin_init(GPePlugin *);
+
+/* Supprime toutes les références externes. */
+static void g_pe_plugin_dispose(GPePlugin *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_pe_plugin_finalize(GPePlugin *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte de l'activation du greffon. */
+static bool g_pe_plugin_enable(GPePlugin *);
+
+/* Prend acte de l'extinction du greffon. */
+static void g_pe_plugin_disable(GPePlugin *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        COMPOSITION DE NOUVEAU GREFFON NATIF                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un greffon de liaison Python */
+G_DEFINE_TYPE_WITH_CODE(GPePlugin, g_pe_plugin, G_TYPE_NATIVE_PLUGIN,
+                        /*G_IMPLEMENT_INTERFACE(G_TYPE_PLUGIN_MANAGER, g_pe_plugin_plugin_manager_interface_init)*/);
+
+
+NATIVE_PLUGIN_ENTRYPOINT(g_pe_plugin_new);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des greffons de support PE.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_class_init(GPePluginClass *class)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GPluginModuleClass *plugin;             /* Version parente de la classe*/
+
+    object = G_OBJECT_CLASS(class);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_pe_plugin_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_pe_plugin_finalize;
+
+    plugin = G_PLUGIN_MODULE_CLASS(class);
+
+    plugin->enable = (pg_management_fc)g_pe_plugin_enable;
+    plugin->disable = (pg_management_fc)g_pe_plugin_disable;
+
+}
+
+#if 0
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
+*                                                                             *
+*  Description : Procède à l'initialisation de l'interface de gestion.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_plugin_manager_interface_init(GPluginManagerInterface *iface)
+{
+    iface->handle_native = (handle_native_plugins_cb)g_pe_plugin_handle_native_plugins_loaded_event;
+
+}
+
+#endif
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de greffon de support PE.            *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_init(GPePlugin *plugin)
+{
+    STORE_PLUGIN_ABI(plugin);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_dispose(GPePlugin *plugin)
+{
+    G_OBJECT_CLASS(g_pe_plugin_parent_class)->dispose(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_finalize(GPePlugin *plugin)
+{
+    G_OBJECT_CLASS(g_pe_plugin_parent_class)->finalize(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = nom du fichier à charger.                         *
+*                                                                             *
+*  Description : Crée un module pour un greffon de support PE.                *
+*                                                                             *
+*  Retour      : Adresse de la structure mise en place.                       *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
+
+GPluginModule *g_pe_plugin_new(GModule *module)
+{
+    GPePlugin *result;                      /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_PE_PLUGIN, NULL);
+
+    if (!g_pe_plugin_create(result, module))
+        g_clear_object(&result);
+
+    return G_PLUGIN_MODULE(result);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser pleinement.                  *
+*                module = module système correspondant.                       *
+*                                                                             *
+*  Description : Met en place un module pour un greffon de support PE.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
+
+bool g_pe_plugin_create(GPePlugin *plugin, GModule *module)
+{
+    bool result;                            /* Bilan à retourner           */
+
 #ifdef INCLUDE_PYTHON3_BINDINGS
-#   define PG_REQ RL("PyChrysalide")
+#   define PG_REQ REQ_LIST("PyChrysalide")
 #else
 #   define PG_REQ NO_REQ
 #endif
 
+    result = g_native_plugin_create(G_NATIVE_PLUGIN(plugin),
+                                    "PeFmt",
+                                    "PE format support",
+                                    PACKAGE_VERSION,
+                                    CHRYSALIDE_WEBSITE("doc/formats"),
+                                    PG_REQ,
+                                    module);
 
+    return result;
+
+}
 
-DEFINE_CHRYSALIDE_PLUGIN("Pe", "PE format support",
-                         PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/formats"),
-                         PG_REQ, AL(PGA_PLUGIN_INIT));//, PGA_CONTENT_RESOLVER));
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
 
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : plugin = greffon à manipuler.                                *
 *                                                                             *
-*  Description : Prend acte du chargement du greffon.                         *
+*  Description : Prend acte de l'activation du greffon.                       *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -60,7 +269,7 @@ DEFINE_CHRYSALIDE_PLUGIN("Pe", "PE format support",
 *                                                                             *
 ******************************************************************************/
 
-G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+static bool g_pe_plugin_enable(GPePlugin *plugin)
 {
     bool result;                            /* Bilan à retourner           */
 
@@ -77,6 +286,60 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Prend acte de l'extinction du greffon.                       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_disable(GPePlugin *plugin)
+{
+
+}
+
+
+
+#if 0
+
+/* ---------------------------------------------------------------------------------- */
+/*                      INTERVENTION DANS LA GESTION DE GREFFONS                      */
+/*                      INTERVENTION DANS LA GESTION DE GREFFONS                      */
+/*                      INTERVENTION DANS LA GESTION DE GREFFONS                      */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = interface à manipuler.                              *
+*                                                                             *
+*  Description : Accompagne la fin du chargement des modules natifs.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pe_plugin_handle_native_plugins_loaded_event(GPePlugin *plugin)
+{
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+
+    gstate = PyGILState_Ensure();
+
+    load_python_plugins(G_PLUGIN_MODULE(plugin));
+
+    PyGILState_Release(gstate);
+
+}
+
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : plugin  = greffon à manipuler.                               *
 *                action  = type d'action attendue.                            *
 *                content = contenu binaire à traiter.                         *
@@ -115,3 +378,6 @@ G_MODULE_EXPORT void chrysalide_plugin_handle_binary_content(const GPluginModule
 
 }
 #endif
+
+
+#endif
diff --git a/plugins/pe/core.h b/plugins/pe/core.h
index 2d9aeb5..5c0696f 100644
--- a/plugins/pe/core.h
+++ b/plugins/pe/core.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * core.h - prototypes pour l'intégration du support du format PE
  *
- * Copyright (C) 2017-2018 Cyrille Bagard
+ * Copyright (C) 2017-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -25,16 +25,18 @@
 #define _PLUGINS_PE_CORE_H
 
 
+#include <glibext/helpers.h>
 #include <plugins/plugin.h>
-#include <plugins/plugin-int.h>
 
 
 
-/* Prend acte du chargement du greffon. */
-G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+#define G_TYPE_PE_PLUGIN (g_pe_plugin_get_type())
 
-/* Procède à une opération liée à un contenu binaire. */
-//G_MODULE_EXPORT void chrysalide_plugin_handle_binary_content(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *);
+DECLARE_GTYPE(GPePlugin, g_pe_plugin, G, PE_PLUGIN);
+
+
+/* Crée un module pour un greffon de support PE. */
+GPluginModule *g_pe_plugin_new(GModule *);
 
 
 
diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index 183a4ef..7b1a331 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -1,7 +1,7 @@
 
 DEFAULT_INCLUDES = -I$(top_builddir) -idirafter.
 
-lib_LTLIBRARIES = pychrysalide.la
+lib_LTLIBRARIES = pychrysalide.la pychrysalideui.la
 
 libdir = $(pluginslibdir)
 
@@ -32,7 +32,9 @@ endif
 
 pychrysalide_la_SOURCES =					\
 	access.h access.c						\
+	bindings.h bindings.c					\
 	constants.h constants.c					\
+	core-int.h								\
 	core.h core.c							\
 	helpers.h helpers.c						\
 	star.h star.c							\
@@ -71,6 +73,24 @@ pychrysalide_la_LDFLAGS =					\
 	$(RUN_PATH)
 
 
+EXTRA_pychrysalideui_la_DEPENDENCIES = pychrysalide.la
+
+pychrysalideui_la_SOURCES =					\
+	core-ui-int.h							\
+	core-ui.h core-ui.c
+
+pychrysalideui_la_LIBADD =
+
+# -ldl: dladdr(), dlerror()
+pychrysalideui_la_LDFLAGS =					\
+	-module -avoid-version -ldl				\
+	$(LIBPYTHON_INTERPRETER_LIBS)			\
+	$(LIBPYGOBJECT_LIBS)					\
+	-L.libs -l:pychrysalide.so				\
+	-L$(top_srcdir)/src/.libs -lchrysacoreui\
+	$(RUN_PATH)
+
+
 devdir = $(includedir)/chrysalide/$(subdir)
 
 dev_HEADERS = $(pychrysalide_la_SOURCES:%c=)
diff --git a/plugins/pychrysalide/bindings.c b/plugins/pychrysalide/bindings.c
new file mode 100644
index 0000000..295667f
--- /dev/null
+++ b/plugins/pychrysalide/bindings.c
@@ -0,0 +1,1090 @@
+
+/* 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 <dlfcn.h>
+#endif
+#include <pygobject.h>
+#include <stdio.h>
+
+
+#include <config.h>
+#include <common/cpp.h>
+#include <plugins/pglist.h> // REMME ?
+#include <plugins/self.h> // 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 <python3-gi>/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 <python3>/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 <python3>/Objects/typeobject.c :
+     *
+     *    int _PyType_CheckConsistency(PyTypeObject *type)
+     *    {
+     *        [...]
+     *        CHECK(!_PyObject_IsFreed((PyObject *)type));
+     *        [...]
+     *    }
+     *
+     *  - cf. _PyObject_IsFreed() dans <python3>/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 <python3-gi>/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 : [<class 'gobject.GBoxed'>, <class 'object'>]
+     *
+     *    - avec module GLib : [<class 'gi.repository.GLib.Checksum'>, <class 'gi.Boxed'>, <class 'gobject.GBoxed'>, <class 'object'>]
+     *
+     * 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) :
+     *
+     *    <frozen importlib._bootstrap>: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
+
+}
diff --git a/plugins/pychrysalide/bindings.h b/plugins/pychrysalide/bindings.h
new file mode 100644
index 0000000..1c63956
--- /dev/null
+++ b/plugins/pychrysalide/bindings.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bindings.h - prototypes pour les é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
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_BINDINGS_H
+#define _PLUGINS_PYCHRYSALIDE_BINDINGS_H
+
+
+/**
+ * Note:
+ * Since Python may define some pre-processor definitions which affect the standard headers
+ * on some systems, you must include Python.h before any standard headers are included.
+ *
+ * cf. https://docs.python.org/3.4/c-api/intro.html
+ */
+#include <Python.h>
+
+
+#include <stdbool.h>
+
+
+
+/* Charge un module GI dans Python avec une version attendue. */
+bool import_namespace_from_gi_repository(const char *, const char *);
+
+/* Raffinements pour la mise en place du module Python */
+typedef struct _pyinit_details_t
+{
+    bool standalone;                        /* Chargement depuis Python ?  */
+
+
+    bool (* populate_extra) (void);         /* Ajout de types ?            */
+
+
+} pyinit_details_t;
+
+/* Implémente le point d'entrée pour l'initialisation de Python. */
+PyObject *init_python_pychrysalide_module(const pyinit_details_t *);
+
+
+
+
+
+bool do_global_init(void);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_BINDINGS_H */
diff --git a/plugins/pychrysalide/core-int.h b/plugins/pychrysalide/core-int.h
new file mode 100644
index 0000000..2b8fcc8
--- /dev/null
+++ b/plugins/pychrysalide/core-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-int.h - prototypes internes pour le plugin permettant des extensions en Python
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_CORE_INT_H
+#define _PLUGINS_PYCHRYSALIDE_CORE_INT_H
+
+
+#include "core.h"
+
+
+#include <plugins/native-int.h>
+
+
+
+/* Greffon natif pour la liaison Python de Chrysalide (instance) */
+struct _GPyChrysalidePlugin
+{
+    GNativePlugin parent;                   /* A laisser en premier        */
+
+    PyObject *py_module;                    /* Réceptacle de chargement    */
+
+};
+
+
+/* Greffon natif pour la liaison Python de Chrysalide (classe) */
+struct _GPyChrysalidePluginClass
+{
+    GNativePluginClass parent;              /* A laisser en premier        */
+
+};
+
+
+/* Met en place un module pour un greffon de support Python. */
+bool g_pychrysalide_plugin_create(GPyChrysalidePlugin *, GModule *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_CORE_INT_H */
diff --git a/plugins/pychrysalide/core-ui-int.h b/plugins/pychrysalide/core-ui-int.h
new file mode 100644
index 0000000..7cecc13
--- /dev/null
+++ b/plugins/pychrysalide/core-ui-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-ui-int.h - prototypes internes pour le plugin permettant des extensions UI en Python
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_CORE_UI_INT_H
+#define _PLUGINS_PYCHRYSALIDE_CORE_UI_INT_H
+
+
+#include "core-ui.h"
+
+
+#include "core-int.h"
+
+
+
+/* Greffon natif pour la liaison Python de Chrysalide sous forme graphique (instance) */
+struct _GPyChrysalidePluginUI
+{
+    GPyChrysalidePlugin parent;             /* A laisser en premier        */
+
+};
+
+
+/* Greffon natif pour la liaison Python de Chrysalide sous forme graphique (classe) */
+struct _GPyChrysalidePluginUIClass
+{
+    GPyChrysalidePluginClass parent;        /* A laisser en premier        */
+
+};
+
+
+/* Met en place un module pour un greffon de support Python. */
+bool g_pychrysalide_plugin_ui_create(GPyChrysalidePluginUI *, GModule *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_CORE_UI_INT_H */
diff --git a/plugins/pychrysalide/core-ui.c b/plugins/pychrysalide/core-ui.c
new file mode 100644
index 0000000..32d3516
--- /dev/null
+++ b/plugins/pychrysalide/core-ui.c
@@ -0,0 +1,318 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-ui.c - plugin permettant des extensions UI en Python
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core-ui.h"
+
+
+#include <stdbool.h>
+
+
+#include <i18n.h>
+#include <plugins/self.h>
+
+
+#include "bindings.h"
+#include "core-ui-int.h"
+
+
+
+/* Note la nature du chargement */
+static bool _standalone = true;
+
+
+
+/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
+
+
+/* Initialise la classe des greffons de support Python. */
+static void g_pychrysalide_plugin_ui_class_init(GPyChrysalidePluginUIClass *);
+
+/* Initialise une instance de greffon de support Python. */
+static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *);
+
+/* Supprime toutes les références externes. */
+static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte de l'activation du greffon. */
+static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        COMPOSITION DE NOUVEAU GREFFON NATIF                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un greffon de liaison Python */
+G_DEFINE_TYPE(GPyChrysalidePluginUI, g_pychrysalide_plugin_ui, G_TYPE_PYCHRYSALIDE_PLUGIN);
+
+
+NATIVE_PLUGIN_ENTRYPOINT(g_pychrysalide_plugin_ui_new);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des greffons de support Python.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pychrysalide_plugin_ui_class_init(GPyChrysalidePluginUIClass *class)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GPluginModuleClass *plugin;             /* Version parente de la classe*/
+
+    object = G_OBJECT_CLASS(class);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_pychrysalide_plugin_ui_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_pychrysalide_plugin_ui_finalize;
+
+    plugin = G_PLUGIN_MODULE_CLASS(class);
+
+    plugin->enable = (pg_management_fc)g_pychrysalide_plugin_ui_enable;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de greffon de support Python.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *plugin)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *plugin)
+{
+    G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->dispose(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *plugin)
+{
+    G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->finalize(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = nom du fichier à charger.                         *
+*                                                                             *
+*  Description : Crée un module pour un greffon de support Python.            *
+*                                                                             *
+*  Retour      : Adresse de la structure mise en place.                       *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
+
+GPluginModule *g_pychrysalide_plugin_ui_new(GModule *module)
+{
+    GPyChrysalidePluginUI *result;          /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_PYCHRYSALIDE_PLUGIN, NULL);
+
+    if (!g_pychrysalide_plugin_ui_create(result, module))
+        g_clear_object(&result);
+
+    return G_PLUGIN_MODULE(result);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser pleinement.                  *
+*                module = module système correspondant.                       *
+*                                                                             *
+*  Description : Met en place un module pour un greffon de support Python.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
+
+bool g_pychrysalide_plugin_ui_create(GPyChrysalidePluginUI *plugin, GModule *module)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = g_pychrysalide_plugin_create(G_PYCHRYSALIDE_PLUGIN(plugin), module);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Prend acte de l'activation du greffon.                       *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    int ret;                                /* Bilan de préparatifs        */
+
+    _standalone = false;
+
+    /* Chargement du module pour Python */
+
+    ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalideui);
+
+    if (ret == -1)
+    {
+        g_plugin_module_log_simple_message(G_PLUGIN_MODULE(plugin),
+                                           LMT_ERROR,
+                                           _("Can not extend the existing table of Python built-in modules."));
+
+        result = false;
+        goto done;
+
+    }
+
+    Py_Initialize();
+
+    gstate = PyGILState_Ensure();
+
+    G_PYCHRYSALIDE_PLUGIN(plugin)->py_module = PyImport_ImportModule("pychrysalide");
+
+    /**
+     * Pour mémoire, une situation concrête conduisant à un échec :
+     * le paquet python3-gi-dbg n'est pas installé alors que le
+     * programme est compilé en mode débogage.
+     *
+     * Dans ce cas, pygobject_init(-1, -1, -1) échoue, et Py_Initialize()
+     * le laisse rien filtrer...
+     *
+     * En mode autonome, le shell Python remonte bien l'erreur par contre.
+     */
+
+    // TODO : check (2025)
+
+    result = (G_PYCHRYSALIDE_PLUGIN(plugin)->py_module != NULL);
+
+    PyGILState_Release(gstate);
+
+ done:
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                             POINT D'ENTREE POUR PYTHON                             */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Point d'entrée pour l'initialisation de Python.              *
+*                                                                             *
+*  Retour      : ?                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyMODINIT_FUNC PyInit_pychrysalideui(void)
+{
+    PyObject *result;                       /* Module Python à retourner   */
+    pyinit_details_t details;               /* Détails de chargement       */
+
+    details.standalone = _standalone;
+
+    details.populate_extra = NULL;
+
+    result = init_python_pychrysalide_module(&details);
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/core-ui.h b/plugins/pychrysalide/core-ui.h
new file mode 100644
index 0000000..658aa19
--- /dev/null
+++ b/plugins/pychrysalide/core-ui.h
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core-ui.h - prototypes pour le plugin permettant des extensions UI en Python
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_CORE_UI_H
+#define _PLUGINS_PYCHRYSALIDE_CORE_UI_H
+
+
+/**
+ * Note:
+ * Since Python may define some pre-processor definitions which affect the standard headers
+ * on some systems, you must include Python.h before any standard headers are included.
+ *
+ * cf. https://docs.python.org/3.4/c-api/intro.html
+ */
+#include <Python.h>
+
+
+#include <glibext/helpers.h>
+#include <plugins/plugin.h>
+
+
+
+/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
+
+
+#define G_TYPE_PYCHRYSALIDE_PLUGIN_UI (g_pychrysalide_plugin_ui_get_type())
+
+DECLARE_GTYPE(GPyChrysalidePluginUI, g_pychrysalide_plugin_ui, G, PYCHRYSALIDE_PLUGIN_UI);
+
+
+/* Crée un module pour un greffon de support Python. */
+GPluginModule *g_pychrysalide_plugin_ui_new(GModule *);
+
+
+
+/* --------------------------- POINT D'ENTREE POUR PYTHON --------------------------- */
+
+
+/* Point d'entrée pour l'initialisation de Python. */
+PyMODINIT_FUNC PyInit_pychrysalideui(void);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_CORE_UI_H */
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index f63fd9e..e815e25 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * core.c - plugin permettant des extensions en Python
  *
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -21,6 +21,15 @@
  */
 
 
+#include "core.h"
+
+
+#include "core-int.h"
+
+
+
+
+
 #undef NO_IMPORT_PYGOBJECT
 #include <pygobject.h>
 #define NO_IMPORT_PYGOBJECT
@@ -32,9 +41,8 @@
 #include <assert.h>
 #include <errno.h>
 #include <malloc.h>
-#include <pygobject.h>
+//#include <pygobject.h>
 #include <stdarg.h>
-#include <stdio.h>
 #include <stdbool.h>
 #include <string.h>
 #include <unistd.h>
@@ -42,826 +50,568 @@
 
 #include <i18n.h>
 #include <gleak.h>
-#include <common/cpp.h>
 #include <common/environment.h>
 #include <common/extstr.h>
 #include <core/core.h>
 #include <core/logs.h>
 #include <core/paths.h>
-#include <plugins/pglist.h>
+#include <plugins/manager-int.h>
+#include <plugins/plugin.h>
 #include <plugins/self.h>
 
 
+
+
 #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"
-#include "plugins/plugin.h"
-
-
-
-DEFINE_CHRYSALIDE_CONTAINER_PLUGIN("PyChrysalide", "Chrysalide bindings to Python",
-                                   PACKAGE_VERSION, CHRYSALIDE_WEBSITE("api/python/pychrysalide"),
-                                   NO_REQ, AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT,
-                                              PGA_NATIVE_PLUGINS_LOADED, PGA_TYPE_BUILDING));
+#include "bindings.h"
+
 
 
 /* Note la nature du chargement */
 static bool _standalone = true;
 
-/* Réceptacle pour le chargement forcé */
-static PyObject *_chrysalide_module = NULL;
 
 
-/* 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 *);
 
-/* 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);
 
-/* Définit la version attendue de GTK à charger dans Python. */
-#ifdef INCLUDE_GTK_SUPPORT
-static bool set_version_for_gtk_namespace(const char *);
-#endif
 
-/* Point de sortie pour l'initialisation de Python. */
-static void PyExit_pychrysalide(void);
+
+
+/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
+
+
+/* Initialise la classe des greffons de support Python. */
+static void g_pychrysalide_plugin_class_init(GPyChrysalidePluginClass *);
+
+/* Procède à l'initialisation de l'interface de gestion. */
+static void g_pychrysalide_plugin_plugin_manager_interface_init(GPluginManagerInterface *);
+
+/* Initialise une instance de greffon de support Python. */
+static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *);
+
+/* Supprime toutes les références externes. */
+static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte de l'activation du greffon. */
+static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *);
+
+/* Prend acte de la désactivation du greffon. */
+static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *);
+
+
+
+/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
+
 
 /* Complète les chemins de recherches de Python. */
 static void extend_python_path(const char *);
 
+/* Crée un greffon à partir de code Python. */
+static GPluginModule *create_python_plugin(const char *, const char *);
+
 /* Charge autant de greffons composés en Python que possible. */
 static void load_python_plugins(GPluginModule *);
 
-/* Efface un type Python pour greffon de la mémoire. */
-static void free_native_plugin_type(PyTypeObject *);
+/* Prend acte du chargement de l'ensemble des greffons natifs. */
+static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPyChrysalidePlugin *);
 
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                        COMPOSITION DE NOUVEAU GREFFON NATIF                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un greffon de liaison Python */
+G_DEFINE_TYPE_WITH_CODE(GPyChrysalidePlugin, g_pychrysalide_plugin, G_TYPE_NATIVE_PLUGIN,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_PLUGIN_MANAGER, g_pychrysalide_plugin_plugin_manager_interface_init));
+
+
+NATIVE_PLUGIN_ENTRYPOINT(g_pychrysalide_plugin_new);
+
+
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = NULL car méthode statique.                            *
-*                args = non utilisé ici.                                      *
+*  Paramètres  : class = classe à initialiser.                                *
 *                                                                             *
-*  Description : Fournit la révision du programme global.                     *
+*  Description : Initialise la classe des greffons de support Python.         *
 *                                                                             *
-*  Retour      : Numéro de révision.                                          *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_chrysalide_revision(PyObject *self, PyObject *args)
+static void g_pychrysalide_plugin_class_init(GPyChrysalidePluginClass *class)
 {
-    PyObject *result;                       /* Valeur à retourner          */
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GPluginModuleClass *plugin;             /* Version parente de la classe*/
 
-#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'."   \
-)
+    object = G_OBJECT_CLASS(class);
 
-    result = PyUnicode_FromString("r" XSTR(REVISION));
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_pychrysalide_plugin_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_pychrysalide_plugin_finalize;
 
-    return result;
+    plugin = G_PLUGIN_MODULE_CLASS(class);
+
+    plugin->enable = (pg_management_fc)g_pychrysalide_plugin_enable;
+    plugin->disable = (pg_management_fc)g_pychrysalide_plugin_disable;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = NULL car méthode statique.                            *
-*                args = non utilisé ici.                                      *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
 *                                                                             *
-*  Description : Fournit la version du programme global.                      *
+*  Description : Procède à l'initialisation de l'interface de gestion.        *
 *                                                                             *
-*  Retour      : Numéro de version.                                           *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_chrysalide_version(PyObject *self, PyObject *args)
+static void g_pychrysalide_plugin_plugin_manager_interface_init(GPluginManagerInterface *iface)
 {
-    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;
+    iface->handle_native = (handle_native_plugins_cb)g_pychrysalide_plugin_handle_native_plugins_loaded_event;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = NULL car méthode statique.                            *
-*                args = non utilisé ici.                                      *
+*  Paramètres  : plugin = instance à initialiser.                             *
 *                                                                             *
-*  Description : Fournit la version du greffon pour Python.                   *
+*  Description : Initialise une instance de greffon de support Python.        *
 *                                                                             *
-*  Retour      : Numéro de version.                                           *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_chrysalide_mod_version(PyObject *self, PyObject *args)
+static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *plugin)
 {
-    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", _chrysalide_plugin.version);
-
-    result = PyUnicode_FromString(version);
+    STORE_PLUGIN_ABI(plugin);
 
-    return result;
+    plugin->py_module = NULL;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : -                                                            *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
 *                                                                             *
-*  Description : Détermine si l'interpréteur lancé est celui pris en compte.  *
+*  Description : Supprime toutes les références externes.                     *
 *                                                                             *
-*  Retour      : true si l'exécution peut se poursuivre, false sinon.         *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool is_current_abi_suitable(void)
+static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *plugin)
 {
-    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()");
-        return false;
-    }
-
-    snprintf(cmds, sizeof(cmds), GRAB_ABI_FLAGS_IN_PYTHON, fds[1]);
-
-    ret = PyRun_SimpleString(cmds);
-    if (ret != 0) goto icas_exit;
-
-    got = read(fds[0], content, sizeof(content));
-    if (got < 0)
-    {
-        perror("read()");
-        goto icas_exit;
-    }
-
-    content[got] = '\0';
-
-    result = (strcmp(content, LIBPYTHON_ABI_FLAGS) == 0);
-
- icas_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;
+    G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->dispose(G_OBJECT(plugin));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : -                                                            *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
 *                                                                             *
-*  Description : Assure une pleine initialisation des objets de Python-GI.    *
+*  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool install_metaclass_for_python_gobjects(void)
+static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *plugin)
 {
-    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 <python3-gi>/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 <python3>/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 <python3>/Objects/typeobject.c :
-     *
-     *    int _PyType_CheckConsistency(PyTypeObject *type)
-     *    {
-     *        [...]
-     *        CHECK(!_PyObject_IsFreed((PyObject *)type));
-     *        [...]
-     *    }
-     *
-     *  - cf. _PyObject_IsFreed() dans <python3>/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 <python3-gi>/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);
+    G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->finalize(G_OBJECT(plugin));
 
-    if (!result)
-    {
-        gi_types_mod = PyImport_ImportModule("gi.types");
+}
 
-        result = (PyErr_Occurred() == NULL);
 
-        if (result)
-            result = (PyType_CheckExact(&PyGObject_Type) == 0);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = nom du fichier à charger.                         *
+*                                                                             *
+*  Description : Crée un module pour un greffon de support Python.            *
+*                                                                             *
+*  Retour      : Adresse de la structure mise en place.                       *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
 
-        Py_XDECREF(gi_types_mod);
+GPluginModule *g_pychrysalide_plugin_new(GModule *module)
+{
+    GPyChrysalidePlugin *result;               /* Structure à retourner       */
 
-    }
+    result = g_object_new(G_TYPE_PYCHRYSALIDE_PLUGIN, NULL);
 
-#ifndef NDEBUG
-    if (result)
-        assert(strcmp(PyGObject_Type.ob_base.ob_base.ob_type->tp_name, "_GObjectMetaBase") == 0);
-#endif
+    if (!g_pychrysalide_plugin_create(result, module))
+        g_clear_object(&result);
 
-    return result;
+    return G_PLUGIN_MODULE(result);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : version = idenfiant de la version de GTK à stipuler.         *
+*  Paramètres  : plugin = instance à initialiser pleinement.                  *
+*                module = module système correspondant.                       *
 *                                                                             *
-*  Description : Définit la version attendue de GTK à charger dans Python.    *
+*  Description : Met en place un module pour un greffon de support Python.    *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
-*  Remarques   : -                                                            *
+*  Remarques   : Le transfert de propriétée du module est total.              *
 *                                                                             *
 ******************************************************************************/
-#ifdef INCLUDE_GTK_SUPPORT
-static bool set_version_for_gtk_namespace(const char *version)
+
+bool g_pychrysalide_plugin_create(GPyChrysalidePlugin *plugin, GModule *module)
 {
     bool result;                            /* Bilan à retourner           */
-    PyObject *gi_mod;                       /* Module Python-GObject       */
-    PyObject *args;                         /* Arguments à fournir         */
 
-    result = false;
+    result = g_native_plugin_create(G_NATIVE_PLUGIN(plugin),
+                                    "PyChrysalide",
+                                    "Chrysalide bindings to Python",
+                                    PACKAGE_VERSION,
+                                    CHRYSALIDE_WEBSITE("api/python/pychrysalide"),
+                                    NO_REQ,
+                                    module);
 
-    /**
-     * On cherche ici à éviter le message suivant si on charge 'gi.repository.Gtk' directement :
-     *
-     *
-     *   PyGIWarning: Gtk was imported without specifying a version first. \
-     *   Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
-     *
-     */
-
-    gi_mod = PyImport_ImportModule("gi");
-
-    if (gi_mod != NULL)
-    {
-        args = Py_BuildValue("ss", "Gtk", version);
+    return result;
 
-        run_python_method(gi_mod, "require_version", args);
+}
 
-        result = (PyErr_Occurred() == NULL);
 
-        Py_DECREF(args);
-        Py_DECREF(gi_mod);
 
-    }
 
-    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
+#if 0
 
-}
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : -                                                            *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                type   = type d'objet à mettre en place.                     *
 *                                                                             *
-*  Description : Point d'entrée pour l'initialisation de Python.              *
+*  Description : Crée une instance à partir d'un type dynamique externe.      *
 *                                                                             *
-*  Retour      : ?                                                            *
+*  Retour      : Instance d'objet gérée par l'extension ou NULL.              *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-#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."
-
-PyMODINIT_FUNC PyInit_pychrysalide(void)
+G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *plugin, PluginAction action, GType type)
 {
-    PyObject *result;                       /* Module Python à retourner   */
-    PyTypeObject *py_gobj_def;              /* Définition GObject courante */
-    GQuark pygobject_class_key;             /* Copie d'un accès GI interne */
-    bool status;                            /* Bilan des inclusions        */
-    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     */
-
-    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",
-        .m_doc = PYCHRYSALIDE_DOC,
-
-        .m_size = -1,
-
-        .m_methods = py_chrysalide_methods
+    gpointer result;                        /* Instance à retourner        */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyTypeObject *pytype;                   /* Classe Python concernée     */
+    PyObject *instance;                     /* Initialisation forcée       */
 
-    };
+    result = NULL;
 
-    /**
-     * 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.
-     */
+    gstate = PyGILState_Ensure();
 
-    result = get_access_to_python_module(py_chrysalide_module.m_name);
+    pytype = pygobject_lookup_class(type);
 
-    if (result != NULL)
+    if (pytype != NULL)
     {
-        Py_INCREF(result);
-        return result;
-    }
+        instance = PyObject_CallObject((PyObject *)pytype, NULL);
+        assert(instance != NULL);
 
-    if (!is_current_abi_suitable())
-    {
-        /**
-         * Un message d'erreur est défini par is_current_abi_suitable() en cas
-         * d'interpréteur pas adapté.
-         */
-        goto exit;
-    }
+        result = pygobject_get(instance);
 
-    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())
-    {
-        PyErr_SetString(PyExc_SystemError, "unable to install metaclass for Python GObjects.");
-        goto exit;
-    }
+    PyGILState_Release(gstate);
 
-    /**
-     * 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 : [<class 'gobject.GBoxed'>, <class 'object'>]
-     *
-     *    - avec module GLib : [<class 'gi.repository.GLib.Checksum'>, <class 'gi.Boxed'>, <class 'gobject.GBoxed'>, <class 'object'>]
-     *
-     * 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) :
-     *
-     *    <frozen importlib._bootstrap>: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 0
-    if (!import_namespace_from_gi_repository("GLib", "2.0"))
-        goto exit;
-#endif
+    return result;
+
+}
 
-#if 0
-#ifdef INCLUDE_GTK_SUPPORT
-    if (!set_version_for_gtk_namespace("3.0"))
-        goto exit;
-#endif
 #endif
 
-    if (!load_core_components(ACC_GLOBAL_VARS))
-    {
-        PyErr_SetString(PyExc_SystemError, "unable to load all basic components.");
-        goto exit;
-    }
 
-    /* Mise en place des fonctionnalités offertes */
 
-    result = PyModule_Create(&py_chrysalide_module);
 
-    register_access_to_python_module(py_chrysalide_module.m_name, result);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : prefix = message d'introduction à faire apparaître à l'écran.*
+*                                                                             *
+*  Description : Présente dans le journal une exception survenue.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    /**
-     * 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.
-     */
+void log_pychrysalide_exception(const char *prefix, ...)
+{
+    va_list ap;                             /* Compléments argumentaires   */
+    char *msg;                              /* Message complet à imprimer  */
+    PyObject *err_type;                     /* Type d'erreur Python        */
+    PyObject *err_value;                    /* Instance Python d'erreur    */
+    PyObject *err_traceback;                /* Trace Python associée       */
+    PyObject *err_string;                   /* Description Python d'erreur */
+    const char *err_msg;                    /* Représentation humaine      */
 
-    py_gobj_def = pygobject_lookup_class(G_TYPE_OBJECT);
+    assert(PyGILState_Check() == 1);
 
-    if (py_gobj_def != &PyGObject_Type)
+    if (PyErr_Occurred())
     {
-        Py_INCREF((PyObject *)py_gobj_def);
+        /* Base de la communication */
 
-        /* Définition récupérée de pyi_object_register_types() */
-        pygobject_class_key = g_quark_from_static_string("PyGObject::class");
+        va_start(ap, prefix);
 
-        g_type_set_qdata(G_TYPE_OBJECT, pygobject_class_key, &PyGObject_Type);
+        vasprintf(&msg, prefix, ap);
 
-    }
+        va_end(ap);
 
-    status = true;
-
-    if (status) status = add_features_module(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) status = ensure_python_string_enum_is_registered();
-    */
-    if (status) status = ensure_python_py_struct_is_registered();
-
-    if (status) status = define_data_types_constants(result);
-
-    if (status) status = populate_analysis_module();
-    if (status) status = populate_arch_module();
-    if (status) status = populate_glibext_module();
-    if (status) status = populate_common_module();
-    if (status) status = populate_core_module();
-    /*
-    if (status) status = populate_debug_module();
-    */
-    if (status) status = populate_format_module();
-    /*
-#ifdef INCLUDE_GTK_SUPPORT
-    if (status) status = populate_gtkext_module();
-    if (status) status = populate_gui_module();
-#endif
-    if (status) status = populate_mangling_module();
-    */
-    if (status) status = populate_plugins_module();
+        /* Détails complémentaires */
 
-    if (!status)
-    {
-        PyErr_SetString(PyExc_SystemError, "failed to load all PyChrysalide components.");
-        Py_DECREF(result);
-        result = NULL;
-        goto exit_and_restore;
-    }
+        PyErr_Fetch(&err_type, &err_value, &err_traceback);
 
-    if (_standalone)
-    {
-        ret = Py_AtExit(PyExit_pychrysalide);
+        PyErr_NormalizeException(&err_type, &err_value, &err_traceback);
 
-        if (ret == -1)
+        if (err_traceback == NULL)
         {
-            PyErr_SetString(PyExc_SystemError, "failed to register a cleanup function.");
-            Py_DECREF(result);
-            result = NULL;
-            goto exit_and_restore;
+            err_traceback = Py_None;
+            Py_INCREF(err_traceback);
         }
 
-        /**
-         * Comme les sources locales sont prioritaires, le fichier "core/global.h"
-         * du greffon masque la fonction suivante, issue du corps principal du
-         * programme.
-         *
-         * On la déclare donc à la main.
-         */
-        /*
-        extern void set_batch_mode(void);
-
-        set_batch_mode();
-        */
+        PyException_SetTraceback(err_value, err_traceback);
+
+        if (err_value == NULL)
+            msg = stradd(msg, _(": no extra information is provided..."));
+
+        else
+        {
+            err_string = PyObject_Str(err_value);
+            err_msg = PyUnicode_AsUTF8(err_string);
+
+            msg = stradd(msg, ": ");
+            msg = stradd(msg, err_msg);
+
+            Py_DECREF(err_string);
+
+        }
 
         /**
-         * 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.
+         * Bien que la documentation précise que la fonction PyErr_Fetch()
+         * transfère la propritété des éléments retournés, la pratique
+         * montre que le programme plante à la terminaison en cas d'exception.
+         *
+         * C'est par exemple le cas quand un greffon Python ne peut se lancer
+         * correctement ; l'exception est alors levée à partir de la fonction
+         * create_python_plugin() et le plantage intervient en sortie d'exécution,
+         * au moment de la libération de l'extension Python :
+         *
+         *    ==14939== Jump to the invalid address stated on the next line
+         *    ==14939==    at 0x1A8FCBC9: ???
+         *    ==14939==    by 0x53DCDB2: g_object_unref (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.5800.3)
+         *    ==14939==    by 0x610F834: on_plugin_ref_toggle (pglist.c:370)
+         *    ==14939==    by 0x610F31A: exit_all_plugins (pglist.c:153)
+         *    ==14939==    by 0x10AD19: main (main.c:440)
+         *    ==14939==  Address 0x1a8fcbc9 is not stack'd, malloc'd or (recently) free'd
          *
-         * Cet enregistrement est donc forcé ici.
+         * Curieusement, un appel à PyErr_PrintEx(1) corrige l'effet, alors qu'un
+         * appel à PyErr_PrintEx(0) ne change rien.
+         *
+         * La seule différence de l'instruction set_sys_last_vars réside en quelques
+         * lignes dans le code de l'interpréteur Python :
+         *
+         *    if (set_sys_last_vars) {
+         *        _PySys_SetObjectId(&PyId_last_type, exception);
+         *        _PySys_SetObjectId(&PyId_last_value, v);
+         *        _PySys_SetObjectId(&PyId_last_traceback, tb);
+         *    }
+         *
+         * L'explication n'est pas encore déterminé : bogue dans Chrysalide ou dans Python ?
+         * L'ajout des éléments dans le dictionnaire du module sys ajoute une référence
+         * à ces éléments.
+         *
+         * On reproduit ici le comportement du code correcteur avec PySys_SetObject().
          */
 
-#ifdef PYTHON_PACKAGE
+        PySys_SetObject("last_type", err_type);
+        PySys_SetObject("last_value", err_value);
+        PySys_SetObject("last_traceback", err_traceback);
 
-        ret = dladdr(__FUNCTION__, &info);
-        if (ret == 0)
-        {
-            LOG_ERROR_DL_N("dladdr");
-            Py_DECREF(result);
-            result = NULL;
-            goto exit_and_restore;
-        }
+        Py_XDECREF(err_traceback);
+        Py_XDECREF(err_value);
+        Py_XDECREF(err_type);
 
-        self = g_plugin_module_new(info.dli_fname);
-        assert(self != NULL);
+        log_plugin_simple_message(LMT_ERROR, msg);
 
-        register_plugin(self);
+        free(msg);
 
-#endif
+    }
 
-        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);
 
-        unlock_plugin_list_for_reading();
 
-        load_remaning_plugins();
 
-        /**
-         * On laisse fuir ici la référence sur self afin d'avoir
-         * l'assurance que le greffon se déchargera toujours en dernier.
-         *
-         * La fuite mémoire est au final évitée dans PyExit_pychrysalide().
-         */
 
-    }
 
- exit_and_restore:
 
-    if (py_gobj_def != &PyGObject_Type)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Prend acte de l'activation du greffon.                       *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    int ret;                                /* Bilan de préparatifs        */
+
+    _standalone = false;
+
+    /* Chargement du module pour Python */
+
+    ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalide);
+
+    if (ret == -1)
     {
-        g_type_set_qdata(G_TYPE_OBJECT, pygobject_class_key, py_gobj_def);
+        g_plugin_module_log_simple_message(G_PLUGIN_MODULE(plugin),
+                                           LMT_ERROR,
+                                           _("Can not extend the existing table of Python built-in modules."));
 
-        Py_DECREF((PyObject *)py_gobj_def);
+        result = false;
+        goto done;
 
     }
 
- exit:
+    Py_Initialize();
+
+    gstate = PyGILState_Ensure();
+
+    plugin->py_module = PyImport_ImportModule("pychrysalide");
+
+    /**
+     * Pour mémoire, une situation concrête conduisant à un échec :
+     * le paquet python3-gi-dbg n'est pas installé alors que le
+     * programme est compilé en mode débogage.
+     *
+     * Dans ce cas, pygobject_init(-1, -1, -1) échoue, et Py_Initialize()
+     * le laisse rien filtrer...
+     *
+     * En mode autonome, le shell Python remonte bien l'erreur par contre.
+     */
+
+    // TODO : check (2025)
+
+    result = (plugin->py_module != NULL);
+
+    PyGILState_Release(gstate);
 
-    if (result == NULL && !_standalone)
-        log_pychrysalide_exception("Loading failed");
+ done:
 
     return result;
 
 }
 
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Prend acte de la désactivation du greffon.                   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin)
+{
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+
+    gstate = PyGILState_Ensure();
+
+    clear_all_accesses_to_python_modules();
+
+    Py_XDECREF(plugin->py_module);
+    plugin->py_module = NULL;
+
+    PyGILState_Release(gstate);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                      INTERVENTION DANS LA GESTION DE GREFFONS                      */
+/* ---------------------------------------------------------------------------------- */
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : path = chemin supplémentaire pour l'espace de recherche.     *
@@ -896,6 +646,85 @@ static void extend_python_path(const char *path)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : modname  = nom du module à charger.                          *
+*                filename = chemin d'accès au code Python à charger.          *
+*                                                                             *
+*  Description : Crée un greffon à partir de code Python.                     *
+*                                                                             *
+*  Retour      : Adresse de la structure mise en place ou NULL si erreur.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GPluginModule *create_python_plugin(const char *modname, const char *filename)
+{
+    GPluginModule *result;                  /* Structure à retourner       */
+    PyObject *name;                         /* Chemin d'accès pour Python  */
+    PyObject *module;                       /* Script Python chargé        */
+    PyObject *dict;                         /* Dictionnaire associé        */
+    PyObject *class;                        /* Classe à instancier         */
+    PyObject *instance;                     /* Instance Python du greffon  */
+
+    name = PyUnicode_FromString(modname);
+    if (name == NULL) goto bad_exit;
+
+    module = PyImport_Import(name);
+    Py_DECREF(name);
+
+    if (module == NULL) goto no_import;
+
+    dict = PyModule_GetDict(module);
+    class = PyDict_GetItemString(dict, "AutoLoad");
+
+    if (class == NULL) goto no_class;
+    if (!PyType_Check(class->ob_type)) goto no_class;
+
+    instance = PyObject_CallFunction(class, NULL);
+    if (instance == NULL) goto no_instance;
+
+    result = G_PLUGIN_MODULE(pygobject_get(instance));
+
+    ///result->filename = strdup(filename);
+
+    /**
+     * L'instance Python et l'objet GLib résultant sont un même PyGObject.
+     *
+     * Donc pas besoin de toucher au comptage des références ici, la libération
+     * se réalisera à la fin, quand l'objet GLib sera libéré.
+     */
+
+    Py_DECREF(module);
+
+    printf(" -> REF: %p %u\n", result, G_OBJECT(result)->ref_count);
+
+    return result;
+
+ no_instance:
+
+    //log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));
+
+ no_class:
+
+    if (class == NULL)
+        log_plugin_simple_message(LMT_ERROR,
+                                  _("An error occured when looking for the 'AutoLoad': item not found!"));
+
+ no_import:
+
+    Py_XDECREF(module);
+
+    //log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);
+
+ bad_exit:
+
+    return NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : plugin = instance représentant le greffon Python d'origine.  *
 *                                                                             *
 *  Description : Charge autant de greffons composés en Python que possible.   *
@@ -920,7 +749,6 @@ static void load_python_plugins(GPluginModule *plugin)
     char *filename;                         /* Chemin d'accès reconstruit  */
     GPluginModule *pyplugin;                /* Lien vers un grffon Python  */
     bool status;                            /* Bilan d'une opération       */
-    //GGenConfig *config;                     /* Configuration à charger     */
 
     /* Définition des zones d'influence */
 
@@ -931,19 +759,19 @@ static void load_python_plugins(GPluginModule *plugin)
 #else
 
     edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python");
+
     dir = opendir(edir);
-    free(edir);
 
     if (dir != NULL)
     {
         closedir(dir);
 
-        edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python");
         extend_python_path(edir);
-        free(edir);
 
     }
 
+    free(edir);
+
 #endif
 
     g_plugin_module_log_variadic_message(plugin, LMT_INFO,
@@ -1007,8 +835,7 @@ static void load_python_plugins(GPluginModule *plugin)
                 goto done_with_plugin;
             }
 
-            //g_plugin_module_create_config(pyplugin);
-
+            /*
             status = g_plugin_module_manage(pyplugin, PGA_PLUGIN_LOADED);
 
             if (!status)
@@ -1018,18 +845,19 @@ static void load_python_plugins(GPluginModule *plugin)
                 g_object_unref(G_OBJECT(pyplugin));
                 goto done_with_plugin;
             }
-
-            /*
-            config = g_plugin_module_get_config(pyplugin);
-            g_generic_config_read(config);
-            g_object_unref(G_OBJECT(config));
             */
 
             g_plugin_module_log_variadic_message(plugin, LMT_PROCESS,
                                                  _("Loaded the Python plugin found in the '<b>%s</b>' directory"),
                                                  filename);
 
-            _register_plugin(pyplugin);
+            printf(" -> BUG // %p\n", pyplugin);
+
+            printf(" -> BUG // %u\n", ((GObject *)pyplugin)->ref_count);
+
+            //register_plugin(pyplugin);
+
+            /////////unref_object(pyplugin);
 
  done_with_plugin:
 
@@ -1049,116 +877,7 @@ static void load_python_plugins(GPluginModule *plugin)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                                                                             *
-*  Description : Prend acte du chargement du greffon.                         *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
-{
-    bool result;                            /* Bilan à retourner           */
-    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    int ret;                                /* Bilan de préparatifs        */
-
-    _standalone = false;
-
-    /* Chargement du module pour Python */
-
-    ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalide);
-
-    if (ret == -1)
-    {
-        log_plugin_simple_message(LMT_ERROR, _("Can not extend the existing table of Python built-in modules."));
-        result = false;
-        goto cpi_done;
-    }
-
-    Py_Initialize();
-
-    gstate = PyGILState_Ensure();
-
-    _chrysalide_module = PyImport_ImportModule("pychrysalide");
-
-    /**
-     * Pour mémoire, une situation concrête conduisant à un échec :
-     * le paquet python3-gi-dbg n'est pas installé alors que le
-     * programme est compilé en mode débogage.
-     *
-     * Dans ce cas, pygobject_init(-1, -1, -1) échoue, et Py_Initialize()
-     * le laisse rien filtrer...
-     *
-     * En mode autonome, le shell Python remonte bien l'erreur par contre.
-     */
-
-    result = (_chrysalide_module != NULL);
-
-    PyGILState_Release(gstate);
-
- cpi_done:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                                                                             *
-*  Description : Prend acte du déchargement du greffon.                       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *plugin)
-{
-    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-
-    gstate = PyGILState_Ensure();
-
-    clear_all_accesses_to_python_modules();
-
-    Py_XDECREF(_chrysalide_module);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : type = informations à libérer de la mémoire.                 *
-*                                                                             *
-*  Description : Efface un type Python pour greffon de la mémoire.            *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void free_native_plugin_type(PyTypeObject *type)
-{
-    free((char *)type->tp_name);
-    free((char *)type->tp_doc);
-
-    free(type);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
+*  Paramètres  : plugin = interface à manipuler.                              *
 *                                                                             *
 *  Description : Accompagne la fin du chargement des modules natifs.          *
 *                                                                             *
@@ -1168,308 +887,48 @@ static void free_native_plugin_type(PyTypeObject *type)
 *                                                                             *
 ******************************************************************************/
 
-G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, PluginAction action)
+static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPyChrysalidePlugin *plugin)
 {
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    size_t count;                           /* Quantité de greffons chargés*/
-    PyObject *module;                       /* Module à recompléter        */
-    PyObject *dict;                         /* Dictionnaire du module      */
-    GPluginModule **list;                   /* Ensemble de ces greffons    */
-    size_t i;                               /* Boucle de parcours          */
-    char *name;                             /* Désignation complète        */
-    char *doc;                              /* Description adaptée         */
-    int ret;                                /* Bilan d'un appel            */
-    PyTypeObject *type;                     /* Nouveau type dynamique      */
 
     gstate = PyGILState_Ensure();
 
-    if (action == PGA_NATIVE_PLUGINS_LOADED)
-    {
-        /* Intégration des greffons natifs en Python */
-
-        if (ensure_python_plugin_module_is_registered())
-        {
-            module = get_access_to_python_module("pychrysalide.plugins");
-            assert(module != NULL);
-
-            dict = PyModule_GetDict(module);
-
-            list = get_all_plugins(&count);
-
-            for (i = 0; i < count; i++)
-            {
-                ret = asprintf(&name, "pychrysalide.plugins.%s", G_OBJECT_TYPE_NAME(list[i]) + 1);
-                if (ret == -1)
-                {
-                    LOG_ERROR_N("asprintf");
-                    continue;
-                }
-
-                ret = asprintf(&doc, "Place holder for the native plugin %s documentation",
-                               G_OBJECT_TYPE_NAME(list[i]) + 1);
-                if (ret == -1)
-                {
-                    LOG_ERROR_N("asprintf");
-                    free(name);
-                    continue;
-                }
-
-                type = calloc(1, sizeof(PyTypeObject));
-
-                type->tp_name = name;
-                type->tp_doc = doc;
-                type->tp_flags = Py_TPFLAGS_DEFAULT;
-                type->tp_new = no_python_constructor_allowed;
-
-                if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type))
-                    g_object_set_data_full(G_OBJECT(list[i]), "python_type", type,
-                                           (GDestroyNotify)free_native_plugin_type);
-
-                else
-                    free_native_plugin_type(type);
-
-            }
-
-            if (list != NULL)
-                free(list);
-
-        }
-
-        /* Chargement des extensions purement Python */
-
-        load_python_plugins(plugin);
-
-    }
+    load_python_plugins(G_PLUGIN_MODULE(plugin));
 
     PyGILState_Release(gstate);
 
 }
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                type   = type d'objet à mettre en place.                     *
-*                                                                             *
-*  Description : Crée une instance à partir d'un type dynamique externe.      *
-*                                                                             *
-*  Retour      : Instance d'objet gérée par l'extension ou NULL.              *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *plugin, PluginAction action, GType type)
-{
-    gpointer result;                        /* Instance à retourner        */
-    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    PyTypeObject *pytype;                   /* Classe Python concernée     */
-    PyObject *instance;                     /* Initialisation forcée       */
-
-    result = NULL;
-
-    gstate = PyGILState_Ensure();
-
-    pytype = pygobject_lookup_class(type);
-
-    if (pytype != NULL)
-    {
-        instance = PyObject_CallObject((PyObject *)pytype, NULL);
-        assert(instance != NULL);
-
-        result = pygobject_get(instance);
-
-    }
-
-    PyGILState_Release(gstate);
-
-    return result;
 
-}
+/* ---------------------------------------------------------------------------------- */
+/*                             POINT D'ENTREE POUR PYTHON                             */
+/* ---------------------------------------------------------------------------------- */
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : namespace = module particulier à charger à partir de gi.     *
-*                version   = idenfiant de la version à stipuler.              *
+*  Paramètres  : -                                                            *
 *                                                                             *
-*  Description : Charge un module GI dans Python avec une version attendue.   *
+*  Description : Point d'entrée pour l'initialisation de Python.              *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : ?                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool import_namespace_from_gi_repository(const char *namespace, const char *version)
+PyMODINIT_FUNC PyInit_pychrysalide(void)
 {
-    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);
+    PyObject *result;                       /* Module Python à retourner   */
+    pyinit_details_t details;               /* Détails de chargement       */
 
- args_error:
+    details.standalone = _standalone;
 
-        Py_DECREF(args);
+    details.populate_extra = NULL;
 
-    }
+    result = init_python_pychrysalide_module(&details);
 
     return result;
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : prefix = message d'introduction à faire apparaître à l'écran.*
-*                                                                             *
-*  Description : Présente dans le journal une exception survenue.             *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void log_pychrysalide_exception(const char *prefix, ...)
-{
-    va_list ap;                             /* Compléments argumentaires   */
-    char *msg;                              /* Message complet à imprimer  */
-    PyObject *err_type;                     /* Type d'erreur Python        */
-    PyObject *err_value;                    /* Instance Python d'erreur    */
-    PyObject *err_traceback;                /* Trace Python associée       */
-    PyObject *err_string;                   /* Description Python d'erreur */
-    const char *err_msg;                    /* Représentation humaine      */
-
-    assert(PyGILState_Check() == 1);
-
-    if (PyErr_Occurred())
-    {
-        /* Base de la communication */
-
-        va_start(ap, prefix);
-
-        vasprintf(&msg, prefix, ap);
-
-        va_end(ap);
-
-        /* Détails complémentaires */
-
-        PyErr_Fetch(&err_type, &err_value, &err_traceback);
-
-        PyErr_NormalizeException(&err_type, &err_value, &err_traceback);
-
-        if (err_traceback == NULL)
-        {
-            err_traceback = Py_None;
-            Py_INCREF(err_traceback);
-        }
-
-        PyException_SetTraceback(err_value, err_traceback);
-
-        if (err_value == NULL)
-            msg = stradd(msg, _(": no extra information is provided..."));
-
-        else
-        {
-            err_string = PyObject_Str(err_value);
-            err_msg = PyUnicode_AsUTF8(err_string);
-
-            msg = stradd(msg, ": ");
-            msg = stradd(msg, err_msg);
-
-            Py_DECREF(err_string);
-
-        }
-
-        /**
-         * Bien que la documentation précise que la fonction PyErr_Fetch()
-         * transfère la propritété des éléments retournés, la pratique
-         * montre que le programme plante à la terminaison en cas d'exception.
-         *
-         * C'est par exemple le cas quand un greffon Python ne peut se lancer
-         * correctement ; l'exception est alors levée à partir de la fonction
-         * create_python_plugin() et le plantage intervient en sortie d'exécution,
-         * au moment de la libération de l'extension Python :
-         *
-         *    ==14939== Jump to the invalid address stated on the next line
-         *    ==14939==    at 0x1A8FCBC9: ???
-         *    ==14939==    by 0x53DCDB2: g_object_unref (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.5800.3)
-         *    ==14939==    by 0x610F834: on_plugin_ref_toggle (pglist.c:370)
-         *    ==14939==    by 0x610F31A: exit_all_plugins (pglist.c:153)
-         *    ==14939==    by 0x10AD19: main (main.c:440)
-         *    ==14939==  Address 0x1a8fcbc9 is not stack'd, malloc'd or (recently) free'd
-         *
-         * Curieusement, un appel à PyErr_PrintEx(1) corrige l'effet, alors qu'un
-         * appel à PyErr_PrintEx(0) ne change rien.
-         *
-         * La seule différence de l'instruction set_sys_last_vars réside en quelques
-         * lignes dans le code de l'interpréteur Python :
-         *
-         *    if (set_sys_last_vars) {
-         *        _PySys_SetObjectId(&PyId_last_type, exception);
-         *        _PySys_SetObjectId(&PyId_last_value, v);
-         *        _PySys_SetObjectId(&PyId_last_traceback, tb);
-         *    }
-         *
-         * L'explication n'est pas encore déterminé : bogue dans Chrysalide ou dans Python ?
-         * L'ajout des éléments dans le dictionnaire du module sys ajoute une référence
-         * à ces éléments.
-         *
-         * On reproduit ici le comportement du code correcteur avec PySys_SetObject().
-         */
-
-        PySys_SetObject("last_type", err_type);
-        PySys_SetObject("last_value", err_value);
-        PySys_SetObject("last_traceback", err_traceback);
-
-        Py_XDECREF(err_traceback);
-        Py_XDECREF(err_value);
-        Py_XDECREF(err_type);
-
-        log_plugin_simple_message(LMT_ERROR, msg);
-
-        free(msg);
-
-    }
-
-}
diff --git a/plugins/pychrysalide/core.h b/plugins/pychrysalide/core.h
index 5d25d3d..60c6c93 100644
--- a/plugins/pychrysalide/core.h
+++ b/plugins/pychrysalide/core.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * core.h - prototypes pour le plugin permettant des extensions en Python
  *
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2018-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -35,31 +35,29 @@
 #include <Python.h>
 
 
+#include <glibext/helpers.h>
 #include <plugins/plugin.h>
-#include <plugins/plugin-int.h>
 
 
 
-/* Point d'entrée pour l'initialisation de Python. */
-PyMODINIT_FUNC PyInit_pychrysalide(void);
+/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */
+
+
+#define G_TYPE_PYCHRYSALIDE_PLUGIN (g_pychrysalide_plugin_get_type())
 
-/* Prend acte du chargement du greffon. */
-G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+DECLARE_GTYPE(GPyChrysalidePlugin, g_pychrysalide_plugin, G, PYCHRYSALIDE_PLUGIN);
 
-/* Prend acte du déchargement du greffon. */
-G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *);
 
-/* Accompagne la fin du chargement des modules natifs. */
-G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *, PluginAction);
+/* Crée un module pour un greffon de support Python. */
+GPluginModule *g_pychrysalide_plugin_new(GModule *);
 
-/* Crée une instance à partir d'un type dynamique externe. */
-G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *, PluginAction, GType);
 
-/* Charge un module GI dans Python avec une version attendue. */
-bool import_namespace_from_gi_repository(const char *, const char *);
 
-/* Présente dans le journal une exception survenue. */
-void log_pychrysalide_exception(const char *, ...);
+/* --------------------------- POINT D'ENTREE POUR PYTHON --------------------------- */
+
+
+/* Point d'entrée pour l'initialisation de Python. */
+PyMODINIT_FUNC PyInit_pychrysalide(void);
 
 
 
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index deed584..ea2f55d 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -216,6 +216,53 @@ bool has_python_method(PyObject *module, const char *method)
 *                                                                             *
 *  Paramètres  : target = propriétaire de la routine visée.                   *
 *                method = désignation de la fonction à appeler.               *
+*                                                                             *
+*  Description : Indique si une routine Python possède une implémentation.    *
+*                                                                             *
+*  Retour      : Bilan de l'analyse.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool has_python_implementation_method(PyObject *module, const char *method)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *func;                         /* Fonction visée              */
+    const PyMethodDef *def;                 /* Définition de la fonction   */
+
+    result = (PyObject_HasAttrString(module, method) == 1);
+
+    if (result)
+    {
+        func = PyObject_GetAttrString(module, method);
+        assert(func != NULL);
+
+        result = PyCallable_Check(func);
+
+        if (func->ob_type == &PyCFunction_Type)
+        {
+            def = ((PyCFunctionObject *)func)->m_ml;
+
+            assert(strcmp(def->ml_name, method) == 0);
+
+            result = (def->ml_meth != not_yet_implemented_method);
+
+        }
+
+        Py_DECREF(func);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : target = propriétaire de la routine visée.                   *
+*                method = désignation de la fonction à appeler.               *
 *                args   = arguments à associer à l'opération.                 *
 *                                                                             *
 *  Description : Appelle une routine Python.                                  *
@@ -1403,6 +1450,109 @@ int convert_to_gdk_rgba(PyObject *arg, void *dst)
 
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en tableau de chaînes de caractères.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_sequence_to_charp_array(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    charp_array_t *array;                   /* Tableau à constituer        */
+    size_t i;                               /* Boucle de parcours          */
+    PyObject *value;                        /* Valeur brute d'un élément   */
+
+    array = (charp_array_t *)dst;
+
+    /* Nettoyage ? */
+    if (arg == NULL)
+    {
+        result = 1;
+        goto clean;
+    }
+
+    else
+    {
+        result = 0;
+
+        if (PySequence_Check(arg) != 1)
+            goto done;
+
+        array->length = PySequence_Length(arg);
+
+        array->values = calloc(array->length, sizeof(char *));
+
+        for (i = 0; i < array->length; i++)
+        {
+            value = PySequence_ITEM(arg, i);
+
+            if (!PyUnicode_Check(value))
+            {
+                Py_DECREF(value);
+                goto clean;
+            }
+
+            array->values[i] = strdup(PyUnicode_DATA(value));
+
+            Py_DECREF(value);
+
+        }
+
+        result = Py_CLEANUP_SUPPORTED;
+
+    }
+
+ done:
+
+    return result;
+
+ clean:
+
+    clean_charp_array(array);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : array = tableau de chaînes de caractères à traiter.          *
+*                                                                             *
+*  Description : Libère de la mémoire un tableau de chaînes de caractères.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void clean_charp_array(charp_array_t *array)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < array->length; i++)
+        if (array->values[i] != NULL)
+            free(array->values[i]);
+
+    if (array->values != NULL)
+        free(array->values);
+
+    array->values = NULL;
+    array->length = 0;
+
+}
+
+
+
 /* ---------------------------------------------------------------------------------- */
 /*                         TRANSFERT DES VALEURS CONSTANTES                           */
 /* ---------------------------------------------------------------------------------- */
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index ec245aa..133726a 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -47,6 +47,9 @@ int convert_to_callable(PyObject *, void *);
 /* Indique si une routine Python existe ou non. */
 bool has_python_method(PyObject *, const char *);
 
+/* Indique si une routine Python possède une implémentation. */
+bool has_python_implementation_method(PyObject *, const char *);
+
 /* Appelle une routine Python. */
 PyObject *run_python_method(PyObject *, const char *, PyObject *);
 
@@ -179,6 +182,26 @@ static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObj
 }
 
 
+/**
+ * Les initialisations de classes engagées par les appels à pyg_register_class_init()
+ * ne se déclenchent qu'après les initialisations complètes des classes côté GObject.
+ *
+ * Typiquement, pour une déclinaison Python du type PythonModule, sont appelées
+ * successivement les fonctions suivantes :
+ *  - g_plugin_module_class_init() ;
+ *  - g_python_plugin_class_init() ;
+ *  - py_plugin_module_init_gclass().
+ *
+ * Il est alors impératif de considérer les pointeurs de fonction déjà en place
+ * afin de ne par remplacer les implémentations de GPythonPlugin par les
+ * wrappers par défaut de PythonModule.
+ */
+
+#define PY_CLASS_SET_WRAPPER(field, ptr)    \
+    if (field == NULL)                      \
+        field = ptr;
+
+
 /* Marque l'interdiction d'une instanciation depuis Python. */
 PyObject *no_python_constructor_allowed(PyTypeObject *, PyObject *, PyObject *);
 
@@ -279,6 +302,21 @@ int convert_to_gdk_rgba(PyObject *, void *);
 
 #endif
 
+/* Tableau de chaînes de caractères converti */
+typedef struct _charp_array_t
+{
+    char **values;                          /* Liste de chaînes textuelles */
+    size_t length;                          /* Taille de cette liste       */
+
+} charp_array_t;
+
+/* Tente de convertir en tableau de chaînes de caractères. */
+int convert_to_sequence_to_charp_array(PyObject *, void *);
+
+/* Libère de la mémoire un tableau de chaînes de caractères. */
+void clean_charp_array(charp_array_t *);
+
+
 
 /* ----------------------- TRANSFERT DES VALEURS CONSTANTES ------------------------- */
 
diff --git a/plugins/pychrysalide/plugins/Makefile.am b/plugins/pychrysalide/plugins/Makefile.am
index bb9ed5d..0cd6af3 100644
--- a/plugins/pychrysalide/plugins/Makefile.am
+++ b/plugins/pychrysalide/plugins/Makefile.am
@@ -3,8 +3,10 @@ noinst_LTLIBRARIES = libpychrysaplugins.la
 
 libpychrysaplugins_la_SOURCES =				\
 	constants.h constants.c					\
-	plugin.h plugin.c						\
 	module.h module.c						\
+	plugin.h plugin.c						\
+	python-int.h							\
+	python.h python.c						\
 	translate.h translate.c
 
 libpychrysaplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
diff --git a/plugins/pychrysalide/plugins/module.c b/plugins/pychrysalide/plugins/module.c
index 1c7b326..ce94611 100644
--- a/plugins/pychrysalide/plugins/module.c
+++ b/plugins/pychrysalide/plugins/module.c
@@ -33,8 +33,8 @@
 #include <plugins/pglist.h>
 
 
-#include "constants.h"
 #include "plugin.h"
+#include "python.h"
 #include "../helpers.h"
 
 
@@ -46,7 +46,7 @@ static PyObject *py_plugins_get_plugin_by_name(PyObject *, PyObject *);
 static PyObject *py_plugins_get_all_plugins(PyObject *, PyObject *);
 
 /* Fournit les greffons offrant le service demandé. */
-static PyObject *py_plugins_get_all_plugins_for_action(PyObject *, PyObject *);
+//static PyObject *py_plugins_get_all_plugins_for_action(PyObject *, PyObject *);
 
 
 
@@ -162,7 +162,7 @@ static PyObject *py_plugins_get_all_plugins(PyObject *self, PyObject *args)
 
 }
 
-
+#if 0
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self = NULL car méthode statique.                            *
@@ -219,7 +219,7 @@ static PyObject *py_plugins_get_all_plugins_for_action(PyObject *self, PyObject
     return result;
 
 }
-
+#endif
 
 /******************************************************************************
 *                                                                             *
@@ -248,7 +248,7 @@ bool add_plugins_module(PyObject *super)
     static PyMethodDef py_plugins_methods[] = {
         PY_PLUGINS_GET_PLUGIN_BY_NAME_METHOD,
         PY_PLUGINS_GET_ALL_PLUGINS_METHOD,
-        PY_PLUGINS_GET_ALL_PLUGINS_FOR_ACTION_METHOD,
+        //PY_PLUGINS_GET_ALL_PLUGINS_FOR_ACTION_METHOD,
         { NULL }
     };
 
@@ -293,6 +293,7 @@ bool populate_plugins_module(void)
     result = true;
 
     if (result) result = ensure_python_plugin_module_is_registered();
+    if (result) result = ensure_python_python_plugin_is_registered();
 
     assert(result);
 
diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c
index de070cb..48cc992 100644
--- a/plugins/pychrysalide/plugins/plugin.c
+++ b/plugins/pychrysalide/plugins/plugin.c
@@ -25,14 +25,12 @@
 #include "plugin.h"
 
 
-#include <assert.h>
-#include <libgen.h>
 #include <malloc.h>
 #include <pygobject.h>
 #include <string.h>
 
 
-#include <common/extstr.h>
+#include <common/compiler.h>
 #include <plugins/dt.h>
 #include <plugins/plugin-int.h>
 #include <plugins/pglist.h>
@@ -52,85 +50,53 @@
 
 
 /* Initialise la classe des greffons d'extension. */
-static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer);
+static int py_plugin_module_init_gclass(GPluginModuleClass *, PyTypeObject *);
 
 CREATE_DYN_ABSTRACT_CONSTRUCTOR(plugin_module, G_TYPE_PLUGIN_MODULE, py_plugin_module_init_gclass);
 
 /* Initialise une instance sur la base du dérivé de GObject. */
 static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds);
 
-/* Encadre une étape de la vie d'un greffon. */
-static bool py_plugin_module_manage_wrapper(GPluginModule *);
-
-/* Assiste la désactivation d'un greffon. */
-static bool py_plugin_module_exit(GPluginModule *);
-
-/* Accompagne la fin du chargement des modules natifs. */
-static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction);
-
-/* Fournit le nom brut associé au greffon par défaut. */
-static PyObject *py_plugin_module_get_modname_by_default(PyObject *, PyObject *);
+/* Pointe le fichier contenant le greffon manipulé. */
+static char *py_plugin_module_get_filename_wrapper(const GPluginModule *);
 
 /* Fournit le nom brut associé au greffon. */
 static char *py_plugin_module_get_modname_wrapper(const GPluginModule *);
 
-#if 0
-
-#ifdef INCLUDE_GTK_SUPPORT
-
-/* Complète une liste de resources pour thème. */
-static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, gboolean, char ***, size_t *);
-
-/* Rend compte de la création d'un panneau. */
-static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *, PluginAction, GPanelItem *);
-
-/* Rend compte d'un affichage ou d'un retrait de panneau. */
-static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *, PluginAction, GPanelItem *, bool);
-
-#endif
-
-/* Procède à une opération liée à un contenu binaire. */
-static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *);
-
-/* Procède à une opération liée à un contenu chargé. */
-static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *, PluginAction, GLoadedContent *, wgroup_id_t, GtkStatusStack *);
+/* Prend acte de l'activation du greffon. */
+static bool py_plugin_module_enable_wrapper(GPluginModule *);
 
-/* Procède à une opération liée à l'analyse d'un format. */
-static bool py_plugin_module_handle_known_format_analysis_wrapper(const GPluginModule *, PluginAction, GKnownFormat *, wgroup_id_t, GtkStatusStack *);
+/* Prend acte de la désactivation du greffon. */
+static bool py_plugin_module_disable_wrapper(GPluginModule *);
 
-/* Procède à un préchargement de format de fichier. */
-static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *, PluginAction, GBinFormat *, GPreloadInfo *, GtkStatusStack *);
 
-/* Procède au rattachement d'éventuelles infos de débogage. */
-static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *, PluginAction, GExeFormat *);
 
-/* Exécute une action pendant un désassemblage de binaire. */
-static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *, PluginAction, GLoadedBinary *, GtkStatusStack *, GProcContext *);
-
-/* Effectue la détection d'effets d'outils externes. */
-static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *, PluginAction, const GLoadedContent *, bool, char ***, size_t *);
-
-#endif
+/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
 
 
+/* Affiche un message dans le journal des messages système. */
+static PyObject *py_plugin_module_log_message(PyObject *, PyObject *);
 
-/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
+/* Indique le nom associé à un greffon. */
+static PyObject *py_plugin_module_get_name(PyObject *, void *);
 
+/* Fournit une description fonctionnelle d'un greffon. */
+static PyObject *py_plugin_module_get_desc(PyObject *, void *);
 
-/* Construit le nom d'un fichier de configuration du greffon. */
-static PyObject *py_plugin_module_build_config_filename(PyObject *, PyObject *);
+/* Fournit la version d'un greffon et de ses fonctionnalités. */
+static PyObject *py_plugin_module_get_version(PyObject *, void *);
 
-/* Affiche un message dans le journal des messages système. */
-static PyObject *py_plugin_module_log_message(PyObject *, PyObject *);
+/* Fournit l'URL des ressources en ligne liées à un greffon. */
+static PyObject *py_plugin_module_get_url(PyObject *, void *);
 
-/* Fournit le nom brut associé au greffon. */
-static PyObject *py_plugin_module_get_modname(PyObject *, void *);
+/* Fournit la liste des dépendances d'un greffon donné. */
+static PyObject *py_plugin_module_get_requirements(PyObject *, void *);
 
 /* Indique le fichier contenant le greffon manipulé. */
 static PyObject *py_plugin_module_get_filename(PyObject *, void *);
 
-/* Fournit la description du greffon dans son intégralité. */
-static PyObject *py_plugin_module_get_interface(PyObject *, void *);
+/* Fournit le nom brut associé au greffon. */
+static PyObject *py_plugin_module_get_modname(PyObject *, void *);
 
 
 
@@ -141,47 +107,26 @@ static PyObject *py_plugin_module_get_interface(PyObject *, void *);
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : class  = classe à initialiser.                               *
-*                unused = données non utilisées ici.                          *
+*  Paramètres  : gclass  = classe GLib à initialiser.                         *
+*                pyclass = classe Python à initialiser.                       *
 *                                                                             *
 *  Description : Initialise la classe des greffons d'extension.               *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : 0 pour indiquer un succès de l'opération.                    *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unused)
+static int py_plugin_module_init_gclass(GPluginModuleClass *gclass, PyTypeObject *pyclass)
 {
-    class->init = NULL;
-    class->manage = py_plugin_module_manage_wrapper;
-    class->exit = py_plugin_module_exit;
+    PY_CLASS_SET_WRAPPER(gclass->get_filename, py_plugin_module_get_filename_wrapper);
+    PY_CLASS_SET_WRAPPER(gclass->get_modname, py_plugin_module_get_modname_wrapper);
 
-    class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper;
+    PY_CLASS_SET_WRAPPER(gclass->enable, py_plugin_module_enable_wrapper);
+    PY_CLASS_SET_WRAPPER(gclass->disable, py_plugin_module_disable_wrapper);
 
-    class->get_modname = py_plugin_module_get_modname_wrapper;
-
-#if 0
-
-#ifdef INCLUDE_GTK_SUPPORT
-    class->include_theme = py_plugin_module_include_theme_wrapper;
-    class->notify_panel = py_plugin_module_notify_panel_creation_wrapper;
-    class->notify_docking = py_plugin_module_notify_panel_docking_wrapper;
-#endif
-
-    class->handle_content = py_plugin_module_handle_binary_content_wrapper;
-    class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper;
-
-    class->handle_fmt_analysis = py_plugin_module_handle_known_format_analysis_wrapper;
-    class->preload_format = py_plugin_module_preload_binary_format_wrapper;
-    class->attach_debug = py_plugin_module_attach_debug_format_wrapper;
-
-    class->process_disass = py_plugin_module_process_disassembly_event_wrapper;
-
-    class->detect = py_plugin_module_detect_external_tools_wrapper;
-
-#endif
+    return 0;
 
 }
 
@@ -202,45 +147,56 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unu
 
 static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
+    const char *desc;                       /* Description plus loquace    */
+    const char *version;                    /* Version du greffon          */
+    const char *url;                        /* Site Web associé            */
+    const char *name;                       /* Désignation humaine courte  */
+    charp_array_t required;                 /* Liste des dépendances       */
     int ret;                                /* Bilan d'un appel            */
     GPluginModule *plugin;                  /* Greffon à manipuler         */
-    plugin_interface *iface;                /* Interface à constituer      */
-    GPluginModule *dependency;              /* Module nécessaire           */
-    PyObject *value;                        /* Valeur à présence imposée   */
-    size_t i;                               /* Boucle de parcours          */
-    PyObject *action;                       /* Identifiant d'une action    */
+
+    static char *kwlist[] = { "name", "desc", "version", "url", "required", NULL };
 
 #define PLUGIN_MODULE_DOC                                                   \
-    "PythonModule is the class allowing the creation of Chrysalide plugins" \
-    " for Python."                                                          \
+    "PluginModule is the core class handling the  Chrysalide plugins."      \
+    " Python plugins should inherit the pychrysalide.plugins.PythonPlugin"  \
+    " instead of this one."                                                 \
     "\n"                                                                    \
     "Calls to the *__init__* constructor of this abstract object expect"    \
-    " no particular argument.\n"                                            \
+    " the following arguments as keyword parameters:\n"                     \
+    "* *name*: a string providing a key name for the plugin;\n"             \
+    "* *desc* (optional): a string for a human readable description of the" \
+    " features provided by the plugin;\n"                                   \
+    "* *version* (optional): a string providing the version of the plugin;" \
+    " Version format is free;\n"                                            \
+    "* *url* (optional): a string for the homepage describing the plugin;\n"\
+    "* *required* (optional): dependencies of the plugin."                  \
     "\n"                                                                    \
-    "Several items have to be defined as class attributes in the final"     \
-    " class:\n"                                                             \
-    "* *_name*: a string providing a small name for the plugin;\n"          \
-    "* *_desc*: a string for a human readable description of the plugin;\n" \
-    "* *_version*: a string providing the version of the plugin;\n"         \
-    "* *_url*: a string for the homepage describing the plugin;\n"          \
-    "* *_actions*: a tuple of"                                              \
-    " pychrysalide.plugins.PluginModule.PluginAction defining the features" \
-    " the plugin is bringing; this list can be empty.\n"                    \
+    "Dependency to the *PyChrysalide* plugin is added automatically if not" \
+    " specified.\n"                                                         \
     "\n"                                                                    \
-    "Depending on the implemented actions, some of the following methods"   \
-    " have to be defined for new classes:\n"                                \
-    "* pychrysalide.plugins.PluginModule._init_config();\n"                 \
-    "* pychrysalide.plugins.PluginModule._notify_plugins_loaded();\n"       \
-    "* pychrysalide.plugins.PluginModule._include_theme();\n"               \
-    "* pychrysalide.plugins.PluginModule._on_panel_creation;\n"             \
-    "* pychrysalide.plugins.PluginModule._on_panel_docking();\n"            \
-    "* pychrysalide.plugins.PluginModule._handle_binary_content();\n"       \
-    "* pychrysalide.plugins.PluginModule._handle_loaded_content();\n"       \
-    "* pychrysalide.plugins.PluginModule._handle_format_analysis();\n"      \
-    "* pychrysalide.plugins.PluginModule._preload_format();\n"              \
-    "* pychrysalide.plugins.PluginModule._attach_debug_format();\n"         \
-    "* pychrysalide.plugins.PluginModule._process_disassembly_event();\n"   \
-    "* pychrysalide.plugins.PluginModule._detect_external_tools()."
+    "The following methods have to be defined for new classes:\n"           \
+    "* pychrysalide.plugins.PluginModule._get_filename();\n"                \
+    "* pychrysalide.plugins.PluginModule._get_modname();\n"                 \
+    "* pychrysalide.plugins.PluginModule._enable();\n"                      \
+    "* pychrysalide.plugins.PluginModule._disable()."
+
+    /* Récupération des paramètres */
+
+    desc = NULL;
+    version = NULL;
+    url = NULL;
+    required.values = NULL;
+    required.length = 0;
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "s|sssO&", kwlist,
+                                      &name, &desc, &version, &url,
+                                      convert_to_sequence_to_charp_array, &required);
+    if (!ret) return -1;
+
+    required.values = realloc(required.values, ++required.length * sizeof(char *));
+
+    required.values[required.length - 1] = strdup("PyChrysalide");
 
     /* Initialisation d'un objet GLib */
 
@@ -251,105 +207,17 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
 
     plugin = G_PLUGIN_MODULE(pygobject_get(self));
 
-    iface = calloc(1, sizeof(plugin_interface));
-    plugin->interface = iface;
-
-#define LOAD_PYTHON_IFACE(attr)                                                                         \
-    do                                                                                                  \
-    {                                                                                                   \
-        value = PyObject_GetAttrString(self, "_" #attr);                                                \
-        if (value == NULL)                                                                              \
-        {                                                                                               \
-            PyErr_SetString(PyExc_TypeError, _("A '_" #attr "' class attributes is missing."));         \
-            return -1;                                                                                  \
-        }                                                                                               \
-        if (PyUnicode_Check(value))                                                                     \
-        {                                                                                               \
-            iface->attr = strdup(PyUnicode_AsUTF8(value));                                              \
-            Py_DECREF(value);                                                                           \
-        }                                                                                               \
-        else                                                                                            \
-        {                                                                                               \
-            Py_DECREF(value);                                                                           \
-            PyErr_SetString(PyExc_TypeError, _("The '_" #attr "' class attributes must be a string.")); \
-            return -1;                                                                                  \
-        }                                                                                               \
-        assert(iface->attr != NULL);                                                                    \
-    }                                                                                                   \
-    while (0);
-
-    LOAD_PYTHON_IFACE(name);
-    LOAD_PYTHON_IFACE(desc);
-    LOAD_PYTHON_IFACE(version);
-    LOAD_PYTHON_IFACE(url);
-
-    iface->container = false;
-
-    /**
-     * Comme le greffon n'est pas passé par la résolution des dépendances,
-     * orchestrée par la fonction g_plugin_module_resolve_dependencies(),
-     * on simule l'effet attendu en obtenant une référence par un appel à
-     * get_plugin_by_name().
-     *
-     * L'incrémentation des références doit coller au plus près de
-     * l'inscription nominative du greffon : en cas de sortie impromptue
-     * (lorsqu'une erreur intervient pendant un chargement par exemple),
-     * l'état de l'ensemble est ainsi cohérent au moment du retrait du
-     * greffon fautif via la fonction g_plugin_module_dispose().
-     */
-
-    lock_plugin_list_for_reading();
-    dependency = get_plugin_by_name("PyChrysalide", NULL);
-    unlock_plugin_list_for_reading();
-
-    assert(dependency != NULL);
-
-    if (dependency == NULL)
-    {
-        PyErr_SetString(PyExc_TypeError, _("The internal name of the Python plugin has changed!"));
-        return -1;
-    }
-
-    iface->required = malloc(sizeof(char *));
-    iface->required[0] = "PyChrysalide";
-    iface->required_count = 1;
+    STORE_PLUGIN_ABI(plugin);
 
-    /* Validation du reste de l'interface */
-
-    value = PyObject_GetAttrString(self, "_actions");
-
-    if (value == NULL)
+    if (!g_plugin_module_create(plugin, name, desc, version, url,
+                                CONST_ARRAY_CAST(required.values, char), required.length))
     {
-        PyErr_SetString(PyExc_TypeError, _("An '_actions' class attributes is missing."));
+        clean_charp_array(&required);
+        PyErr_SetString(PyExc_ValueError, _("Unable to create plugin module."));
         return -1;
     }
 
-    if (!PyTuple_Check(value))
-    {
-        Py_DECREF(value);
-        PyErr_SetString(PyExc_TypeError, _("The '_actions' class attributes must be a tuple."));
-        return -1;
-    }
-
-    iface->actions_count = PyTuple_Size(value);
-    iface->actions = malloc(iface->actions_count * sizeof(plugin_action_t));
-
-    for (i = 0; i < iface->actions_count; i++)
-    {
-        action = PyTuple_GetItem(value, i);
-
-        if (!PyLong_Check(action))
-        {
-            Py_DECREF(value);
-            PyErr_SetString(PyExc_TypeError, _("invalid type for plugin action."));
-            return -1;
-        }
-
-        iface->actions[i] = PyLong_AsUnsignedLong(action);
-
-    }
-
-    Py_DECREF(value);
+    clean_charp_array(&required);
 
     return 0;
 
@@ -358,56 +226,55 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
+*  Paramètres  : plugin = greffon à consulter.                                *
 *                                                                             *
-*  Description : Encadre une étape de la vie d'un greffon.                    *
+*  Description : Pointe le fichier contenant le greffon manipulé.             *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Chemin d'accès au greffon.                                   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool py_plugin_module_manage_wrapper(GPluginModule *plugin)
+static char *py_plugin_module_get_filename_wrapper(const GPluginModule *plugin)
 {
-    bool result;                            /* Bilan à faire remonter      */
+    char *result;                           /* Désignation brute à renvoyer*/
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
     PyObject *pyobj;                        /* Objet Python concerné       */
-    PyObject *args;                         /* Arguments pour l'appel      */
     PyObject *pyret;                        /* Bilan d'exécution           */
 
-#define PLUGIN_MODULE_MANAGE_WRAPPER PYTHON_WRAPPER_DEF                 \
-(                                                                       \
-    _manage, "$self, action, /",                                        \
-    METH_VARARGS,                                                       \
-    "Abstract method called to react to several steps of the plugin"    \
-    " life.\n"                                                          \
-    "\n"                                                                \
-    "The expected action is a"                                          \
-    " pychrysalide.plugins.PluginModule.PluginAction value.\n"          \
-    "\n"                                                                \
-    "This method has to be defined in order to handle actions such as"  \
-    " *PLUGIN_LOADED*."                                                 \
+#define PLUGIN_MODULE_GET_FILENAME_WRAPPER PYTHON_WRAPPER_DEF       \
+(                                                                   \
+    _get_filename, "$self, /",                                      \
+    METH_NOARGS,                                                    \
+    "Abstract method providing the filename of the script.\n"       \
+    "\n"                                                            \
+    "The result should be the string value pointing to the plugin"  \
+    " file path.\n"                                                 \
 )
 
-    result = true;
+    result = NULL;
 
     gstate = PyGILState_Ensure();
 
     pyobj = pygobject_new(G_OBJECT(plugin));
 
-    if (has_python_method(pyobj, "_manage"))
+    if (has_python_method(pyobj, "_get_filename"))
     {
-        args = PyTuple_New(1);
+        pyret = run_python_method(pyobj, "_get_filename", NULL);
 
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(PGA_PLUGIN_LOADED));
+        if (pyret != NULL)
+        {
+            if (!PyUnicode_Check(pyret))
+                g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                                     _("The returned raw name must be a string"));
 
-        pyret = run_python_method(pyobj, "_manage", args);
+            else
+                result = strdup(PyUnicode_DATA(pyret));
 
-        result = (pyret == Py_True);
+        }
 
         Py_XDECREF(pyret);
-        Py_DECREF(args);
 
     }
 
@@ -422,44 +289,62 @@ static bool py_plugin_module_manage_wrapper(GPluginModule *plugin)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
+*  Paramètres  : plugin = greffon à valider.                                  *
 *                                                                             *
-*  Description : Assiste la désactivation d'un greffon.                       *
+*  Description : Fournit le nom brut associé au greffon.                      *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Désignation brute du greffon.                                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool py_plugin_module_exit(GPluginModule *plugin)
+static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin)
 {
-    bool result;                            /* Bilan à faire remonter      */
-    plugin_interface *final;                /* Interface finale conservée  */
+    char *result;                           /* Désignation brute à renvoyer*/
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan d'exécution           */
 
-    result = true;
+#define PLUGIN_MODULE_GET_MODNAME_WRAPPER PYTHON_WRAPPER_DEF        \
+(                                                                   \
+    _get_modname, "$self, /",                                       \
+    METH_NOARGS,                                                    \
+    "Abstract method providing the raw module name of the loaded"   \
+    " plugin.\n"                                                    \
+    "\n"                                                            \
+    "The result should be a short string value.\n"                  \
+)
 
-    final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
+    result = NULL;
+
+    gstate = PyGILState_Ensure();
 
-    if (final != NULL)
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_get_modname"))
     {
-        if (final->name != NULL) free(final->name);
-        if (final->desc != NULL) free(final->desc);
-        if (final->version != NULL) free(final->version);
-        if (final->url != NULL) free(final->url);
+        pyret = run_python_method(pyobj, "_get_modname", NULL);
 
-        assert(final->required_count == 1);
+        if (pyret != NULL)
+        {
+            if (!PyUnicode_Check(pyret))
+                g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                                     _("The returned raw name must be a string"));
 
-        if (final->required != NULL)
-            free(final->required);
+            else
+                result = strdup(PyUnicode_DATA(pyret));
 
-        if (final->actions != NULL)
-            free(final->actions);
+        }
 
-        free(final);
+        Py_XDECREF(pyret);
 
     }
 
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
     return result;
 
 }
@@ -468,51 +353,45 @@ static bool py_plugin_module_exit(GPluginModule *plugin)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
 *                                                                             *
-*  Description : Accompagne la fin du chargement des modules natifs.          *
+*  Description : Prend acte de l'activation du greffon.                       *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin, PluginAction action)
+static bool py_plugin_module_enable_wrapper(GPluginModule *plugin)
 {
+    bool result;                            /* Bilan à retourner           */
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
     PyObject *pyobj;                        /* Objet Python concerné       */
-    PyObject *args;                         /* Arguments pour l'appel      */
     PyObject *pyret;                        /* Bilan d'exécution           */
 
-#define PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER PYTHON_WRAPPER_DEF  \
-(                                                                       \
-    _notify_plugins_loaded, "$self, action, /",                         \
-    METH_VARARGS,                                                       \
-    "Abstract method called once all the (native?) plugins are"         \
-    " loaded.\n"                                                        \
-    "\n"                                                                \
-    "The expected action is a"                                          \
-    " pychrysalide.plugins.PluginModule.PluginAction value.\n"          \
-    "\n"                                                                \
-    "This method has to be defined in order to handle actions such as"  \
-    " *NATIVE_PLUGINS_LOADED* or *PLUGINS_LOADED*."                     \
+#define PLUGIN_MODULE_ENABLE_WRAPPER PYTHON_WRAPPER_DEF             \
+(                                                                   \
+    _enable, "$self, /",                                            \
+    METH_VARARGS,                                                   \
+    "Abstract method called when the plugin gets enabled.\n"        \
+    "\n"                                                            \
+    "The result is a boolean status: *False* if an implementation"  \
+    " failed, *True* otherwise."                                    \
 )
 
+    result = true;
+
     gstate = PyGILState_Ensure();
 
     pyobj = pygobject_new(G_OBJECT(plugin));
 
-    if (has_python_method(pyobj, "_notify_plugins_loaded"))
+    if (has_python_implementation_method(pyobj, "_enable"))
     {
-        args = PyTuple_New(1);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        pyret = run_python_method(pyobj, "_enable", NULL);
 
-        pyret = run_python_method(pyobj, "_notify_plugins_loaded", args);
+        result = (pyret == Py_True);
 
         Py_XDECREF(pyret);
-        Py_DECREF(args);
 
     }
 
@@ -520,36 +399,6 @@ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin
 
     PyGILState_Release(gstate);
 
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : self = objet Python concerné par l'appel.                    *
-*                args = arguments fournis à l'appel.                          *
-*                                                                             *
-*  Description : Fournit le nom brut associé au greffon par défaut.           *
-*                                                                             *
-*  Retour      : Désignation brute du greffon.                                *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_plugin_module_get_modname_by_default(PyObject *self, PyObject *args)
-{
-    PyObject *result;                       /* Bilan à retourner           */
-    GPluginModule *plugin;                  /* Version native du greffon   */
-    char *path;                             /* Chemin à traiter            */
-
-    plugin = G_PLUGIN_MODULE(pygobject_get(self));
-
-    path = strdup(g_plugin_module_get_filename(plugin));
-
-    result = PyUnicode_FromString(basename(path));
-
-    free(path);
-
     return result;
 
 }
@@ -557,52 +406,44 @@ static PyObject *py_plugin_module_get_modname_by_default(PyObject *self, PyObjec
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à valider.                                  *
+*  Paramètres  : plugin = greffon à manipuler.                                *
 *                                                                             *
-*  Description : Fournit le nom brut associé au greffon.                      *
+*  Description : Prend acte de la désactivation du greffon.                   *
 *                                                                             *
-*  Retour      : Désignation brute du greffon.                                *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin)
+static bool py_plugin_module_disable_wrapper(GPluginModule *plugin)
 {
-    char *result;                           /* Désignation brute à renvoyer*/
+    bool result;                            /* Bilan à retourner           */
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
     PyObject *pyobj;                        /* Objet Python concerné       */
     PyObject *pyret;                        /* Bilan d'exécution           */
 
-#define PLUGIN_MODULE_GET_MODNAME_WRAPPER PYTHON_WRAPPER_DEF_WITH       \
-(                                                                       \
-    _get_modname, "$self, /",                                           \
-    METH_VARARGS, py_plugin_module_get_modname_by_default,              \
-    "(Abstract) method providing the raw module name of the plugin.\n"  \
-    " loaded.\n"                                                        \
-    "\n"                                                                \
-    "The result should be a short string value.\n"                      \
-    "\n"                                                                \
-    "A default implementation builds the module name from the Python"   \
-    " script filename."                                                 \
+#define PLUGIN_MODULE_DISABLE_WRAPPER PYTHON_WRAPPER_DEF            \
+(                                                                   \
+    _disable, "$self, /",                                           \
+    METH_VARARGS,                                                   \
+    "Abstract method called when the plugin gets disabled.\n"       \
+    "\n"                                                            \
+    "The result is a boolean status: *False* if an implementation"  \
+    " failed, *True* otherwise."                                    \
 )
 
-    result = NULL;
+    result = true;
 
     gstate = PyGILState_Ensure();
 
     pyobj = pygobject_new(G_OBJECT(plugin));
 
-    if (has_python_method(pyobj, "_get_modname"))
+    if (has_python_implementation_method(pyobj, "_disable"))
     {
-        pyret = run_python_method(pyobj, "_get_modname", NULL);
+        pyret = run_python_method(pyobj, "_disable", NULL);
 
-        if (!PyUnicode_Check(pyret))
-            g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
-                                                 _("The returned raw name must be a string"));
-
-        else
-            result = strdup(PyUnicode_DATA(pyret));
+        result = (pyret == Py_True);
 
         Py_XDECREF(pyret);
 
@@ -617,6 +458,15 @@ static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin)
 }
 
 
+
+
+
+
+
+
+
+
+
 #if 0
 
 #ifdef INCLUDE_GTK_SUPPORT
@@ -1382,51 +1232,42 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *
 *  Paramètres  : self = objet Python concerné par l'appel.                    *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Construit le nom d'un fichier de configuration du greffon.   *
+*  Description : Affiche un message dans le journal des messages système.     *
 *                                                                             *
-*  Retour      : Chemin d'accès déterminé, ou NULL en cas d'erreur.           *
+*  Retour      : Rien en équivalent Python.                                   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_plugin_module_build_config_filename(PyObject *self, PyObject *args)
+static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
-    const char *final;                      /* Suffixe de fichier imposé   */
-    int create;                             /* Volonté de création         */
-    char *filename;                         /* Nom de fichier déterminé    */
+    LogMessageType type;                    /* Espèce du message           */
+    const char *msg;                        /* Contenu du message          */
 
-#define PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD PYTHON_METHOD_DEF        \
+#define PLUGIN_MODULE_LOG_MESSAGE_METHOD PYTHON_METHOD_DEF                  \
 (                                                                           \
-    build_config_filename, "final, /, create=False",                        \
+    log_message, "type, msg, /",                                            \
     METH_VARARGS, py_plugin_module,                                         \
-    "Build a filename suitable for the plugin configuration, ending with"   \
-    " the *final* suffix.\n"                                                \
+    "Display a message in the log window, in graphical mode, or in the"     \
+    " console output if none.\n"                                            \
     "\n"                                                                    \
-    "If the *create* parameter is set, the path to this filename is"        \
-    " created.\n"                                                           \
+    "The type of the message has to be a pychrysalide.core.LogMessageType"  \
+    " value."                                                               \
     "\n"                                                                    \
-    "The result is a string or None on failure."                            \
+    "The only difference with the main pychrysalide.core.log_message()"     \
+    " function is that messages are automatically prefixed with the plugin" \
+    " name here."                                                           \
 )
 
-    create = 0;
-
-    if (!PyArg_ParseTuple(args, "s|p", &final, &create))
+    if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg))
         return NULL;
 
-    filename = g_plugin_module_build_config_filename(G_PLUGIN_MODULE(pygobject_get(self)), final, create);
+    g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg);
 
-    if (filename != NULL)
-    {
-        result = PyUnicode_FromString(filename);
-        free(filename);
-    }
-    else
-    {
-        result = Py_None;
-        Py_INCREF(result);
-    }
+    result = Py_None;
+    Py_INCREF(result);
 
     return result;
 
@@ -1435,45 +1276,35 @@ static PyObject *py_plugin_module_build_config_filename(PyObject *self, PyObject
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = objet Python concerné par l'appel.                    *
-*                args = arguments fournis à l'appel.                          *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Affiche un message dans le journal des messages système.     *
+*  Description : Indique le nom associé à un greffon.                         *
 *                                                                             *
-*  Retour      : Rien en équivalent Python.                                   *
+*  Retour      : Désignation interne de l'extension, pour référence(s).       *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args)
+static PyObject *py_plugin_module_get_name(PyObject *self, void *closure)
 {
-    PyObject *result;                       /* Bilan à retourner           */
-    LogMessageType type;                    /* Espèce du message           */
-    const char *msg;                        /* Contenu du message          */
+    PyObject *result;                       /* Valeur à retourner          */
+    GPluginModule *plugin;                  /* Version native du greffon   */
+    const char *name;                       /* Nom attribué au greffon     */
 
-#define PLUGIN_MODULE_LOG_MESSAGE_METHOD PYTHON_METHOD_DEF                  \
-(                                                                           \
-    log_message, "type, msg, /",                                            \
-    METH_VARARGS, py_plugin_module,                                         \
-    "Display a message in the log window, in graphical mode, or in the"     \
-    " console output if none.\n"                                            \
-    "\n"                                                                    \
-    "The type of the message has to be a pychrysalide.core.LogMessageType"  \
-    " value."                                                               \
-    "\n"                                                                    \
-    "The only difference with the main pychrysalide.core.log_message()"     \
-    " function is that messages are automatically prefixed with the plugin" \
-    " name here."                                                           \
+#define PLUGIN_MODULE_NAME_ATTRIB PYTHON_GET_DEF_FULL   \
+(                                                       \
+    name, py_plugin_module,                             \
+    "Name of the plugin. This string value is used to"  \
+    " reference the plugin as dependency."              \
 )
 
-    if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg))
-        return NULL;
+    plugin = G_PLUGIN_MODULE(pygobject_get(self));
 
-    g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg);
+    name = g_plugin_module_get_name(plugin);
 
-    result = Py_None;
-    Py_INCREF(result);
+    result = PyUnicode_FromString(name);
 
     return result;
 
@@ -1485,32 +1316,31 @@ static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args)
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Fournit le nom brut associé au greffon.                      *
+*  Description : Fournit une description fonctionnelle d'un greffon.          *
 *                                                                             *
-*  Retour      : Désignation brute du greffon.                                *
+*  Retour      : Description textuelle associée à une extension ou NULL.      *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_plugin_module_get_modname(PyObject *self, void *closure)
+static PyObject *py_plugin_module_get_desc(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Valeur à retourner          */
     GPluginModule *plugin;                  /* Version native du greffon   */
-    char *modname;                          /* Désignation brute           */
+    const char *desc;                       /* Description du greffon      */
 
-#define PLUGIN_MODULE_MODNAME_ATTRIB PYTHON_GET_DEF_FULL    \
-(                                                           \
-    modname, py_plugin_module,                              \
-    "Raw module name of the plugin."                        \
+#define PLUGIN_MODULE_DESC_ATTRIB PYTHON_GET_DEF_FULL   \
+(                                                       \
+    desc, py_plugin_module,                             \
+    "Optional plugin description as string or *None*."  \
 )
 
     plugin = G_PLUGIN_MODULE(pygobject_get(self));
-    modname = g_plugin_module_get_modname(plugin);
 
-    result = PyUnicode_FromString(modname);
+    desc = g_plugin_module_get_desc(plugin);
 
-    free(modname);
+    result = PyUnicode_FromString(desc);
 
     return result;
 
@@ -1522,30 +1352,32 @@ static PyObject *py_plugin_module_get_modname(PyObject *self, void *closure)
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Indique le fichier contenant le greffon manipulé.            *
+*  Description : Fournit la version d'un greffon et de ses fonctionnalités.   *
 *                                                                             *
-*  Retour      : Chemin d'accès au greffon.                                   *
+*  Retour      : Version sous forme de chaîne de caractères ou None.          *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_plugin_module_get_filename(PyObject *self, void *closure)
+static PyObject *py_plugin_module_get_version(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Valeur à retourner          */
     GPluginModule *plugin;                  /* Version native du greffon   */
-    const char *filename;                   /* Chemin d'accès associé      */
+    const char *version;                    /* Version du greffon          */
 
-#define PLUGIN_MODULE_FILENAME_ATTRIB PYTHON_GET_DEF_FULL   \
+#define PLUGIN_MODULE_VERSION_ATTRIB PYTHON_GET_DEF_FULL    \
 (                                                           \
-    filename, py_plugin_module,                             \
-    "Filename of the plugin."                               \
+    version, py_plugin_module,                              \
+    "Optional plugin version, in free format, as string,"   \
+    " or *None*."                                           \
 )
 
     plugin = G_PLUGIN_MODULE(pygobject_get(self));
-    filename = g_plugin_module_get_filename(plugin);
 
-    result = PyUnicode_FromString(filename);
+    version = g_plugin_module_get_version(plugin);
+
+    result = PyUnicode_FromString(version);
 
     return result;
 
@@ -1557,113 +1389,204 @@ static PyObject *py_plugin_module_get_filename(PyObject *self, void *closure)
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Fournit la description du greffon dans son intégralité.      *
+*  Description : Fournit l'URL des ressources en ligne liées à un greffon.    *
 *                                                                             *
-*  Retour      : Interfaçage renseigné.                                       *
+*  Retour      : URL de renvoi associée à une extension ou None.              *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_plugin_module_get_interface(PyObject *self, void *closure)
+static PyObject *py_plugin_module_get_url(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Valeur à retourner          */
     GPluginModule *plugin;                  /* Version native du greffon   */
-    const plugin_interface *iface;          /* Interface liée à traduire   */
+    const char *url;                        /* URL associée au greffon     */
 
-#define PLUGIN_MODULE_INTERFACE_ATTRIB PYTHON_GET_DEF_FULL      \
+#define PLUGIN_MODULE_URL_ATTRIB PYTHON_GET_DEF_FULL            \
 (                                                               \
-    interface, py_plugin_module,                                \
-    "Interface exported by the plugin..\n"                      \
-    "\n"                                                        \
-    "This property is a pychrysalide.StructObject instance."    \
-    "\n"                                                        \
-    "The provided information is composed of the following"     \
-    " properties :\n"                                           \
-    "\n"                                                        \
-    "* gtp_name;\n"                                             \
-    "* name;\n"                                                 \
-    "* desc;\n"                                                 \
-    "* version;\n"                                              \
-    "* url;\n"                                                  \
-    "* container;\n"                                            \
-    "* required;\n"                                             \
-    "* actions.\n"                                              \
-    "\n"                                                        \
-    "The *gtp_name* value may be *None* for non-native plugin." \
-    " All other fields carry a string value except:\n"          \
-    "* *container*: a boolean status indicating if the plugin"  \
-    " can embed other plugins;\n"                               \
-    "* *required*: a tuple of depedencies names;\n"             \
-    "* *actions*: a tuple of available features from the plugin"\
-    " coded as pychrysalide.plugins.PluginModule.PluginAction"  \
-    " values."                                                  \
+    url, py_plugin_module,                                      \
+    "Optional URL pointing to the plugin homepage as string"    \
+    " or *None*."                                               \
 )
 
     plugin = G_PLUGIN_MODULE(pygobject_get(self));
-    iface = g_plugin_module_get_interface(plugin);
 
-    result = translate_plugin_interface_to_python(iface);
+    url = g_plugin_module_get_url(plugin);
+
+    result = PyUnicode_FromString(url);
 
     return result;
 
 }
 
-#if 0
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Fournit la configuration mise en place pour le greffon.      *
+*  Description : Fournit la liste des dépendances d'un greffon donné.         *
 *                                                                             *
-*  Retour      : Configuration dédiée à l'extension.                          *
+*  Retour      : Liste des noms d'extensions requises pour une extension.     *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_plugin_module_get_config(PyObject *self, void *closure)
+static PyObject *py_plugin_module_get_requirements(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Valeur à retourner          */
     GPluginModule *plugin;                  /* Version native du greffon   */
-    GGenConfig *config;                     /* Configuration associée      */
+    const char * const *required;           /* Liste de dépendances        */
+    size_t count;                           /* Nombre de ces dépendances   */
+    size_t i;                               /* Boucle de parcours          */
 
-#define PLUGIN_MODULE_CONFIG_ATTRIB PYTHON_GET_DEF_FULL         \
+#define PLUGIN_MODULE_REQUIREMENTS_ATTRIB PYTHON_GET_DEF_FULL   \
 (                                                               \
-    config, py_plugin_module,                                   \
-    "Dedicated configuration for the plugin."                   \
-    "\n"                                                        \
-    "The value is a pychrysalide.glibext.GenConfig instance"    \
-    " or None if the configuration is not yet created.\n"       \
-    "\n"                                                        \
-    "As configuration storage path depends on the plugin name," \
-    " all plugin properties have to get fully loaded by the"    \
-    " core before the configuration can be setup."              \
-    "automatically"            \
+    requirements, py_plugin_module,                             \
+    "Tuple of the plugin dependencies."                         \
+)
+
+    plugin = G_PLUGIN_MODULE(pygobject_get(self));
+
+    required = g_plugin_module_get_requirements(plugin, &count);
+
+    result = PyTuple_New(count);
+
+    for (i = 0; i < count; i++)
+        PyTuple_SetItem(result, i, PyUnicode_FromString(required[i]));
+
+    return result;
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Indique le fichier contenant le greffon manipulé.            *
+*                                                                             *
+*  Retour      : Chemin d'accès au greffon.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_get_filename(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    GPluginModule *plugin;                  /* Version native du greffon   */
+    char *filename;                         /* Chemin d'accès associé      */
+
+#define PLUGIN_MODULE_FILENAME_ATTRIB PYTHON_GET_DEF_FULL   \
+(                                                           \
+    filename, py_plugin_module,                             \
+    "Filename of the plugin."                               \
+)
+
+    plugin = G_PLUGIN_MODULE(pygobject_get(self));
+
+    filename = g_plugin_module_get_filename(plugin);
+
+    if (filename != NULL)
+    {
+        result = PyUnicode_FromString(filename);
+
+        free(filename);
+
+    }
+
+    else
+    {
+        /**
+         * La méthode de classe sollicitée a renvoyé une valeur nulle.
+         *
+         * Si cette méthode correspond à une implémentation Python
+         * (avec un appel à not_yet_implemented_method()), une exception
+         * est déjà en place.
+         *
+         * Si aucune exception n'a été prévue, un rattrapage est effectué ici.
+         */
+
+        if (PyErr_Occurred() == NULL)
+            PyErr_SetString(PyExc_NotImplementedError, _("unexpected NULL value as filename"));
+
+        result = NULL;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit le nom brut associé au greffon.                      *
+*                                                                             *
+*  Retour      : Désignation brute du greffon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_get_modname(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    GPluginModule *plugin;                  /* Version native du greffon   */
+    char *modname;                          /* Désignation brute           */
+
+#define PLUGIN_MODULE_MODNAME_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                           \
+    modname, py_plugin_module,                              \
+    "Raw module name of the plugin."                        \
 )
 
     plugin = G_PLUGIN_MODULE(pygobject_get(self));
-    config = g_plugin_module_get_config(plugin);
 
-    if (config == NULL)
+    modname = g_plugin_module_get_modname(plugin);
+
+    if (modname != NULL)
     {
-        result = Py_None;
-        Py_INCREF(result);
+        result = PyUnicode_FromString(modname);
+
+        free(modname);
+
     }
 
     else
     {
-        result = pygobject_new(G_OBJECT(config));
+        /**
+         * La méthode de classe sollicitée a renvoyé une valeur nulle.
+         *
+         * Si cette méthode correspond à une implémentation Python
+         * (avec un appel à not_yet_implemented_method()), une exception
+         * est déjà en place.
+         *
+         * Si aucune exception n'a été prévue, un rattrapage est effectué ici.
+         */
+
+        if (PyErr_Occurred() == NULL)
+            PyErr_SetString(PyExc_NotImplementedError, _("unexpected NULL value as modname"));
 
-        g_object_unref(G_OBJECT(config));
+        result = NULL;
 
     }
 
     return result;
 
 }
-#endif
 
 
 /******************************************************************************
@@ -1681,33 +1604,22 @@ static PyObject *py_plugin_module_get_config(PyObject *self, void *closure)
 PyTypeObject *get_python_plugin_module_type(void)
 {
     static PyMethodDef py_plugin_module_methods[] = {
-        PLUGIN_MODULE_MANAGE_WRAPPER,
-        PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER,
+        PLUGIN_MODULE_GET_FILENAME_WRAPPER,
         PLUGIN_MODULE_GET_MODNAME_WRAPPER,
-#if 0
-#ifdef INCLUDE_GTK_SUPPORT
-        PLUGIN_MODULE_INCLUDE_THEME_WRAPPER,
-        PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER,
-        PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER,
-#endif
-        PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER,
-        PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER,
-        PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER,
-        PLUGIN_MODULE_PRELOAD_BINARY_FORMAT_WRAPPER,
-        PLUGIN_MODULE_ATTACH_DEBUG_FORMAT_WRAPPER,
-        PLUGIN_MODULE_PROCESS_DISASSEMBLY_EVENT_WRAPPER,
-        PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER,
-        PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD,
-#endif
+        PLUGIN_MODULE_ENABLE_WRAPPER,
+        PLUGIN_MODULE_DISABLE_WRAPPER,
         PLUGIN_MODULE_LOG_MESSAGE_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_plugin_module_getseters[] = {
-        PLUGIN_MODULE_MODNAME_ATTRIB,
+        PLUGIN_MODULE_NAME_ATTRIB,
+        PLUGIN_MODULE_DESC_ATTRIB,
+        PLUGIN_MODULE_VERSION_ATTRIB,
+        PLUGIN_MODULE_URL_ATTRIB,
+        PLUGIN_MODULE_REQUIREMENTS_ATTRIB,
         PLUGIN_MODULE_FILENAME_ATTRIB,
-        PLUGIN_MODULE_INTERFACE_ATTRIB,
-        //PLUGIN_MODULE_CONFIG_ATTRIB,
+        PLUGIN_MODULE_MODNAME_ATTRIB,
         { NULL }
     };
 
@@ -1761,10 +1673,9 @@ bool ensure_python_plugin_module_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
-        if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type))
-            return false;
+        pyg_register_class_init(G_TYPE_PLUGIN_MODULE, (PyGClassInitFunc)py_plugin_module_init_gclass);
 
-        if (!define_plugin_module_constants(type))
+        if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type))
             return false;
 
     }
@@ -1772,80 +1683,3 @@ bool ensure_python_plugin_module_is_registered(void)
     return true;
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : modname  = nom du module à charger.                          *
-*                filename = chemin d'accès au code Python à charger.          *
-*                                                                             *
-*  Description : Crée un greffon à partir de code Python.                     *
-*                                                                             *
-*  Retour      : Adresse de la structure mise en place ou NULL si erreur.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GPluginModule *create_python_plugin(const char *modname, const char *filename)
-{
-    GPluginModule *result;                  /* Structure à retourner       */
-    PyObject *name;                         /* Chemin d'accès pour Python  */
-    PyObject *module;                       /* Script Python chargé        */
-    PyObject *dict;                         /* Dictionnaire associé        */
-    PyObject *class;                        /* Classe à instancier         */
-    PyObject *instance;                     /* Instance Python du greffon  */
-
-    name = PyUnicode_FromString(modname);
-    if (name == NULL) goto bad_exit;
-
-    module = PyImport_Import(name);
-    Py_DECREF(name);
-
-    if (module == NULL) goto no_import;
-
-    dict = PyModule_GetDict(module);
-    class = PyDict_GetItemString(dict, "AutoLoad");
-
-    if (class == NULL) goto no_class;
-    if (!PyType_Check(class->ob_type)) goto no_class;
-
-    instance = PyObject_CallFunction(class, NULL);
-    if (instance == NULL) goto no_instance;
-
-    result = G_PLUGIN_MODULE(pygobject_get(instance));
-
-    result->filename = strdup(filename);
-
-    /**
-     * L'instance Python et l'objet GLib résultante sont un même PyGObject.
-     *
-     * Donc pas besoin de toucher au comptage des références ici, la libération
-     * se réalisera à la fin, quand l'objet GLib sera libéré.
-     */
-
-    Py_DECREF(module);
-
-    return result;
-
- no_instance:
-
-    log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));
-
- no_class:
-
-    if (class == NULL)
-        log_plugin_simple_message(LMT_ERROR,
-                                  _("An error occured when looking for the 'AutoLoad': item not found!"));
-
- no_import:
-
-    Py_XDECREF(module);
-
-    log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);
-
- bad_exit:
-
-    return NULL;
-
-}
diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h
index ad54b8e..fd3d239 100644
--- a/plugins/pychrysalide/plugins/plugin.h
+++ b/plugins/pychrysalide/plugins/plugin.h
@@ -27,13 +27,9 @@
 
 
 #include <Python.h>
-#include <glib-object.h>
 #include <stdbool.h>
 
 
-#include <plugins/plugin.h>
-
-
 
 /* Fournit un accès à une définition de type à diffuser. */
 PyTypeObject *get_python_plugin_module_type(void);
@@ -41,9 +37,6 @@ PyTypeObject *get_python_plugin_module_type(void);
 /* Prend en charge l'objet 'pychrysalide.plugins.PluginModule'. */
 bool ensure_python_plugin_module_is_registered(void);
 
-/* Crée un greffon à partir de code Python. */
-GPluginModule *create_python_plugin(const char *, const char *);
-
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */
diff --git a/plugins/pychrysalide/plugins/python-int.h b/plugins/pychrysalide/plugins/python-int.h
new file mode 100644
index 0000000..7408d18
--- /dev/null
+++ b/plugins/pychrysalide/plugins/python-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * python-int.h - prototypes internes pour la déclinaison Python de greffons
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_PLUGINS_PYTHON_INT_H
+#define _PLUGINS_PYCHRYSALIDE_PLUGINS_PYTHON_INT_H
+
+
+#include "python.h"
+
+
+#include <plugins/plugin-int.h>
+
+
+
+/* Greffon Python pour Chrysalide (instance) */
+struct _GPythonPlugin
+{
+    GPluginModule parent;                   /* A laisser en premier        */
+
+    char *file;                             /* Valeur initiale de __file__ */
+
+};
+
+
+/* Greffon Python pour Chrysalide (classe) */
+struct _GPythonPluginClass
+{
+    GPluginModuleClass parent;              /* A laisser en premier        */
+
+};
+
+
+/* Met en place un greffon Python. */
+bool g_python_plugin_create(GPythonPlugin *, const char *, const char *, const char *, const char *, char ***, size_t *, const char *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PYTHON_INT_H */
diff --git a/plugins/pychrysalide/plugins/python.c b/plugins/pychrysalide/plugins/python.c
new file mode 100644
index 0000000..a958a8d
--- /dev/null
+++ b/plugins/pychrysalide/plugins/python.c
@@ -0,0 +1,489 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * python.c - déclinaison Python de greffons
+ *
+ * Copyright (C) 2025 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 "python.h"
+
+
+#include <malloc.h>
+#include <pygobject.h>
+
+
+#include <common/compiler.h>
+#include <common/cpp.h>
+
+
+#include "plugin.h"
+#include "python-int.h"
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+/* ------------------------- COMPOSITION DE NOUVEAU GREFFON ------------------------- */
+
+
+/* Initialise la classe des greffons Python. */
+static void g_python_plugin_class_init(GPythonPluginClass *);
+
+/* Initialise une instance de greffon Python. */
+static void g_python_plugin_init(GPythonPlugin *);
+
+/* Supprime toutes les références externes. */
+static void g_python_plugin_dispose(GPythonPlugin *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_python_plugin_finalize(GPythonPlugin *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Pointe le fichier contenant le greffon manipulé. */
+static char *g_python_plugin_get_filename(const GPythonPlugin *);
+
+/* Fournit le nom brut associé au greffon. */
+static char *g_python_plugin_get_modname(const GPythonPlugin *);
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(python_plugin, G_TYPE_PYTHON_PLUGIN, NULL);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_python_plugin_init(PyObject *self, PyObject *args, PyObject *kwds);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                           COMPOSITION DE NOUVEAU GREFFON                           */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un greffon Python. */
+G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des greffons Python.                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_python_plugin_class_init(GPythonPluginClass *class)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GPluginModuleClass *plugin;             /* Version parente de la classe*/
+
+    object = G_OBJECT_CLASS(class);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize;
+
+    plugin = G_PLUGIN_MODULE_CLASS(class);
+
+    plugin->get_filename = (get_plugin_filename_fc)g_python_plugin_get_filename;
+    plugin->get_modname = (get_plugin_modname_fc)g_python_plugin_get_modname;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de greffon Python.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_python_plugin_init(GPythonPlugin *plugin)
+{
+    STORE_PLUGIN_ABI(plugin);
+
+    plugin->file = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_python_plugin_dispose(GPythonPlugin *plugin)
+{
+    G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_python_plugin_finalize(GPythonPlugin *plugin)
+{
+    if (plugin->file != NULL)
+        free(plugin->file);
+
+    G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin   = instance à initialiser pleinement.                *
+*                name     = nom du greffon pour référence, principalement.    *
+*                desc     = présentation éventuelle à destination humaine.    *
+*                version  = indication de version éventuelle.                 *
+*                url      = référence vers une ressource en ligne.            *
+*                required = liste de dépendances éventuelles ou NULL.         *
+*                count    = taille de cette liste.                            *
+*                file     = emplacement du script considéré.                  *
+*                                                                             *
+*  Description : Met en place un greffon Python.                              *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
+
+bool g_python_plugin_create(GPythonPlugin *plugin, const char *name, const char *desc, const char *version, const char *url, char ***required, size_t *count, const char *file)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    /* Ajout imposé d'une dépendance à Python */
+
+    *required = realloc(*required, ++(*count) * sizeof(char *));
+
+    (*required)[*count - 1] = strdup("PyChrysalide");
+
+    /* Poursuite de la mise en place */
+
+    result = g_plugin_module_create(G_PLUGIN_MODULE(plugin),
+                                    name, desc, version, url,
+                                    CONST_ARRAY_CAST(*required, char), *count);
+
+    if (result)
+        plugin->file = strdup(file);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                                                                             *
+*  Description : Pointe le fichier contenant le greffon manipulé.             *
+*                                                                             *
+*  Retour      : Chemin d'accès au greffon.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_python_plugin_get_filename(const GPythonPlugin *plugin)
+{
+    char *result;                           /* Chemin d'accès à renvoyer   */
+
+    result = strdup(plugin->file);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à valider.                                  *
+*                                                                             *
+*  Description : Fournit le nom brut associé au greffon.                      *
+*                                                                             *
+*  Retour      : Désignation brute du greffon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_python_plugin_get_modname(const GPythonPlugin *plugin)
+{
+    char *result;                           /* Désignation brute à renvoyer*/
+    char *filename;                         /* Chemin du script Python     */
+    char *name;                             /* Nom du fichier associé      */
+    size_t length;                          /* Taille du nom               */
+    int ret;                                /* Bilan d'une comparaison     */
+
+    filename = g_python_plugin_get_filename(plugin);
+
+    name = basename(filename);
+
+    length = strlen(name);
+
+#define PYTHON_SUFFIX ".py"
+
+    ret = strncmp(&name[length - STATIC_STR_SIZE(PYTHON_SUFFIX)],
+                  PYTHON_SUFFIX,
+                  STATIC_STR_SIZE(PYTHON_SUFFIX));
+
+    if (ret == 0)
+        name[length - STATIC_STR_SIZE(PYTHON_SUFFIX)] = '\0';
+
+    result = strdup(name);
+
+    free(filename);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_python_plugin_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    const char *version;                    /* Version du greffon          */
+    const char *url;                        /* Site Web associé            */
+    charp_array_t required;                 /* Liste des dépendances       */
+    const char *file;                       /* Emplacement du script       */
+    int ret;                                /* Bilan de lecture des args.  */
+    PyObject *value;                        /* Valeur d'un arg. implicite  */
+    const char *name;                       /* Désignation humaine courte  */
+    const char *desc;                       /* Description plus loquace    */
+    GPythonPlugin *plugin;                  /* Greffon à manipuler         */
+
+    static char *kwlist[] = { "file", "version", "url", "required", NULL };
+
+#define PYTHON_PLUGIN_DOC                                                       \
+    "The PythonPlugin class helps to build custom Python plugins:\n"            \
+    "* some required information (*name* and *desc* for the parent"             \
+    " constructor) is automatically extracted from the final class name"        \
+    " or its documentation;\n"                                                  \
+    "* implementations for pychrysalide.plugins.PluginModule._get_filename()"   \
+    " and pychrysalide.plugins.PluginModule._get_modname() are provided,"       \
+    " relying on the *file* argument.\n"                                        \
+    "\n"                                                                        \
+    "Calls to the *__init__* constructor of this abstract object expect the"    \
+    " following arguments as keyword parameters:\n"                             \
+    "* *file*: path to the Python script; the value should be equal to the"     \
+    " *__file__* keyword;\n"                                                    \
+    "* *version* (optional): a string providing the version of the plugin;"     \
+    " Version format is free;\n"                                                \
+    "* *url* (optional): a string for the homepage describing the plugin;\n"    \
+    "* *required* (optional): dependencies of the plugin."
+
+    /* Récupération des paramètres */
+
+    version = NULL;
+    url = NULL;
+    required.values = NULL;
+    required.length = 0;
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "s|ssO&", kwlist,
+                                      &file, &version, &url,
+                                      convert_to_sequence_to_charp_array, &required);
+    if (!ret) return -1;
+
+    name = self->ob_type->tp_name;
+
+    value = PyObject_GetAttrString(self, "__doc__");
+
+    if (value != NULL && PyUnicode_Check(value))
+        desc = PyUnicode_AsUTF8(value);
+    else
+        desc = NULL;
+
+    Py_XDECREF(value);
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    plugin = G_PYTHON_PLUGIN(pygobject_get(self));
+
+    STORE_PLUGIN_ABI(plugin);
+
+    if (!g_python_plugin_create(plugin, name, desc, version, url,
+                                &required.values, &required.length,
+                                file))
+    {
+        clean_charp_array(&required);
+        PyErr_SetString(PyExc_ValueError, _("Unable to create Python plugin."));
+        return -1;
+    }
+
+    clean_charp_array(&required);
+
+    return 0;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                           DEFINITION POUR SUPPORT PYTHON                           */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_python_plugin_type(void)
+{
+    static PyMethodDef py_python_plugin_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_python_plugin_getseters[] = {
+        { NULL }
+    };
+
+    static PyTypeObject py_python_plugin_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.plugins.PythonPlugin",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = PYTHON_PLUGIN_DOC,
+
+        .tp_methods     = py_python_plugin_methods,
+        .tp_getset      = py_python_plugin_getseters,
+
+        .tp_init        = py_python_plugin_init,
+        .tp_new         = py_python_plugin_new,
+
+    };
+
+    return &py_python_plugin_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.plugins.PythonPlugin'. *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_python_plugin_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'PythonPlugin'  */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_python_plugin_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.plugins");
+
+        dict = PyModule_GetDict(module);
+
+        if (!ensure_python_plugin_module_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type))
+            return false;
+
+    }
+
+    return true;
+
+}
diff --git a/plugins/pychrysalide/plugins/python.h b/plugins/pychrysalide/plugins/python.h
new file mode 100644
index 0000000..8613bd1
--- /dev/null
+++ b/plugins/pychrysalide/plugins/python.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * python.h - prototypes pour la déclinaison Python de greffons
+ *
+ * Copyright (C) 2025 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
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_PLUGINS_PYTHON_H
+#define _PLUGINS_PYCHRYSALIDE_PLUGINS_PYTHON_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+#include <glibext/helpers.h>
+
+
+
+/* ------------------------- COMPOSITION DE NOUVEAU GREFFON ------------------------- */
+
+
+#define G_TYPE_PYTHON_PLUGIN (g_python_plugin_get_type())
+
+DECLARE_GTYPE(GPythonPlugin, g_python_plugin, G, PYTHON_PLUGIN);
+
+
+
+/* ------------------------- DEFINITION POUR SUPPORT PYTHON ------------------------- */
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_python_plugin_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.PythonPlugin'. */
+bool ensure_python_python_plugin_is_registered(void);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PYTHON_H */
diff --git a/src/common/compiler.h b/src/common/compiler.h
index 2585e47..65df8a4 100644
--- a/src/common/compiler.h
+++ b/src/common/compiler.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * compiler.h - prototypes pour le regroupement d'astuces à destination du compilateur
  *
- * Copyright (C) 2024 Cyrille Bagard
+ * Copyright (C) 2024-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -34,5 +34,19 @@
 #define __weak __attribute__((weak))
 
 
+/**
+ * Contournement des avertissements de la forme suivante :
+ *
+ *    assignment to 'const char * const*' from incompatible pointer type 'char **' [-Wincompatible-pointer-types]
+ *
+ * Références :
+ *  - https://www.reddit.com/r/C_Programming/comments/qa2231/const_char_const_and_char_are_incompatible/
+ *  - https://stackoverflow.com/questions/78125/why-cant-i-convert-char-to-a-const-char-const-in-c
+ *  - https://c-faq.com/ansi/constmismatch.html
+ */
+
+#define CONST_ARRAY_CAST(a, tp) (const tp **)a
+
+
 
 #endif  /* _COMMON_COMPILER_H */
diff --git a/src/common/cpp.h b/src/common/cpp.h
index 39e7676..2644281 100644
--- a/src/common/cpp.h
+++ b/src/common/cpp.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * cpp.h - prototypes pour avoir à disposition un langage C plus plus mieux
  *
- * Copyright (C) 2010-2020 Cyrille Bagard
+ * Copyright (C) 2010-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -31,6 +31,12 @@
 
 
 /**
+ * Fournit la taille d'une chaîne statique.
+ */
+#define STATIC_STR_SIZE(s) (sizeof(s) - 1)
+
+
+/**
  * Fournit la taille d'un tableau statique.
  */
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index dd191fa..555c449 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -1,12 +1,16 @@
 
 noinst_LTLIBRARIES = libplugins.la
 
-libplugins_la_SOURCES =					\
-	dt.h dt.c							\
-	pglist.h pglist.c					\
-	plugin-def.h						\
-	plugin-int.h						\
-	plugin.h plugin.c					\
+libplugins_la_SOURCES =						\
+	dt.h dt.c								\
+	manager-int.h							\
+	manager.h manager.c						\
+	native-int.h							\
+	native.h native.c						\
+	pglist.h pglist.c						\
+	plugin-def.h							\
+	plugin-int.h							\
+	plugin.h plugin.c						\
 	self.h
 
 libplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)
diff --git a/src/plugins/dt.c b/src/plugins/dt.c
index 2899845..9de0553 100644
--- a/src/plugins/dt.c
+++ b/src/plugins/dt.c
@@ -550,7 +550,7 @@ gpointer create_object_from_type(GType type)
     result = NULL;
 
     if (g_dynamic_types_find(_chrysalide_dtypes, type) != NULL)
-        result = build_type_instance(type);
+        result = NULL;//build_type_instance(type);
 
     else
         result = g_object_new(type, NULL);
diff --git a/src/plugins/manager-int.h b/src/plugins/manager-int.h
new file mode 100644
index 0000000..5ccc8f8
--- /dev/null
+++ b/src/plugins/manager-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * singleton-int.h - définitions internes propres aux interventions dans la gestion des extensions
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_CONTAINER_INT_H
+#define _PLUGINS_CONTAINER_INT_H
+
+
+#include "manager.h"
+
+
+
+/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
+
+
+/* Accompagne la fin du chargement des modules natifs. */
+typedef void (* handle_native_plugins_cb) (GPluginManager *);
+
+/* Prend acte du chargement de l'ensemble des greffons. */
+typedef void (* handle_all_plugins_cb) (GPluginManager *);
+
+
+/* Instance d'objet visant à être unique (interface) */
+struct _GPluginManagerInterface
+{
+    GTypeInterface base_iface;              /* A laisser en premier        */
+
+    handle_native_plugins_cb handle_native; /* Greffons natifs chargés     */
+    handle_all_plugins_cb handle_all;       /* Ensemble des greffons chargé*/
+
+};
+
+
+
+#endif  /* _PLUGINS_CONTAINER_INT_H */
diff --git a/src/plugins/manager.c b/src/plugins/manager.c
new file mode 100644
index 0000000..381fbc1
--- /dev/null
+++ b/src/plugins/manager.c
@@ -0,0 +1,113 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.c - intervention dans la gestion des extensions
+ *
+ * Copyright (C) 2025 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "manager.h"
+
+
+#include "manager-int.h"
+
+
+
+/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
+
+
+/* Procède à l'initialisation de l'interface de gestion. */
+static void g_plugin_manager_default_init(GPluginManagerInterface *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                      INTERVENTION DANS LA GESTION DE GREFFONS                      */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Détermine le type d'une interface pour l'intervention dans la gestion des greffons. */
+G_DEFINE_INTERFACE(GPluginManager, g_plugin_manager, G_TYPE_OBJECT)
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
+*                                                                             *
+*  Description : Procède à l'initialisation de l'interface de gestion.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_plugin_manager_default_init(GPluginManagerInterface *iface)
+{
+    iface->handle_native = NULL;
+    iface->handle_all = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : manager = interface à manipuler.                             *
+*                                                                             *
+*  Description : Accompagne la fin du chargement des modules natifs.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_plugin_manager_handle_native_plugins_loaded_event(GPluginManager *manager)
+{
+    GPluginManagerInterface *iface;         /* Interface utilisée          */
+
+    iface = G_PLUGIN_MANAGER_GET_IFACE(manager);
+
+    if (iface->handle_native != NULL)
+        iface->handle_native(manager);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : manager = interface à manipuler.                             *
+*                                                                             *
+*  Description : Prend acte du chargement de l'ensemble des greffons.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_plugin_manager_handle_all_plugins_loaded_event(GPluginManager *manager)
+{
+    GPluginManagerInterface *iface;         /* Interface utilisée          */
+
+    iface = G_PLUGIN_MANAGER_GET_IFACE(manager);
+
+    if (iface->handle_all != NULL)
+        iface->handle_all(manager);
+
+}
diff --git a/src/plugins/manager.h b/src/plugins/manager.h
new file mode 100644
index 0000000..2eb90a8
--- /dev/null
+++ b/src/plugins/manager.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.h - prototypes pour l'intervention dans la gestion des extensions
+ *
+ * Copyright (C) 2025 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_MANAGER_H
+#define _PLUGINS_MANAGER_H
+
+
+#include "../glibext/helpers.h"
+
+
+
+/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */
+
+
+#define G_TYPE_PLUGIN_MANAGER (g_plugin_manager_get_type())
+
+DECLARE_INTERFACE(GPluginManager, g_plugin_manager, G, PLUGIN_MANAGER);
+
+
+/* Accompagne la fin du chargement des modules natifs. */
+void g_plugin_manager_handle_native_plugins_loaded_event(GPluginManager *);
+
+/* Prend acte du chargement de l'ensemble des greffons. */
+void g_plugin_manager_handle_all_plugins_loaded_event(GPluginManager *);
+
+
+
+/* -------------------- SOLLICITATION DES FONCTIONNALITES CREEES -------------------- */
+
+
+#define notify_native_plugins_loaded() \
+    process_all_plugins_for(G_TYPE_PLUGIN_MANAGER, G_PLUGIN_MANAGER, \
+                            g_plugin_manager_handle_native_plugins_loaded_event)
+
+#define notify_all_plugins_loaded() \
+    process_all_plugins_for(G_TYPE_PLUGIN_MANAGER, G_PLUGIN_MANAGER, \
+                            g_plugin_manager_handle_all_plugins_loaded_event)
+
+
+
+#endif  /* _PLUGINS_MANAGER_H */
diff --git a/src/plugins/native-int.h b/src/plugins/native-int.h
new file mode 100644
index 0000000..8b8e0eb
--- /dev/null
+++ b/src/plugins/native-int.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * native-int.h - prototypes pour les structures internes des greffons natifs
+ *
+ * Copyright (C) 2025 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_NATIVE_INT_H
+#define _PLUGINS_NATIVE_INT_H
+
+
+#include "native.h"
+
+
+#include "plugin-int.h"
+
+
+
+/* Marqueur identifiable */
+#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de
+
+
+/* Greffon natif pour Chrysalide (instance) */
+struct _GNativePlugin
+{
+    GPluginModule parent;                   /* A laisser en premier        */
+
+    GModule *module;                        /* Abstration de manipulation  */
+
+};
+
+
+/* Greffon natif pour Chrysalide (classe) */
+struct _GNativePluginClass
+{
+    GPluginModuleClass parent;              /* A laisser en premier        */
+
+};
+
+
+/* Met en place un greffon natif. */
+bool g_native_plugin_create(GNativePlugin *, const char *, const char *, const char *, const char *, const char * const *, size_t, GModule *);
+
+
+
+#endif  /* _PLUGINS_NATIVE_INT_H */
diff --git a/src/plugins/native.c b/src/plugins/native.c
new file mode 100644
index 0000000..fedccbe
--- /dev/null
+++ b/src/plugins/native.c
@@ -0,0 +1,278 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * native.c - interactions avec un greffon natif donné
+ *
+ * Copyright (C) 2025 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 "native.h"
+
+
+#include "native-int.h"
+#include "../common/cpp.h"
+
+
+
+/* ------------------------- COMPOSITION DE NOUVEAU GREFFON ------------------------- */
+
+
+/* Initialise la classe des greffons natifs. */
+static void g_native_plugin_class_init(GNativePluginClass *);
+
+/* Initialise une instance de greffon natif. */
+static void g_native_plugin_init(GNativePlugin *);
+
+/* Supprime toutes les références externes. */
+static void g_native_plugin_dispose(GNativePlugin *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_native_plugin_finalize(GNativePlugin *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Pointe le fichier contenant le greffon manipulé. */
+static char *g_native_plugin_get_filename(const GNativePlugin *);
+
+/* Fournit le nom brut associé au greffon. */
+static char *g_native_plugin_get_modname(const GNativePlugin *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                           COMPOSITION DE NOUVEAU GREFFON                           */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un greffon Python. */
+G_DEFINE_TYPE(GNativePlugin, g_native_plugin, G_TYPE_PLUGIN_MODULE);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des greffons natifs.                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_native_plugin_class_init(GNativePluginClass *class)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GPluginModuleClass *plugin;             /* Version parente de la classe*/
+
+    object = G_OBJECT_CLASS(class);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_native_plugin_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_native_plugin_finalize;
+
+    plugin = G_PLUGIN_MODULE_CLASS(class);
+
+    plugin->get_filename = (get_plugin_filename_fc)g_native_plugin_get_filename;
+    plugin->get_modname = (get_plugin_modname_fc)g_native_plugin_get_modname;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de greffon natif.                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_native_plugin_init(GNativePlugin *plugin)
+{
+    plugin->module = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_native_plugin_dispose(GNativePlugin *plugin)
+{
+    if (plugin->module != NULL)
+    {
+        g_module_close(plugin->module);
+        plugin->module = NULL;
+    }
+
+    G_OBJECT_CLASS(g_native_plugin_parent_class)->dispose(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_native_plugin_finalize(GNativePlugin *plugin)
+{
+    G_OBJECT_CLASS(g_native_plugin_parent_class)->finalize(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin   = instance à initialiser pleinement.                *
+*                name     = nom du greffon pour référence, principalement.    *
+*                desc     = présentation éventuelle à destination humaine.    *
+*                version  = indication de version éventuelle.                 *
+*                url      = référence vers une ressource en ligne.            *
+*                required = liste de dépendances éventuelles ou NULL.         *
+*                count    = taille de cette liste.                            *
+*                module   = extension vue du système.                         *
+*                                                                             *
+*  Description : Met en place un greffon natif.                               *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : Le transfert de propriétée du module est total.              *
+*                                                                             *
+******************************************************************************/
+
+bool g_native_plugin_create(GNativePlugin *plugin, const char *name, const char *desc, const char *version, const char *url, const char * const *required, size_t count, GModule *module)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = g_plugin_module_create(G_PLUGIN_MODULE(plugin), name, desc, version, url, required, count);
+
+    if (result)
+        plugin->module = module;
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                                                                             *
+*  Description : Pointe le fichier contenant le greffon manipulé.             *
+*                                                                             *
+*  Retour      : Chemin d'accès au greffon.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_native_plugin_get_filename(const GNativePlugin *plugin)
+{
+    char *result;                           /* Chemin d'accès à renvoyer   */
+
+    result = strdup(g_module_name(plugin->module));
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à valider.                                  *
+*                                                                             *
+*  Description : Fournit le nom brut associé au greffon.                      *
+*                                                                             *
+*  Retour      : Désignation brute du greffon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_native_plugin_get_modname(const GNativePlugin *plugin)
+{
+    char *result;                           /* Désignation brute à renvoyer*/
+    char *path;                             /* Chemin à traiter            */
+    char *filename;                         /* Nom de bibliothèque partagée*/
+    size_t length;                          /* Taille du nom               */
+    int ret;                                /* Bilan d'une comparaison     */
+
+    path = g_native_plugin_get_filename(plugin);
+
+    filename = basename(path);
+
+    if (strncmp(filename, "lib", 3) == 0)
+        filename += 3;
+
+    length = strlen(filename);
+
+#ifdef _WIN32
+#   define SHARED_SUFFIX ".dll"
+#else
+#   define SHARED_SUFFIX ".so"
+#endif
+
+    if (length >= STATIC_STR_SIZE(SHARED_SUFFIX))
+    {
+        ret = strncmp(&filename[length - STATIC_STR_SIZE(SHARED_SUFFIX)],
+                      SHARED_SUFFIX,
+                      STATIC_STR_SIZE(SHARED_SUFFIX));
+
+        if (ret == 0)
+            filename[length - STATIC_STR_SIZE(SHARED_SUFFIX)] = '\0';
+
+    }
+
+    result = strdup(filename);
+
+    free(path);
+
+    return result;
+
+}
diff --git a/src/plugins/native.h b/src/plugins/native.h
new file mode 100644
index 0000000..205342c
--- /dev/null
+++ b/src/plugins/native.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * native.h - prototypes pour les interactions avec un greffon natif donné
+ *
+ * Copyright (C) 2025 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
+ */
+
+
+#ifndef _PLUGINS_NATIVE_H
+#define _PLUGINS_NATIVE_H
+
+
+#include "../glibext/helpers.h"
+
+
+
+#define G_TYPE_NATIVE_PLUGIN (g_native_plugin_get_type())
+
+DECLARE_GTYPE(GNativePlugin, g_native_plugin, G, NATIVE_PLUGIN);
+
+
+
+#endif  /* _PLUGINS_NATIVE_H */
diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c
index e4cb825..083f11f 100644
--- a/src/plugins/pglist.c
+++ b/src/plugins/pglist.c
@@ -30,20 +30,29 @@
 #include <malloc.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 
 #include <i18n.h>
 
 
 #include "dt.h"
+#include "manager.h"
 #include "plugin-int.h"
-#include "../common/extstr.h"
+#include "../common/cpp.h"
+#include "../common/extstr.h"       // REMME ?
 #include "../core/logs.h"
 #include "../core/nox.h"
 #include "../core/paths.h"
 
 
 
+/**
+ * Prototype de la fonction de création, à garder synchronisé avec
+ * NATIVE_PLUGIN_ENTRYPOINT() (cf. native-int.h).
+ */
+typedef GPluginModule * (* get_plugin_instance_cb) (GModule *);
+
 /* Liste de l'ensemble des greffons */
 static GPluginModule **_pg_list = NULL;
 static size_t _pg_count = 0;
@@ -129,6 +138,10 @@ bool init_all_plugins(bool load)
 
 void exit_all_plugins(void)
 {
+
+#if 0 //////
+
+
     size_t i;                               /* Boucle de parcours          */
     const plugin_interface *pg_iface;       /* Définition du greffon       */
 
@@ -188,6 +201,10 @@ void exit_all_plugins(void)
 
     exit_chrysalide_dynamic_types();
 
+
+
+#endif
+
 }
 
 
@@ -244,83 +261,95 @@ static int filter_dirs_or_mods(const struct dirent *entry)
 *                                                                             *
 *  Paramètres  : dir = répertoire à parcourir en quête de greffons (sans /).  *
 *                                                                             *
-*  Description : Part à la recherche de greffons sous forme de modules.       *
+*  Description : Indique la version (NOX/UI) associée à un nom de fichier.    *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : true si la version complémentaire existe ou false.           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void browse_directory_for_plugins(const char *dir)
+static bool check_for_plugin_versions(const char *dir, const char *filename, bool *is_nox, bool *is_ui)
 {
-    struct dirent **namelist;               /* Eléments trouvés            */
-    int ret;                                /* Bilan du parcours           */
-    bool nox;                               /* Absence de support graphique*/
-    char *filename;                         /* Elément à ausculter         */
-    GPluginModule *plugin;                  /* Greffon à intégrer ou pas   */
-
-    ret = scandir(dir, &namelist, filter_dirs_or_mods, alphasort);
-    if (ret < 0)
-    {
-        LOG_ERROR_N("scandir");
-        return;
-    }
-
-    nox = run_in_nox_mode();
+    bool result;                            /* Bilan à renvoyer            */
+    size_t length;                          /* Taille du nom de fichier    */
+    char *alt_path;                         /* Autre chemin complet testé  */
+    int ret;                                /* Bilan d'une impression      */
 
-    while (ret--)
-    {
-
-        if (nox)
-        {
 #ifdef _WIN32
-#   define UI_SHARED_SUFFIX "-ui.dll"
+#   define SHARED_SUFFIX ".dll"
 #else
-#   define UI_SHARED_SUFFIX "-ui.so"
+#   define SHARED_SUFFIX ".so"
 #endif
+#define UI_SHARED_SUFFIX "ui" SHARED_SUFFIX
 
-            if (strstr(namelist[ret]->d_name, UI_SHARED_SUFFIX) != NULL)
-            {
-                log_variadic_message(LMT_ERROR, _("Skipping unsuitable file: %s"), namelist[ret]->d_name);
-                continue;
-            }
+    result = false;
 
-        }
+    /* Propriétés du fichier courant */
 
-        filename = (char *)calloc(strlen(dir) + 1 + strlen(namelist[ret]->d_name) + 1, sizeof(char));
+    length = strlen(filename);
 
-        strcpy(filename, dir);
-        strcat(filename, G_DIR_SEPARATOR_S);
-        strcat(filename, namelist[ret]->d_name);
+    if (length < STATIC_STR_SIZE(UI_SHARED_SUFFIX))
+        *is_ui = false;
 
-        if (namelist[ret]->d_type == DT_DIR)
-            browse_directory_for_plugins(filename);
+    else
+        *is_ui = (strcmp(filename + length - STATIC_STR_SIZE(UI_SHARED_SUFFIX), UI_SHARED_SUFFIX) == 0);
+
+    if (*is_ui)
+        *is_nox = false;
+
+    else
+    {
+        if (length < STATIC_STR_SIZE(SHARED_SUFFIX))
+            *is_nox = false;
 
         else
-        {
-            plugin = g_plugin_module_new(filename);
+            *is_nox = (strcmp(filename + length - STATIC_STR_SIZE(SHARED_SUFFIX), SHARED_SUFFIX) == 0);
 
-            if (plugin != NULL)
-                register_plugin(plugin);
+    }
+
+    /* Recherche d'une version alternative */
 
+    if (*is_nox || *is_ui)
+    {
+
+        if (*is_nox)
+            ret = asprintf(&alt_path, "%s%s%.*s%s",
+                           dir, G_DIR_SEPARATOR_S,
+                           (int)(length - STATIC_STR_SIZE(SHARED_SUFFIX)), filename,
+                           UI_SHARED_SUFFIX);
+        else
+            ret = asprintf(&alt_path, "%s%s%.*s%s",
+                           dir, G_DIR_SEPARATOR_S,
+                           (int)(length - STATIC_STR_SIZE(SHARED_SUFFIX)), filename,
+                           SHARED_SUFFIX);
+
+        if (ret <= 0)
+        {
+            LOG_ERROR_N("asprintf");
+            goto exit;
         }
 
-        free(filename);
-        free(namelist[ret]);
+        ret = access(alt_path, R_OK | X_OK);
+
+        result = (ret == 0);
+
+        free(alt_path);
 
     }
 
-    free(namelist);
+ exit:
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à ajouter aux autres disponibles.           *
+*  Paramètres  : dir = répertoire à parcourir en quête de greffons (sans /).  *
 *                                                                             *
-*  Description : Ajoute un greffon à la liste principale de greffons.         *
+*  Description : Part à la recherche de greffons sous forme de modules.       *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -328,52 +357,117 @@ static void browse_directory_for_plugins(const char *dir)
 *                                                                             *
 ******************************************************************************/
 
-void _register_plugin(GPluginModule *plugin)
+static void browse_directory_for_plugins(const char *dir)
 {
-    size_t i;                               /* Boucle de parcours          */
-    const plugin_interface *pg_iface;       /* Informations à consulter    */
-    const char *name;                       /* Désignation du greffon      */
-
-    /**
-     * L'appel sans verrou n'est fourni que pour les greffons
-     * mettant en place des greffons en interne !
-     */
-
-    /* Recherche d'un éventuel doublon */
+    struct dirent **namelist;               /* Eléments trouvés            */
+    int ret;                                /* Bilan d'un appel            */
+    int k;                                  /* Boucle de parcours          */
+    bool nox_mode;                          /* Absence de support graphique*/
+    char *filename;                         /* Elément à ausculter         */
+    bool is_nox;                            /* Chemin de version basique ? */
+    bool is_ui;                             /* Chemin de version graphique */
+    bool has_alt;                           /* Existence d'une alternative */
+    GModule *module;                        /* Abstration de manipulation  */
+    get_plugin_instance_cb get_instance;    /* Point d'entrée exporté      */
+    GPluginModule *plugin;                  /* Greffon à intégrer ou pas   */
 
-    pg_iface = g_plugin_module_get_interface(plugin);
+    ret = scandir(dir, &namelist, filter_dirs_or_mods, alphasort);
+    if (ret < 0)
+    {
+        LOG_ERROR_N("scandir");
+        return;
+    }
 
-    name = pg_iface->name;
+    nox_mode = run_in_nox_mode();
 
-    for (i = 0; i < _pg_count; i++)
+    for (k = ret; k--; )
     {
-        pg_iface = g_plugin_module_get_interface(_pg_list[i]);
+        ret = asprintf(&filename, "%s%s%s", dir, G_DIR_SEPARATOR_S, namelist[k]->d_name);
+        if (ret <= 0)
+        {
+            LOG_ERROR_N("asprintf");
+            continue;
+        }
+
+        if (namelist[k]->d_type == DT_DIR)
+            browse_directory_for_plugins(filename);
 
-        if (strcmp(name, pg_iface->name) == 0)
+        else
         {
-            log_variadic_message(LMT_ERROR,
-                                 _("Plugin '%s' already registered!"), name);
 
-            break;
+            printf("// Candidate // %s\n", filename);
 
-        }
+            has_alt = check_for_plugin_versions(dir, namelist[k]->d_name, &is_nox, &is_ui);
 
-    }
+            printf("  -> nox=%d  ui=%d  -> alt? %d\n", is_nox, is_ui, has_alt);
 
-    /* Ajout du greffon à la liste */
 
-    if (i == _pg_count)
-    {
-        _pg_list = (GPluginModule **)realloc(_pg_list, ++_pg_count * sizeof(GPluginModule));
+            if ((nox_mode && is_nox) || (!nox_mode && ((is_nox && !has_alt) || is_ui)))
+            {
+
+
+                printf(" ---> load!\n");
 
-        _pg_list[_pg_count - 1] = plugin;
 
-        g_object_add_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL);
+
+                module = g_module_open(filename, G_MODULE_BIND_LAZY);
+                if (module == NULL)
+                {
+                    log_variadic_message(LMT_ERROR, 
+                                         _("Error while loading the plugin candidate '%s' : %s"),
+                                         filename, g_module_error());
+                    goto next_file;
+                }
+
+
+                printf(" (main) module=%p '%s'\n", module, g_module_name(module));
+
+
+                if (!g_module_symbol(module, "get_chrysalide_plugin_instance", (gpointer *)&get_instance))
+                {
+                    log_variadic_message(LMT_ERROR,
+                                         _("No '%s' entry in plugin candidate '%s'"),
+                                         "<sym>", filename);
+
+
+
+                }
+
+
+                if (get_instance == NULL)
+                    plugin = NULL;
+                else
+                    plugin = get_instance(module);
+
+
+
+                printf(" ===> plugin: %p\n", plugin);
+
+
+
+                if (plugin != NULL)
+                {
+                    register_plugin(plugin);
+                    unref_object(plugin);
+                }
+
+                else
+                    g_module_close(module);
+
+            }
+            else
+                log_variadic_message(LMT_INFO, _("Skipping unsuitable file for plugin: %s"), filename);
+
+        }
+
+ next_file:
+
+        free(filename);
+        free(namelist[k]);
 
     }
 
-    else
-        /* FIXME : leak(plugin); */;
+    free(namelist);
 
 }
 
@@ -394,7 +488,7 @@ void _register_plugin(GPluginModule *plugin)
 
 static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolean last)
 {
-    const plugin_interface *pg_iface;       /* Vitrine d'un greffon        */
+    const char *name;                       /* Désignation du greffon      */
     size_t index;                           /* Indice du greffon           */
     GPluginModule *same;                    /* Juste pour la récupération  */
 
@@ -402,16 +496,17 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea
     {
         assert(g_rw_lock_writer_trylock(&_pg_lock) == FALSE);
 
-        pg_iface = g_plugin_module_get_interface(plugin);
+        name = g_plugin_module_get_name(plugin);
 
-        same = get_plugin_by_name(pg_iface->name, &index);
+        same = get_plugin_by_name(name, &index);
         assert(same != NULL);
+        assert(same == plugin);
 
-        _pg_list[index] = NULL;
+        g_clear_object(&_pg_list[index]);
 
-        g_object_remove_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL);
+        g_object_remove_toggle_ref(G_OBJECT(same), (GToggleNotify)on_plugin_ref_toggle, NULL);
 
-        g_object_unref(G_OBJECT(same));
+        unref_object(same);
 
     }
 
@@ -432,9 +527,40 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea
 
 void register_plugin(GPluginModule *plugin)
 {
+    size_t i;                               /* Boucle de parcours          */
+    const char *name;                       /* Désignation du greffon      */
+    const char *existing;                   /* Nom d'un greffon en place   */
+
     g_rw_lock_writer_lock(&_pg_lock);
 
-    _register_plugin(plugin);
+    /* Recherche d'un éventuel doublon */
+
+    name = g_plugin_module_get_name(plugin);
+
+    for (i = 0; i < _pg_count; i++)
+    {
+        existing = g_plugin_module_get_name(_pg_list[i]);
+
+        if (strcmp(name, existing) == 0)
+        {
+            log_variadic_message(LMT_ERROR, _("Plugin '%s' already registered!"), name);
+            break;
+        }
+
+    }
+
+    /* Ajout du greffon à la liste */
+
+    if (i == _pg_count)
+    {
+        _pg_list = realloc(_pg_list, ++_pg_count * sizeof(GPluginModule));
+
+        _pg_list[_pg_count - 1] = plugin;
+        ref_object(plugin);
+
+        g_object_add_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL);
+
+    }
 
     g_rw_lock_writer_unlock(&_pg_lock);
 
@@ -543,7 +669,7 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
 {
     GPluginModule *result;                  /* Greffon trouvé à renvoyer   */
     size_t i;                               /* Boucle de parcours          */
-    const plugin_interface *pg_iface;       /* Vitrine d'un greffon        */
+    const char *current;                    /* Nom du greffon courant      */
 
     result = NULL;
 
@@ -557,11 +683,12 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
         /* Si on est en train de procéder à un nettoyage... */
         if (_pg_list[i] == NULL) continue;
 
-        pg_iface = g_plugin_module_get_interface(_pg_list[i]);
+        current = g_plugin_module_get_name(_pg_list[i]);
 
-        if (strcmp(pg_iface->name, name) == 0)
+        if (strcmp(current, name) == 0)
         {
             result = _pg_list[i];
+            ref_object(result);
 
             if (index != NULL)
                 *index = i;
@@ -570,9 +697,6 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
 
     }
 
-    if (result != NULL)
-        g_object_ref(G_OBJECT(result));
-
     return result;
 
 }
@@ -603,60 +727,7 @@ GPluginModule **get_all_plugins(size_t *count)
     for (i = 0; i < _pg_count; i++)
     {
         result[i] = _pg_list[i];
-        g_object_ref(G_OBJECT(_pg_list[i]));
-    }
-
-    g_rw_lock_reader_unlock(&_pg_lock);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : action = fonctionnalité recherchée.                          *
-*                count  = nombre de greffons trouvés. [OUT]                   *
-*                                                                             *
-*  Description : Fournit les greffons offrant le service demandé.             *
-*                                                                             *
-*  Retour      : Liste de greffons correspondants issue d'un tri interne.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GPluginModule **get_all_plugins_for_action(PluginAction action, size_t *count)
-{
-    GPluginModule **result;                 /* Liste à retourner           */
-    size_t i;                               /* Boucle de parcours #1       */
-    const plugin_interface *pg_iface;       /* Informations à consulter    */
-    size_t j;                               /* Boucle de parcours #2       */
-
-    result = NULL;
-    *count = 0;
-
-    g_rw_lock_reader_lock(&_pg_lock);
-
-    for (i = 0; i < _pg_count; i++)
-    {
-        pg_iface = g_plugin_module_get_interface(_pg_list[i]);
-
-        for (j = 0; j < pg_iface->actions_count; j++)
-        {
-            if (pg_iface->actions[j] == action)
-            {
-                result = realloc(result, ++(*count) * sizeof(GPluginModule *));
-
-                result[*count - 1] = _pg_list[i];
-                g_object_ref(G_OBJECT(_pg_list[i]));
-
-                break;
-
-            }
-
-        }
-
+        ref_object(result[i]);
     }
 
     g_rw_lock_reader_unlock(&_pg_lock);
diff --git a/src/plugins/pglist.h b/src/plugins/pglist.h
index 83e9091..5541493 100644
--- a/src/plugins/pglist.h
+++ b/src/plugins/pglist.h
@@ -52,9 +52,6 @@ void _lock_unlock_plugin_list_for_reading(bool lock);
 #define unlock_plugin_list_for_reading() _lock_unlock_plugin_list_for_reading(false)
 
 /* Ajoute un greffon à la liste principale de greffons. */
-void _register_plugin(GPluginModule *);
-
-/* Ajoute un greffon à la liste principale de greffons. */
 void register_plugin(GPluginModule *);
 
 /* Charge tous les greffons restant à charger. */
@@ -66,16 +63,39 @@ GPluginModule *get_plugin_by_name(const char *, size_t *);
 /* Fournit la liste de l'ensemble des greffons. */
 GPluginModule **get_all_plugins(size_t *);
 
-/* Fournit les greffons offrant le service demandé. */
-GPluginModule **get_all_plugins_for_action(PluginAction, size_t *);
-
 
 
 /**
  * Définitions des opérations appliquables à une catégories de greffons.
  */
 
-#define process_all_plugins_for(a, f, ...)                  \
+#define process_all_plugins_for(tp, cst, fc)                    \
+    do                                                          \
+    {                                                           \
+        size_t __count;                                         \
+        GPluginModule **__list;                                 \
+        size_t __i;                                             \
+        __list = get_all_plugins(&__count);                     \
+        for (__i = 0; __i < __count; __i++)                     \
+        {                                                       \
+            if (G_TYPE_CHECK_INSTANCE_TYPE(__list[__i], tp))    \
+                fc(cst(__list[__i]));                           \
+            unref_object(__list[__i]);                          \
+        }                                                       \
+        if (__list != NULL)                                     \
+            free(__list);                                       \
+    }                                                           \
+    while (0)
+
+
+
+
+
+#if 0
+
+// TODO : REMME
+
+#define process_all_plugins_for_old__(a, f, ...)                  \
     do                                                      \
     {                                                       \
         size_t __count;                                     \
@@ -114,11 +134,13 @@ GPluginModule **get_all_plugins_for_action(PluginAction, size_t *);
 
 /* DPS_PG_MANAGEMENT */
 
+/*
 #define notify_native_plugins_loaded() \
-    process_all_plugins_for(PGA_NATIVE_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL)
+    process_all_plugins_for_old__(PGA_NATIVE_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL)
 
 #define notify_all_plugins_loaded() \
-    process_all_plugins_for(PGA_ALL_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL)
+    process_all_plugins_for_old__(PGA_ALL_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL)
+*/
 
 #define build_type_instance(t) \
     process_plugins_while_null(PGA_TYPE_BUILDING, g_plugin_module_build_type_instance, t)
@@ -126,44 +148,47 @@ GPluginModule **get_all_plugins_for_action(PluginAction, size_t *);
 /* DPS_SETUP */
 
 #define include_plugin_theme(d, r, c) \
-    process_all_plugins_for(PGA_GUI_THEME, g_plugin_module_include_theme, d, r, c)
+    process_all_plugins_for_old__(PGA_GUI_THEME, g_plugin_module_include_theme, d, r, c)
 
 /* DPS_RUNNING */
 
 #define notify_panel_creation(i) \
-    process_all_plugins_for(PGA_PANEL_CREATION, g_plugin_module_notify_panel_creation, i)
+    process_all_plugins_for_old__(PGA_PANEL_CREATION, g_plugin_module_notify_panel_creation, i)
 
 #define notify_panel_docking(i, d) \
-    process_all_plugins_for(PGA_PANEL_DOCKING, g_plugin_module_notify_panel_docking, i, d)
+    process_all_plugins_for_old__(PGA_PANEL_DOCKING, g_plugin_module_notify_panel_docking, i, d)
 
 /* DPS_CONTENT */
 
 #define handle_binary_content(a, c, i, s) \
-    process_all_plugins_for(a, g_plugin_module_handle_binary_content, c, i, s)
+    process_all_plugins_for_old__(a, g_plugin_module_handle_binary_content, c, i, s)
 
 #define handle_loaded_content(a, c, i, s) \
-    process_all_plugins_for(a, g_plugin_module_handle_loaded_content, c, i, s)
+    process_all_plugins_for_old__(a, g_plugin_module_handle_loaded_content, c, i, s)
 
 /* DPS_FORMAT */
 
 #define handle_known_format_analysis(a, f, g, s) \
-    process_all_plugins_for(a, g_plugin_module_handle_known_format_analysis, f, g, s)
+    process_all_plugins_for_old__(a, g_plugin_module_handle_known_format_analysis, f, g, s)
 
 #define preload_binary_format(a, f, i, s) \
-    process_all_plugins_for(a, g_plugin_module_preload_binary_format, f, i, s)
+    process_all_plugins_for_old__(a, g_plugin_module_preload_binary_format, f, i, s)
 
 #define attach_debug_format(f) \
-    process_all_plugins_for(PGA_FORMAT_ATTACH_DEBUG, g_plugin_module_attach_debug_format, f)
+    process_all_plugins_for_old__(PGA_FORMAT_ATTACH_DEBUG, g_plugin_module_attach_debug_format, f)
 
 /* DPS_DISASSEMBLY */
 
 #define process_disassembly_event(a, b, s, c) \
-    process_all_plugins_for(a, g_plugin_module_process_disassembly_event, b, s, c)
+    process_all_plugins_for_old__(a, g_plugin_module_process_disassembly_event, b, s, c)
 
 /* DPS_DETECTION */
 
 #define detect_external_tools(a, cnt, v, n, c) \
-    process_all_plugins_for(a, g_plugin_module_detect_external_tools, cnt, v, n, c)
+    process_all_plugins_for_old__(a, g_plugin_module_detect_external_tools, cnt, v, n, c)
+
+
+#endif
 
 
 
diff --git a/src/plugins/plugin-def.h b/src/plugins/plugin-def.h
index 1118140..b5e0b51 100644
--- a/src/plugins/plugin-def.h
+++ b/src/plugins/plugin-def.h
@@ -35,18 +35,6 @@
 /* ------------------------ IDENTIFICATION DE COMPATIBILITES ------------------------ */
 
 
-/* Version identifiant les définitions courantes */
-typedef uint32_t plugin_abi_version_t;
-
-#define DEFINE_PLUGIN_ABI_VERSION(maj, min, rev) \
-    (((maj & 0xff) << 24) | ((min & 0xff) << 16) | (rev & 0xffff))
-
-#define GET_ABI_MAJ_VERSION(vs) ((vs >> 24) & 0xff)
-#define GET_ABI_MIN_VERSION(vs) ((vs >> 16) & 0xff)
-#define GET_ABI_REV_VERSION(vs) (vs & 0xffff)
-
-#define CURRENT_ABI_VERSION DEFINE_PLUGIN_ABI_VERSION(0, 3, 0)
-
 
 
 /* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */
@@ -232,14 +220,14 @@ typedef enum _PluginAction
 /* ------------------------ PREMIER INTERFACAGE PROTOCOLAIRE ------------------------ */
 
 
-#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de1234abcdull
+//#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de1234abcdull
 
 
 /* Définition d'un greffon */
 typedef struct _plugin_interface
 {
     uint64_t magic;                         /* Vérification a minima       */
-    plugin_abi_version_t abi_version;       /* Version du protocole utilisé*/
+    uint32_t /*plugin_abi_version_t*/ abi_version;       /* Version du protocole utilisé*/
 
     /**
      * Les champs suivants ne sont généralement pas alloués dynamiquement,
diff --git a/src/plugins/plugin-int.h b/src/plugins/plugin-int.h
index 3ba19dc..07b455a 100644
--- a/src/plugins/plugin-int.h
+++ b/src/plugins/plugin-int.h
@@ -37,21 +37,28 @@
 #include "../common/bits.h"
 
 
-/* Transfert de la conscience de soi. */
-typedef void (* pg_set_self_fc) (GPluginModule *);
 
-/* Prend acte du [dé]chargement du greffon. */
+/* Pointe le fichier contenant le greffon manipulé. */
+typedef char * (* get_plugin_filename_fc) (const GPluginModule *);
+
+/* Fournit le nom brut associé au greffon. */
+typedef char * (* get_plugin_modname_fc) (const GPluginModule *);
+
+/* Prend acte de (l'|la dés)activation du greffon. */
 typedef bool (* pg_management_fc) (GPluginModule *);
 
+
+
+
+/* Transfert de la conscience de soi. */
+typedef void (* pg_set_self_fc) (GPluginModule *);
+
 /* Accompagne la fin du chargement des modules natifs. */
 typedef void (* pg_plugins_loaded_fc) (GPluginModule *, PluginAction);
 
 /* Crée une instance à partir d'un type dynamique externe. */
 typedef gpointer (* pg_build_instance_fc) (GPluginModule *, PluginAction, GType);
 
-/* Fournit le nom brut associé au greffon. */
-typedef char * (* pg_get_modname_fc) (const GPluginModule *);
-
 #if 0
 
 /* Procède à une opération liée à un contenu binaire. */
@@ -90,22 +97,47 @@ typedef void (* pg_detect_tools_fc) (const GPluginModule *, PluginAction, const
 #endif
 
 
+/* Marqueur identifiable */
+#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de
+
+
+/* Version identifiant les définitions courantes */
+typedef uint32_t plugin_abi_version_t;
+
+#define DEFINE_PLUGIN_ABI_VERSION(maj, min, rev) \
+    (((maj & 0xff) << 24) | ((min & 0xff) << 16) | (rev & 0xffff))
+
+#define GET_ABI_MAJ_VERSION(vs) ((vs >> 24) & 0xff)
+#define GET_ABI_MIN_VERSION(vs) ((vs >> 16) & 0xff)
+#define GET_ABI_REV_VERSION(vs) (vs & 0xffff)
+
+/**
+ * 0.3.0 : dernière version avec actions et fonctions associées
+ * 1.0.0 (04/01/25) : bascule en chargement d'objet et interfaces
+ */
+#define CURRENT_ABI_VERSION DEFINE_PLUGIN_ABI_VERSION(1, 0, 0)
+
+
 /* Greffon pour Chrysalide (instance) */
 struct _GPluginModule
 {
     GObject parent;                         /* A laisser en premier        */
 
-    char *filename;                         /* Fichier associé au greffon  */
-    GModule *module;                        /* Abstration de manipulation  */
+    uint32_t magic;                         /* Vérification a minima       */
+    plugin_abi_version_t abi_version;       /* Version du protocole utilisé*/
+
+    char *name;                             /* Désignation humaine courte  */
+    char *desc;                             /* Description plus loquace    */
+    char *version;                          /* Version du greffon          */
+    char *url;                              /* Site Web associé            */
 
-    const plugin_interface *interface;      /* Déclaration d'interfaçage   */
+    char **required;                        /* Pré-chargements requis      */
+    size_t required_count;                  /* Quantité de ces dépendances */
 
     PluginStatusFlags flags;                /* Fanion pour l'état courant  */
 
     bitfield_t *dependencies;               /* Cartographie des dépendances*/
 
-    //GGenConfig *config;                     /* Configuration dédiée        */
-
 };
 
 
@@ -114,6 +146,18 @@ struct _GPluginModuleClass
 {
     GObjectClass parent;                    /* A laisser en premier        */
 
+    get_plugin_filename_fc get_filename;    /* Obtention du chemin         */
+    get_plugin_modname_fc get_modname;      /* Fourniture du nom brut      */
+
+    pg_management_fc enable;                /* Procédure d'activation      */
+    pg_management_fc disable;               /* Procédure d'extinction      */
+
+
+
+    /////////////////////////////////////////////
+
+#if 0
+
     pg_management_fc init;                  /* Procédure d'initialisation  */
     pg_management_fc manage;                /* Etape dans la vie du greffon*/
     pg_management_fc exit;                  /* Procédure d'extinction      */
@@ -121,8 +165,6 @@ struct _GPluginModuleClass
     pg_plugins_loaded_fc plugins_loaded;    /* Fin des chargements         */
     pg_build_instance_fc build_instance;    /* Création d'objets           */
 
-    pg_get_modname_fc get_modname;          /* Fourniture du nom brut      */
-
 #if 0
 #ifdef INCLUDE_GTK_SUPPORT
     pg_include_theme_fc include_theme;      /* Extension d'un thème        */
@@ -141,12 +183,28 @@ struct _GPluginModuleClass
 
     pg_detect_tools_fc detect;              /* Lancement de détections     */
 #endif
+#endif
+
+    /////////////////////////////////////////////
+
 
 };
 
 
-/* Met en place la configuration dédiée au greffon. */
-void g_plugin_module_create_config(GPluginModule *);
+
+#define STORE_PLUGIN_ABI(p)                     \
+    do                                          \
+    {                                           \
+        GPluginModule *_p;                      \
+        _p = G_PLUGIN_MODULE(p);                \
+        _p->magic = CHRYSALIDE_PLUGIN_MAGIC;    \
+        _p->abi_version = CURRENT_ABI_VERSION;  \
+    }                                           \
+    while (0);
+
+
+/* Met en place un greffon. */
+bool g_plugin_module_create(GPluginModule *, const char *, const char *, const char *, const char *, const char * const *, size_t);
 
 
 
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index 75cf4e0..c537bc3 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -30,7 +30,6 @@
 #include <libgen.h>
 #include <malloc.h>
 #include <stdarg.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -38,6 +37,7 @@
 #include "dt.h"
 #include "pglist.h"
 #include "plugin-int.h"
+#include "../common/compiler.h"
 #include "../common/extstr.h"
 #include "../common/pathname.h"
 #include "../common/xdg.h"
@@ -56,19 +56,12 @@ static void g_plugin_module_dispose(GPluginModule *);
 /* Procède à la libération totale de la mémoire. */
 static void g_plugin_module_finalize(GPluginModule *);
 
-/* Initialise la classe des greffons d'extension. */
-static void g_plugin_module_init_gclass(GPluginModuleClass *, GModule *);
-
-/* Fournit le nom brut associé au greffon. */
-static char *_g_plugin_module_get_modname(const GPluginModule *);
-
 
 
 /* Indique le type défini pour un greffon. */
 G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT);
 
 
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : class = classe à initialiser.                                *
@@ -84,16 +77,17 @@ G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT);
 static void g_plugin_module_class_init(GPluginModuleClass *class)
 {
     GObjectClass *object;                   /* Autre version de la classe  */
-    GPluginModuleClass *plugin;             /* Version parente de la classe*/
 
     object = G_OBJECT_CLASS(class);
 
     object->dispose = (GObjectFinalizeFunc/* ! */)g_plugin_module_dispose;
     object->finalize = (GObjectFinalizeFunc)g_plugin_module_finalize;
 
-    plugin = G_PLUGIN_MODULE_CLASS(class);
+    class->get_filename = NULL;
+    class->get_modname = NULL;
 
-    plugin->get_modname = (pg_get_modname_fc)_g_plugin_module_get_modname;
+    class->enable = NULL;
+    class->disable = NULL;
 
 }
 
@@ -112,7 +106,17 @@ static void g_plugin_module_class_init(GPluginModuleClass *class)
 
 static void g_plugin_module_init(GPluginModule *plugin)
 {
-    //plugin->config = NULL;
+    plugin->name = NULL;
+    plugin->desc = NULL;
+    plugin->version = NULL;
+    plugin->url = NULL;
+
+    plugin->required = NULL;
+    plugin->required_count = 0;
+
+    plugin->flags = PSF_NONE;
+
+    plugin->dependencies = NULL;
 
 }
 
@@ -131,58 +135,35 @@ static void g_plugin_module_init(GPluginModule *plugin)
 
 static void g_plugin_module_dispose(GPluginModule *plugin)
 {
-    const plugin_interface *pg_iface;       /* Définition du greffon       */
     size_t i;                               /* Boucle de parcours          */
     GPluginModule *dependency;              /* Module nécessaire           */
     GPluginModuleClass *class;              /* Classe de l'instance active */
 
-    pg_iface = g_plugin_module_get_interface(plugin);
+    lock_plugin_list_for_reading();
 
-    if (pg_iface != NULL)
+    for (i = 0; i < plugin->required_count; i++)
     {
-        lock_plugin_list_for_reading();
+        dependency = get_plugin_by_name(plugin->required[i], NULL);
 
-        for (i = 0; i < pg_iface->required_count; i++)
+        /* Si le chargement a bien été complet avant la sortie... */
+        if (dependency != NULL)
         {
-            dependency = get_plugin_by_name(pg_iface->required[i], NULL);
+            /* Un coup pour l'appel à get_plugin_by_name(). */
+            unref_object(dependency);
 
-            /* Si le chargement a bien été complet avant la sortie... */
-            if (dependency != NULL)
-            {
-                /* Un coup pour l'appel à get_plugin_by_name(). */
-                g_object_unref(G_OBJECT(dependency));
-
-                /* Un coup pour la dépendance */
-                g_object_unref(G_OBJECT(dependency));
-
-            }
+            /* Un coup pour la dépendance */
+            unref_object(dependency);
 
         }
 
-        unlock_plugin_list_for_reading();
-
     }
 
-    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
+    unlock_plugin_list_for_reading();
 
-    if (class->exit != NULL)
-        class->exit(plugin);
-
-    /*
-    if (plugin->config != NULL)
-    {
-        g_generic_config_write(plugin->config);
-
-        g_clear_object(&plugin->config);
+    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
 
-    }
-    */
-
-    if (plugin->module != NULL)
-    {
-        g_module_close(plugin->module);
-        plugin->module = NULL;
-    }
+    if (class->disable != NULL)
+        class->disable(plugin);
 
     G_OBJECT_CLASS(g_plugin_module_parent_class)->dispose(G_OBJECT(plugin));
 
@@ -203,7 +184,25 @@ static void g_plugin_module_dispose(GPluginModule *plugin)
 
 static void g_plugin_module_finalize(GPluginModule *plugin)
 {
-    free(plugin->filename);
+    size_t i;                               /* Boucle de parcours          */
+
+    if (plugin->name != NULL)
+        free(plugin->name);
+
+    if (plugin->desc != NULL)
+        free(plugin->desc);
+
+    if  (plugin->version != NULL)
+        free(plugin->version);
+
+    if (plugin->url != NULL)
+        free(plugin->url);
+
+    for (i = 0; i < plugin->required_count; i++)
+        free(plugin->required[i]);
+
+    if (plugin->required != NULL)
+        free(plugin->required);
 
     if (plugin->dependencies != NULL)
         delete_bit_field(plugin->dependencies);
@@ -215,627 +214,173 @@ static void g_plugin_module_finalize(GPluginModule *plugin)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : filename = nom du fichier à charger.                         *
+*  Paramètres  : plugin   = instance à initialiser pleinement.                *
+*                name     = nom du greffon pour référence, principalement.    *
+*                desc     = présentation éventuelle à destination humaine.    *
+*                version  = indication de version éventuelle.                 *
+*                url      = référence vers une ressource en ligne.            *
+*                required = liste de dépendances éventuelles ou NULL.         *
+*                count    = taille de cette liste.                            *
 *                                                                             *
-*  Description : Crée un module pour un greffon donné.                        *
+*  Description : Met en place un greffon.                                     *
 *                                                                             *
-*  Retour      : Adresse de la structure mise en place.                       *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GPluginModule *g_plugin_module_new(const gchar *filename)
+bool g_plugin_module_create(GPluginModule *plugin, const char *name, const char *desc, const char *version, const char *url, const char * const *required, size_t count)
 {
-    GPluginModule *result;                  /* Structure à retourner       */
-    GModule *module;                        /* Abstration de manipulation  */
-    pg_set_self_fc set_self;                /* Copie du greffon            */
-    const plugin_interface *interface;      /* Déclaration d'interfaçage   */
-    plugin_abi_version_t current;           /* Version de l'ABI actuelle   */
-    bool valid;                             /* Statut de validité          */
-    size_t i;                               /* Boucle de parcours          */
-    uint32_t action;                        /* Identifiant d'une action    */
-    uint32_t category;                      /* Catégorie principale        */
-    uint32_t sub;                           /* Sous-catégorie visée        */
-    GType gtype;                            /* Nouveau type de greffon     */
-
-    module = g_module_open(filename, G_MODULE_BIND_LAZY);
-    if (module == NULL)
-    {
-        log_variadic_message(LMT_ERROR, 
-                             _("Error while loading the plugin candidate '%s' : %s"),
-                             filename, g_module_error());
-        goto bad_module;
-    }
-
-
-#define load_plugin_symbol(mod, sym, dest)                                          \
-    ({                                                                              \
-        bool __result;                                                              \
-        if (!g_module_symbol(mod, sym, (gpointer *)dest))                           \
-        {                                                                           \
-            log_variadic_message(LMT_ERROR,                                         \
-                                 _("No '%s' entry in plugin candidate '%s'"),       \
-                                 sym, filename);                                    \
-            __result = false;                                                       \
-        }                                                                           \
-        else __result = true;                                                       \
-        __result;                                                                   \
-    })
-
-
-    /* Récupération de la version d'ABI */
-
-    if (!load_plugin_symbol(module, "chrysalide_plugin_set_self", &set_self))
-        goto no_self_setter;
-
-    if (!load_plugin_symbol(module, "_chrysalide_plugin", &interface))
-        goto no_interface;
-
-    current = CURRENT_ABI_VERSION;
-
-    if (current != interface->abi_version)
-        goto wrong_abi;
-
-    /* Localisation des différents points d'entrée déclarés */
-
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours #1       */
+    size_t k;                               /* Boucle de parcours #2       */
 
-#define check_plugin_symbol(mod, sym)                                           \
-    ({                                                                          \
-        bool __result;                                                          \
-        __result = g_module_symbol(mod, sym, (gpointer []) { NULL });           \
-        if (!__result)                                                          \
-            log_variadic_message(LMT_ERROR,                                     \
-                                 _("No '%s' entry in plugin candidate '%s'"),   \
-                                 sym, filename);                                \
-        __result;                                                               \
-    })
+    /* Validations préalables */
 
+    assert(name != NULL);
 
-    valid = true;
+    result = (name != NULL);
 
-    for (i = 0; i < interface->actions_count && valid; i++)
+    if (result && plugin->abi_version != CURRENT_ABI_VERSION)
     {
-        action = interface->actions[i];
-        category = MASK_PLUGIN_CATEGORY(action);
-        sub = MASK_PLUGIN_SUB_CATEGORY(action);
-
-        switch (category)
-        {
-            case DPC_BASIC:
-
-                switch (sub)
-                {
-                    case DPS_NONE:
-                        break;
-
-                    case DPS_PG_MANAGEMENT:
-
-                        switch (action)
-                        {
-                            case PGA_PLUGIN_INIT:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_init");
-                                break;
-
-                            case PGA_PLUGIN_LOADED:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_manage");
-                                break;
-
-                            case PGA_PLUGIN_EXIT:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_exit");
-                                break;
-
-                            default:
-                                log_variadic_message(LMT_WARNING,
-                                                     _("Unknown action '0x%02x' in plugin '%s'..."),
-                                                     interface->actions[i], filename);
-                                break;
-
-                        }
-
-                        break;
-
-                    case DPS_CORE_MANAGEMENT:
-
-                        switch (action)
-                        {
-                            case PGA_NATIVE_PLUGINS_LOADED:
-                            case PGA_ALL_PLUGINS_LOADED:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_on_plugins_loaded");
-                                break;
-
-                            case PGA_TYPE_BUILDING:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_build_type_instance");
-                                break;
-
-                            default:
-                                log_variadic_message(LMT_WARNING,
-                                                     _("Unknown action '0x%02x' in plugin '%s'..."),
-                                                     interface->actions[i], filename);
-                                break;
-
-                        }
-
-                        break;
-
-                    default:
-                        log_variadic_message(LMT_WARNING,
-                                             _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename);
-                        break;
-
-                }
-
-                break;
-
-#if 0
-
-            case DPC_GUI:
-
-                switch (sub)
-                {
-                    case DPS_SETUP:
-
-                        switch (action)
-                        {
-                            case PGA_GUI_THEME:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_include_theme");
-                                break;
-
-                            default:
-                                log_variadic_message(LMT_WARNING,
-                                                     _("Unknown action '0x%02x' in plugin '%s'..."),
-                                                     interface->actions[i], filename);
-                                break;
-
-                        }
-
-                        break;
-
-                    case DPS_RUNNING:
-
-                        switch (action)
-                        {
-                            case PGA_PANEL_CREATION:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_on_panel_creation");
-                                break;
-
-                            case PGA_PANEL_DOCKING:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_on_panel_docking");
-                                break;
-
-                            default:
-                                log_variadic_message(LMT_WARNING,
-                                                     _("Unknown action '0x%02x' in plugin '%s'..."),
-                                                     interface->actions[i], filename);
-                                break;
-
-                        }
-
-                        break;
-
-                    default:
-                        log_variadic_message(LMT_WARNING,
-                                             _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename);
-                        break;
-
-                }
-
-                break;
-
-            case DPC_BINARY_PROCESSING:
-
-                switch (sub)
-                {
-                    case DPS_CONTENT:
-
-                        switch (action)
-                        {
-                            case PGA_CONTENT_EXPLORER:
-                            case PGA_CONTENT_RESOLVER:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_handle_binary_content");
-                                break;
+        result = false;
 
-                            case PGA_CONTENT_ANALYZED:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_handle_loaded_content");
-                                break;
+        log_variadic_message(LMT_ERROR, _("ABI mismatch detected: %08x (plugin) vs %08x (core)"),
+                             plugin->abi_version, CURRENT_ABI_VERSION);
 
-                            default:
-                                log_variadic_message(LMT_WARNING,
-                                                     _("Unknown action '0x%02x' in plugin '%s'..."),
-                                                     interface->actions[i], filename);
-                                break;
-
-                        }
-
-                        break;
-
-                    case DPS_FORMAT:
-
-                        switch (action)
-                        {
-                            case PGA_FORMAT_ANALYSIS_STARTED:
-                            case PGA_FORMAT_ANALYSIS_ENDED:
-                            case PGA_FORMAT_POST_ANALYSIS_STARTED:
-                            case PGA_FORMAT_POST_ANALYSIS_ENDED:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_handle_binary_format_analysis");
-                                break;
-
-                            case PGA_FORMAT_PRELOAD:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_preload_binary_format");
-                                break;
+    }
 
-                            case PGA_FORMAT_ATTACH_DEBUG:
-                                valid = check_plugin_symbol(module, "chrysalide_plugin_attach_debug");
-                                break;
+    /* Mémorisation des informations */
 
-                            default:
-                                log_variadic_message(LMT_WARNING,
-                                                     _("Unknown action '0x%02x' in plugin '%s'..."),
-                                                     interface->actions[i], filename);
-                                break;
+    if (result)
+    {
+        plugin->name = strdup(name);
 
-                        }
+        if (desc != NULL)
+            plugin->desc = strdup(desc);
 
-                        break;
+        if (version != NULL)
+            plugin->version = strdup(version);
 
-                    case DPS_DISASSEMBLY:
-                        valid = check_plugin_symbol(module, "chrysalide_plugin_process_disassembly_event");
-                        break;
+        if (url != NULL)
+            plugin->url = strdup(url);
 
-                    case DPS_DETECTION:
-                        valid = check_plugin_symbol(module, "chrysalide_plugin_detect_external_tools");
-                        break;
+        if (count > 0)
+        {
+            plugin->required = malloc(count * sizeof(char *));
+            plugin->required_count = 0;
 
-                    default:
-                        log_variadic_message(LMT_WARNING,
-                                             _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename);
+            for (i = 0; i < count; i++)
+            {
+                for (k = 0; k < plugin->required_count; k++)
+                    if (strcmp(required[i], plugin->required[k]) == 0)
                         break;
 
-                }
+                if (k < plugin->required_count)
+                    continue;
 
-#endif
+                plugin->required[plugin->required_count++] = strdup(required[i]);
 
-                break;
+            }
 
-            default:
-                log_variadic_message(LMT_WARNING,
-                                     _("Unknown category '0x%02x' in plugin '%s'..."), category, filename);
-                break;
+            plugin->required = realloc(plugin->required, plugin->required_count * sizeof(char *));
 
         }
 
     }
 
-    if (!valid)
-        goto missing_feature;
-
-    gtype = build_dynamic_type(G_TYPE_PLUGIN_MODULE, interface->gtp_name,
-                               (GClassInitFunc)g_plugin_module_init_gclass, module, NULL);
-
-    if (gtype == G_TYPE_INVALID)
-        goto no_instance;
-
-    result = g_object_new(gtype, NULL);
-
-    result->filename = strdup(filename);
-    result->module = module;
-
-    result->interface = interface;
-
-    set_self(result);
-
     return result;
 
- no_self_setter:
-
-    log_variadic_message(LMT_ERROR, _("Self pointer setter is missing for plugin '%s'"), filename);
-    goto bad_plugin;
-
- no_interface:
-
-    log_variadic_message(LMT_ERROR, _("Main interface is missing for plugin '%s'"), filename);
-    goto bad_plugin;
-
- wrong_abi:
-
-    log_variadic_message(LMT_ERROR, _("ABI mismatch detected! Plugin '%s' rejected"), filename);
-    goto bad_plugin;
-
- missing_feature:
-
-    log_variadic_message(LMT_ERROR, _("An expected feature is missing for plugin '%s'"), filename);
-    goto bad_plugin;
-
- no_instance:
-
-    log_variadic_message(LMT_ERROR, _("Unabled to create an instance of plugin '%s'"), filename);
-
- bad_plugin:
-
-    g_module_close(module);
-
- bad_module:
-
-    return NULL;
-
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : class  = classe à initialiser.                               *
-*                module = module représentant le greffon chargé en mémoire.   *
+*  Paramètres  : plugin = greffon à consulter.                                *
 *                                                                             *
-*  Description : Initialise la classe des greffons d'extension.               *
+*  Description : Indique le nom associé à un greffon.                         *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Désignation interne de l'extension, pour référence(s).       *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void g_plugin_module_init_gclass(GPluginModuleClass *class, GModule *module)
+const char *g_plugin_module_get_name(const GPluginModule *plugin)
 {
-    const plugin_interface *interface;      /* Déclaration d'interfaçage   */
-    size_t i;                               /* Boucle de parcours          */
-    uint32_t action;                        /* Identifiant d'une action    */
-    uint32_t category;                      /* Catégorie principale        */
-    uint32_t sub;                           /* Sous-catégorie visée        */
-
-
-#undef load_plugin_symbol
-
-#define load_plugin_symbol(mod, sym, dest)                          \
-    ({                                                              \
-        bool __result;                                              \
-        __result = g_module_symbol(mod, sym, (gpointer *)dest);     \
-        assert(__result);                                           \
-        __result;                                                   \
-    })
-
-
-    load_plugin_symbol(module, "_chrysalide_plugin", &interface);
-
-    for (i = 0; i < interface->actions_count; i++)
-    {
-        action = interface->actions[i];
-        category = MASK_PLUGIN_CATEGORY(action);
-        sub = MASK_PLUGIN_SUB_CATEGORY(action);
-
-        switch (category)
-        {
-            case DPC_BASIC:
-
-                switch (sub)
-                {
-                    case DPS_NONE:
-                        break;
-
-                    case DPS_PG_MANAGEMENT:
-
-                        switch (action)
-                        {
-                            case PGA_PLUGIN_INIT:
-                                load_plugin_symbol(module, "chrysalide_plugin_init", &class->init);
-                                break;
-
-                            case PGA_PLUGIN_LOADED:
-                                load_plugin_symbol(module, "chrysalide_plugin_manage", &class->manage);
-                                break;
-
-                            case PGA_PLUGIN_EXIT:
-                                load_plugin_symbol(module, "chrysalide_plugin_exit", &class->exit);
-                                break;
-
-                            default:
-                                assert(false);
-                                break;
-
-                        }
-
-                        break;
-
-                    case DPS_CORE_MANAGEMENT:
-
-                        switch (action)
-                        {
-                            case PGA_NATIVE_PLUGINS_LOADED:
-                            case PGA_ALL_PLUGINS_LOADED:
-                                load_plugin_symbol(module, "chrysalide_plugin_on_plugins_loaded",
-                                                   &class->plugins_loaded);
-                                break;
-
-                            case PGA_TYPE_BUILDING:
-                                load_plugin_symbol(module, "chrysalide_plugin_build_type_instance",
-                                                   &class->build_instance);
-                                break;
-
-                            default:
-                                assert(false);
-                                break;
-
-                        }
-
-                        break;
-
-                    default:
-                        assert(false);
-                        break;
-
-                }
-
-                break;
-#if 0
-            case DPC_GUI:
-
-                switch (sub)
-                {
-                    case DPS_SETUP:
-
-                        switch (action)
-                        {
-                            case PGA_GUI_THEME:
-#ifdef INCLUDE_GTK_SUPPORT
-                                load_plugin_symbol(module, "chrysalide_plugin_include_theme",
-                                                   &class->include_theme);
-#endif
-                                break;
-
-                            default:
-                                assert(false);
-                                break;
-
-                        }
-
-                        break;
-
-                    case DPS_RUNNING:
-
-                        switch (action)
-                        {
-                            case PGA_PANEL_CREATION:
-#ifdef INCLUDE_GTK_SUPPORT
-                                load_plugin_symbol(module, "chrysalide_plugin_on_panel_creation",
-                                                   &class->notify_panel);
-#endif
-                                break;
-
-                            case PGA_PANEL_DOCKING:
-#ifdef INCLUDE_GTK_SUPPORT
-                                load_plugin_symbol(module, "chrysalide_plugin_on_panel_docking",
-                                                   &class->notify_docking);
-#endif
-                                break;
-
-                            default:
-                                assert(false);
-                                break;
-
-                        }
-
-                        break;
+    const char *result;                     /* Valeur finale à renvoyer    */
 
-                    default:
-                        assert(false);
-                        break;
-
-                }
-
-                break;
-
-            case DPC_BINARY_PROCESSING:
-
-                switch (sub)
-                {
-                    case DPS_CONTENT:
-
-                        switch (action)
-                        {
-                            case PGA_CONTENT_EXPLORER:
-                            case PGA_CONTENT_RESOLVER:
-                                load_plugin_symbol(module, "chrysalide_plugin_handle_binary_content",
-                                                   &class->handle_content);
-                                break;
-
-                            case PGA_CONTENT_ANALYZED:
-                                load_plugin_symbol(module, "chrysalide_plugin_handle_loaded_content",
-                                                   &class->handle_loaded);
-                                break;
-
-                            default:
-                                assert(false);
-                                break;
-
-                        }
-
-                        break;
-
-                    case DPS_FORMAT:
+    result = plugin->name;
 
-                        switch (action)
-                        {
-                            case PGA_FORMAT_ANALYSIS_STARTED:
-                            case PGA_FORMAT_ANALYSIS_ENDED:
-                            case PGA_FORMAT_POST_ANALYSIS_STARTED:
-                            case PGA_FORMAT_POST_ANALYSIS_ENDED:
-                                load_plugin_symbol(module, "chrysalide_plugin_handle_binary_format_analysis",
-                                                   &class->handle_fmt_analysis);
-                                break;
-
-                            case PGA_FORMAT_PRELOAD:
-                                load_plugin_symbol(module, "chrysalide_plugin_preload_binary_format", &class->preload_format);
-                                break;
-
-                            case PGA_FORMAT_ATTACH_DEBUG:
-                                load_plugin_symbol(module, "chrysalide_plugin_attach_debug", &class->attach_debug);
-                                break;
+    return result;
 
-                            default:
-                                assert(false);
-                                break;
+}
 
-                        }
 
-                        break;
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                                                                             *
+*  Description : Fournit une description fonctionnelle d'un greffon.          *
+*                                                                             *
+*  Retour      : Description textuelle associée à une extension ou NULL.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-                    case DPS_DISASSEMBLY:
-                        load_plugin_symbol(module, "chrysalide_plugin_process_disassembly_event", &class->process_disass);
-                        break;
+const char *g_plugin_module_get_desc(const GPluginModule *plugin)
+{
+    const char *result;                     /* Valeur finale à renvoyer    */
 
-                    case DPS_DETECTION:
-                        load_plugin_symbol(module, "chrysalide_plugin_detect_external_tools", &class->detect);
-                        break;
+    result = plugin->desc;
 
-                    default:
-                        assert(false);
-                        break;
+    return result;
 
-                }
+}
 
-#endif
 
-                break;
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                                                                             *
+*  Description : Fournit la version d'un greffon et de ses fonctionnalités.   *
+*                                                                             *
+*  Retour      : Version sous forme de chaîne de caractères ou NULL.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-            default:
-                assert(false);
-                break;
+const char *g_plugin_module_get_version(const GPluginModule *plugin)
+{
+    const char *result;                     /* Valeur finale à renvoyer    */
 
-        }
+    result = plugin->version;
 
-    }
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à valider.                                  *
+*  Paramètres  : plugin = greffon à consulter.                                *
 *                                                                             *
-*  Description : Fournit le nom brut associé au greffon.                      *
+*  Description : Fournit l'URL des ressources en ligne liées à un greffon.    *
 *                                                                             *
-*  Retour      : Désignation brute du greffon.                                *
+*  Retour      : URL de renvoi associée à une extension ou NULL.              *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-char *g_plugin_module_get_modname(const GPluginModule *plugin)
+const char *g_plugin_module_get_url(const GPluginModule *plugin)
 {
-    char *result;                           /* Désignation brute à renvoyer*/
-    GPluginModuleClass *class;              /* Classe de l'instance active */
-
-    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
-
-    result = class->get_modname(plugin);
+    const char *result;                     /* Valeur finale à renvoyer    */
 
-    /**
-     * Tente une opération de la dernière chance.
-     *
-     * Dans le cas d'un module Python, la fonction de classe peut ne pas
-     * trouver de support si l'extension Python n'est pas au point.
-     */
-    if (result == NULL && class->get_modname != _g_plugin_module_get_modname)
-        result = _g_plugin_module_get_modname(plugin);
+    result = plugin->url;
 
     return result;
 
@@ -844,41 +389,24 @@ char *g_plugin_module_get_modname(const GPluginModule *plugin)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à valider.                                  *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                count  = taille de la liste fournie. [OUT]                   *
 *                                                                             *
-*  Description : Fournit le nom brut associé au greffon.                      *
+*  Description : Fournit la liste des dépendances d'un greffon donné.         *
 *                                                                             *
-*  Retour      : Désignation brute du greffon.                                *
+*  Retour      : Liste des noms d'extensions requises pour une extension.     *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static char *_g_plugin_module_get_modname(const GPluginModule *plugin)
+const char * const *g_plugin_module_get_requirements(const GPluginModule *plugin, size_t *count)
 {
-    char *result;                           /* Désignation brute à renvoyer*/
-    char *path;                             /* Chemin à traiter            */
-    char *filename;                         /* Nom de bibliothèque partagée*/
-    size_t length;                          /* Taille du nom               */
-
-    path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin)));
-
-    filename = basename(path);
-
-    if (strncmp(filename, "lib", 3) == 0)
-        filename += 3;
-
-    length = strlen(filename);
-
-    if (length >= 3)
-    {
-        if (strncmp(&filename[length - 3], ".so", 3) == 0)
-            filename[length - 3] = '\0';
-    }
+    const char * const *result;             /* Valeur finale à renvoyer    */
 
-    result = strdup(filename);
+    result = CONST_ARRAY_CAST(plugin->required, char);
 
-    free(path);
+    *count = plugin->required_count;
 
     return result;
 
@@ -889,7 +417,7 @@ static char *_g_plugin_module_get_modname(const GPluginModule *plugin)
 *                                                                             *
 *  Paramètres  : plugin = greffon à consulter.                                *
 *                                                                             *
-*  Description : Indique le fichier contenant le greffon manipulé.            *
+*  Description : Pointe le fichier contenant le greffon manipulé.             *
 *                                                                             *
 *  Retour      : Chemin d'accès au greffon.                                   *
 *                                                                             *
@@ -897,28 +425,42 @@ static char *_g_plugin_module_get_modname(const GPluginModule *plugin)
 *                                                                             *
 ******************************************************************************/
 
-const char *g_plugin_module_get_filename(const GPluginModule *plugin)
+char *g_plugin_module_get_filename(const GPluginModule *plugin)
 {
-    return plugin->filename;
+    char *result;                           /* Chemin d'accès à renvoyer   */
+    GPluginModuleClass *class;              /* Classe de l'instance active */
+
+    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
+
+    result = class->get_filename(plugin);
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à consulter.                                *
+*  Paramètres  : plugin = greffon à valider.                                  *
 *                                                                             *
-*  Description : Fournit la description du greffon dans son intégralité.      *
+*  Description : Fournit le nom brut associé au greffon.                      *
 *                                                                             *
-*  Retour      : Interfaçage renseigné.                                       *
+*  Retour      : Désignation brute du greffon.                                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-const plugin_interface *g_plugin_module_get_interface(const GPluginModule *plugin)
+char *g_plugin_module_get_modname(const GPluginModule *plugin)
 {
-    return plugin->interface;
+    char *result;                           /* Désignation brute à renvoyer*/
+    GPluginModuleClass *class;              /* Classe de l'instance active */
+
+    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
+
+    result = class->get_modname(plugin);
+
+    return result;
 
 }
 
@@ -979,7 +521,6 @@ void g_plugin_module_override_flags(GPluginModule *plugin, PluginStatusFlags fla
 bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule **list, size_t count)
 {
     bool result;                            /* Bilan à faire remonter      */
-    const plugin_interface *pg_iface;       /* Définition du greffon       */
     bitfield_t *new;                        /* Nouvelle définition         */
     size_t i;                               /* Boucle de parcours          */
     GPluginModule *dependency;              /* Module nécessaire           */
@@ -997,15 +538,13 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *
 
     if ((plugin->flags & (PSF_UNKNOW_DEP | PSF_DEP_LOOP)) == 0)
     {
-        pg_iface = g_plugin_module_get_interface(plugin);
-
         /* Collecte des dépendances */
 
         new = dup_bit_field(plugin->dependencies);
 
-        for (i = 0; i < pg_iface->required_count; i++)
+        for (i = 0; i < plugin->required_count; i++)
         {
-            dependency = get_plugin_by_name(pg_iface->required[i], &index);
+            dependency = get_plugin_by_name(plugin->required[i], &index);
 
             if (dependency == NULL)
                 plugin->flags |= PSF_UNKNOW_DEP;
@@ -1023,7 +562,7 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *
                  */
 
                 if (test_in_bit_field(plugin->dependencies, index))
-                    g_object_unref(G_OBJECT(dependency));
+                    unref_object(dependency);
 
             }
 
@@ -1041,13 +580,14 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *
 
         /* Vérification sanitaire */
 
-        dependency = get_plugin_by_name(pg_iface->name, &index);
+        dependency = get_plugin_by_name(plugin->name, &index);
         assert(dependency != NULL);
+        assert(dependency == plugin);
 
         if (test_in_bit_field(plugin->dependencies, index))
             plugin->flags |= PSF_DEP_LOOP;
 
-        g_object_unref(G_OBJECT(dependency));
+        unref_object(dependency);
 
 
     }
@@ -1075,12 +615,12 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co
 {
     bool result;                            /* Bilan à retourner           */
     PluginStatusFlags flags;                /* Fanions de greffon          */
-    const plugin_interface *pg_iface;       /* Définition du greffon       */
     size_t i;                               /* Boucle de parcours          */
     GPluginModule *dependency;              /* Module nécessaire           */
+    char *filename;                         /* Chemin d'accès au greffon   */
     GPluginModuleClass *class;              /* Classe de l'instance active */
-    //GGenConfig *config;                     /* Configuration à charger     */
-    char *dir;                              /* Répertoire modifiable       */
+    char *tmp;                              /* Chaîne modifiable           */
+    char *dir;                              /* Pointeur vers répertoire    */
 
     /* Si un essai précédent a déjà échoué ou réussi... */
 
@@ -1092,40 +632,41 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co
 
     /* Chargement des dépendances */
 
-    pg_iface = g_plugin_module_get_interface(plugin);
-
     result = true;
 
-    for (i = 0; i < pg_iface->required_count && result; i++)
+    filename = g_plugin_module_get_filename(plugin);
+
+    for (i = 0; i < plugin->required_count && result; i++)
     {
-        dependency = get_plugin_by_name(pg_iface->required[i], NULL);
+        dependency = get_plugin_by_name(plugin->required[i], NULL);
         assert(dependency != NULL);
 
         result = g_plugin_module_load(dependency, list, count);
 
-        g_object_unref(G_OBJECT(dependency));
+        unref_object(dependency);
 
     }
 
     if (!result)
     {
-        log_variadic_message(LMT_ERROR,
-                             _("Some dependencies failed to load for plugin '%s'"), plugin->filename);
+        log_variadic_message(LMT_ERROR, _("Some dependencies failed to load for plugin '%s'"), filename);
+
+        plugin->flags |= PSF_FAILURE;
         goto failure;
+
     }
 
     /* Chargement du greffon courant */
 
     class = G_PLUGIN_MODULE_GET_CLASS(plugin);
 
-    if (class->init != NULL)
+    if (class->enable != NULL)
     {
-        result = class->init(plugin);
+        result = class->enable(plugin);
 
         if (!result)
         {
-            log_variadic_message(LMT_ERROR,
-                                 _("Plugin '%s' failed to load itself..."), plugin->filename);
+            log_variadic_message(LMT_ERROR, _("Plugin '%s' failed to load itself..."), filename);
 
             plugin->flags |= PSF_FAILURE;
             goto failure;
@@ -1134,39 +675,23 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co
 
     }
 
-    g_plugin_module_create_config(plugin);
-
-    result = g_plugin_module_manage(plugin, PGA_PLUGIN_LOADED);
+    /* Message de bilan */
 
-    if (!result)
-    {
-        log_variadic_message(LMT_ERROR,
-                             _("Plugin '%s' failed to complete loading..."), plugin->filename);
-
-        plugin->flags |= PSF_FAILURE;
-        goto failure;
-
-    }
-
-    /*
-    config = g_plugin_module_get_config(plugin);
-    g_generic_config_read(config);
-    g_object_unref(G_OBJECT(config));
-    */
-
-    dir = strdup(plugin->filename);
-    dir = dirname(dir);
+    tmp = strdup(filename);
+    dir = dirname(tmp);
 
     log_variadic_message(LMT_PROCESS,
                          _("Loaded the '<b>%s</b>' file as plugin from the '<b>%s</b>' directory"),
-                         strrchr(plugin->filename, G_DIR_SEPARATOR) + 1, dir);
+                         strrchr(filename, G_DIR_SEPARATOR) + 1, dir);
 
-    free(dir);
+    free(tmp);
 
     plugin->flags |= PSF_LOADED;
 
  failure:
 
+    free(filename);
+
     return result;
 
 }
@@ -1227,31 +752,6 @@ char *g_plugin_module_build_config_filename(const GPluginModule *plugin, const c
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : plugin = greffon à compléter.                                *
-*                                                                             *
-*  Description : Met en place la configuration dédiée au greffon.             *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_plugin_module_create_config(GPluginModule *plugin)
-{
-    char *filename;                         /* Chemin d'accès particulier  */
-
-    filename = g_plugin_module_build_config_filename(plugin, "config.xml", false);
-
-    //plugin->config = g_generic_config_new_from_file(filename);
-
-    free(filename);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : plugin = greffon à consulter.                                *
 *                                                                             *
 *  Description : Fournit la configuration mise en place pour le greffon.      *
@@ -1295,11 +795,11 @@ void g_plugin_module_log_simple_message(const GPluginModule *plugin, LogMessageT
     size_t len;                             /* Taille tampon disponible    */
     char *buffer;                           /* Tampon du msg reconstitué   */
 
-    len = 4 + strlen(plugin->interface->name) + 6 + strlen(msg) + 1;
+    len = 4 + strlen(plugin->name) + 6 + strlen(msg) + 1;
     buffer = calloc(len, sizeof(char));
 
     strcpy(buffer, "<i>[");
-    strcat(buffer, plugin->interface->name);
+    strcat(buffer, plugin->name);
     strcat(buffer, "]</i> ");
     strcat(buffer, msg);
 
@@ -1345,80 +845,12 @@ void g_plugin_module_log_variadic_message(const GPluginModule *plugin, LogMessag
 }
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                                                                             *
-*  Description : Encadre une étape de la vie d'un greffon.                    *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool g_plugin_module_manage(GPluginModule *plugin, PluginAction action)
-{
-    bool result;                            /* Bilan à faire remonter      */
-    GPluginModuleClass *class;              /* Classe de l'instance active */
-    const plugin_interface *pg_iface;       /* Informations à consulter    */
-    size_t i;                               /* Boucle de parcours          */
-    bool handle_action;                     /* Action supportée ?          */
-
-    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
-
-    if (class->manage == NULL)
-        result = true;
-
-    else
-    {
-        handle_action = false;
-
-        pg_iface = g_plugin_module_get_interface(plugin);
-
-        for (i = 0; i < pg_iface->actions_count; i++)
-            if (pg_iface->actions[i] == PGA_PLUGIN_LOADED)
-            {
-                handle_action = true;
-                break;
-            }
-
-        if (handle_action)
-            result = class->manage(plugin/*, action*/);
-        else
-            result = true;
-
-    }
-
-    return result;
-
-}
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                unused = variable non utilisé pour l'usage de __VA_ARGS__.   *
-*                                                                             *
-*  Description : Accompagne la fin du chargement des modules.                 *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_plugin_module_notify_plugins_loaded(GPluginModule *plugin, PluginAction action, void *unused)
-{
-    GPluginModuleClass *class;              /* Classe de l'instance active */
 
-    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
 
-    class->plugins_loaded(plugin, action);
 
-}
+#if 0
 
 
 /******************************************************************************
@@ -1450,8 +882,6 @@ gpointer g_plugin_module_build_type_instance(GPluginModule *plugin, PluginAction
 
 
 
-#if 0
-
 #ifdef INCLUDE_GTK_SUPPORT
 
 
diff --git a/src/plugins/plugin.h b/src/plugins/plugin.h
index 5c473b2..a4cc388 100644
--- a/src/plugins/plugin.h
+++ b/src/plugins/plugin.h
@@ -52,6 +52,27 @@
 DECLARE_GTYPE(GPluginModule, g_plugin_module, G, PLUGIN_MODULE);
 
 
+/* Indique le nom associé à un greffon. */
+const char *g_plugin_module_get_name(const GPluginModule *);
+
+/* Fournit une description fonctionnelle d'un greffon. */
+const char *g_plugin_module_get_desc(const GPluginModule *);
+
+/* Fournit la version d'un greffon et de ses fonctionnalités. */
+const char *g_plugin_module_get_version(const GPluginModule *);
+
+/* Fournit l'URL des ressources en ligne liées à un greffon. */
+const char *g_plugin_module_get_url(const GPluginModule *);
+
+/* Fournit la liste des dépendances d'un greffon donné. */
+const char * const *g_plugin_module_get_requirements(const GPluginModule *, size_t *);
+
+/* Pointe le fichier contenant le greffon manipulé. */
+char *g_plugin_module_get_filename(const GPluginModule *);
+
+/* Fournit le nom brut associé au greffon. */
+char *g_plugin_module_get_modname(const GPluginModule *);
+
 /* Fanions indiquant le statut du greffon */
 typedef enum _PluginStatusFlags
 {
@@ -66,19 +87,6 @@ typedef enum _PluginStatusFlags
 
 #define BROKEN_PLUGIN_STATUS (PSF_UNKNOW_DEP | PSF_DEP_LOOP | PSF_FAILURE)
 
-
-/* Crée un module pour un greffon donné. */
-GPluginModule *g_plugin_module_new(const gchar *);
-
-/* Fournit le nom brut associé au greffon. */
-char *g_plugin_module_get_modname(const GPluginModule *);
-
-/* Indique le fichier contenant le greffon manipulé. */
-const char *g_plugin_module_get_filename(const GPluginModule *);
-
-/* Fournit la description du greffon dans son intégralité. */
-const plugin_interface *g_plugin_module_get_interface(const GPluginModule *);
-
 /* Fournit des indications sur l'état du greffon. */
 PluginStatusFlags g_plugin_module_get_flags(const GPluginModule *);
 
@@ -103,17 +111,12 @@ void g_plugin_module_log_simple_message(const GPluginModule *, LogMessageType, c
 /* Présente dans le journal un message complexe. */
 void g_plugin_module_log_variadic_message(const GPluginModule *, LogMessageType, const char *, ...);
 
-/* Encadre une étape de la vie d'un greffon. */
-bool g_plugin_module_manage(GPluginModule *, PluginAction);
 
-/* Accompagne la fin du chargement des modules natifs. */
-void g_plugin_module_notify_plugins_loaded(GPluginModule *, PluginAction, void *);
+#if 0
 
 /* Crée une instance à partir d'un type dynamique externe. */
 gpointer g_plugin_module_build_type_instance(GPluginModule *, PluginAction, GType);
 
-#if 0
-
 #ifdef INCLUDE_GTK_SUPPORT
 
 /* Complète une liste de resources pour thème. */
diff --git a/src/plugins/self.h b/src/plugins/self.h
index 4d5ddb0..78a3fe6 100644
--- a/src/plugins/self.h
+++ b/src/plugins/self.h
@@ -1,8 +1,8 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * self.h - définitions pour inclusion dans les différents greffons
+ * self.h - définitions de fonctionnalités facilitant la mise en place d'extensions natives
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -26,72 +26,55 @@
 #define _PLUGINS_SELF_H
 
 
-#ifndef _PLUGINS_PLUGIN_H
-#   include "plugin.h"
-#endif
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "plugin.h"
 #include "../common/compiler.h"
 
 
 
-/* Facilitations de déclarations */
+/* Symboles principaux */
+
+#define PLUGIN_CORE_SELF                                                        \
+static GPluginModule *_this_plugin = NULL;                                      \
+static void chrysalide_plugin_set_self(GPluginModule *);                        \
+static void chrysalide_plugin_set_self(GPluginModule *plugin)                   \
+{                                                                               \
+    assert(_this_plugin == NULL);                                               \
+    _this_plugin = plugin;                                                      \
+};                                                                              \
+__private GPluginModule *_chrysalide_plugin_get_self(void);                     \
+__private GPluginModule *_chrysalide_plugin_get_self(void)                      \
+{                                                                               \
+    return _this_plugin;                                                        \
+};
+
+#define NATIVE_PLUGIN_ENTRYPOINT(fc)                                            \
+PLUGIN_CORE_SELF;                                                               \
+G_MODULE_EXPORT GPluginModule *get_chrysalide_plugin_instance(GModule *);       \
+G_MODULE_EXPORT GPluginModule *get_chrysalide_plugin_instance(GModule *module)  \
+{                                                                               \
+    GPluginModule *result;                  /* Instance à retourner        */   \
+    result = fc(module);                                                        \
+    chrysalide_plugin_set_self(result);                                         \
+    return result;                                                              \
+}
+
+
+/* Spécifications */
 
 #define CHRYSALIDE_WEBSITE(p) "https://www.chrysalide.re/" p
 
-#define EMPTY_PG_LIST(name)                         \
-    name = NULL,                                    \
-    name ## _count = 0                              \
-
-#define BUILD_PG_LIST(name, lst)                    \
-    name = lst,                                     \
-    name ## _count = sizeof(lst) / sizeof(lst[0])   \
-
-#define AL(...) BUILD_PG_LIST(.actions, ((plugin_action_t []){ __VA_ARGS__ }))
-
-#define RL(...) BUILD_PG_LIST(.required, ((char *[]){ __VA_ARGS__ }))
-
-#define NO_REQ EMPTY_PG_LIST(.required)
-
-
-/* Composants d'interface */
-
-#define PLUGIN_CORE_SELF                                                                    \
-static GPluginModule *_this_plugin = NULL;                                                  \
-G_MODULE_EXPORT void chrysalide_plugin_set_self(GPluginModule *p);                          \
-G_MODULE_EXPORT void chrysalide_plugin_set_self(GPluginModule *p) { _this_plugin = p; };    \
-__private GPluginModule *_chrysalide_plugin_get_self(void);                                 \
-__private GPluginModule *_chrysalide_plugin_get_self(void) { return _this_plugin; };
-
-#define PLUGIN_CORE_PROPS(n, d, v, u, c)                        \
-                                                                \
-    .magic = CHRYSALIDE_PLUGIN_MAGIC,                           \
-    .abi_version = CURRENT_ABI_VERSION,                         \
-                                                                \
-    .gtp_name = "G" n "Plugin",                                 \
-    .name = n,                                                  \
-    .desc = d,                                                  \
-    .version = v,                                               \
-    .url = u,                                                   \
-                                                                \
-    .container = c
-
-#define DEFINE_CHRYSALIDE_PLUGIN(n, d, v, u, r, a)              \
-PLUGIN_CORE_SELF                                                \
-G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = {   \
-    PLUGIN_CORE_PROPS(n, d, v, u, false),                       \
-    r,                                                          \
-    a,                                                          \
-}
+#define NO_REQ NULL, 0
 
-#define DEFINE_CHRYSALIDE_CONTAINER_PLUGIN(n, d, v, u, r, a)    \
-PLUGIN_CORE_SELF                                                \
-G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = {   \
-    PLUGIN_CORE_PROPS(n, d, v, u, true),                        \
-    r,                                                          \
-    a,                                                          \
-}
+#define BUILD_PG_LIST(lst) lst, sizeof(lst) / sizeof(lst[0])
+
+#define REQ_LIST(...) BUILD_PG_LIST((const char *[]){ __VA_ARGS__ })
 
 
-/* Manipulations accélérées */
+/* Journalisation */
 
 __private GPluginModule *_chrysalide_plugin_get_self(void);
 
diff --git a/tests/plugins/plugin.py b/tests/plugins/plugin.py
index 6409975..9015409 100644
--- a/tests/plugins/plugin.py
+++ b/tests/plugins/plugin.py
@@ -1,223 +1,96 @@
-#!/usr/bin/python3-dbg
-# -*- coding: utf-8 -*-
-
 
 from chrysacase import ChrysalideTestCase
-from pychrysalide import PluginModule
-import gc
+from pychrysalide.plugins import PluginModule
 
 
 class TestPlugin(ChrysalideTestCase):
     """TestCase for GPluginModule."""
 
 
-    def testGarbageCollecting(self):
-        """Ensure the garbarge collector is working for plugin modules."""
-
+    def testPluginInfoImplementations(self):
+        """Retrieve plugin basic information provided by __init__()."""
 
-        class MyPG_1(PluginModule):
+        class MyPlugin(PluginModule):
 
             def __init__(self):
+                super().__init__('custom-name', desc='custom-desc', url='custom-url', version='0.0.1')
 
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
+        my = MyPlugin()
 
-                super(MyPG_1, self).__init__(**interface)
+        self.assertEqual(my.name, 'custom-name')
+        self.assertEqual(my.desc, 'custom-desc')
+        self.assertEqual(my.version, '0.0.1')
+        self.assertEqual(my.url, 'custom-url')
 
 
-        pg = MyPG_1()
-        self.assertIsNotNone(pg)
+    def testPluginMethodImplementations(self):
+        """Ensure required plugins abstract methods can be implemented."""
 
-
-        class MyPG_2(PluginModule):
+        class MyWrongPlugin(PluginModule):
 
             def __init__(self):
+                super().__init__('pg-name')
 
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
-
-                super(MyPG_2, self).__init__(**interface)
+        my = MyWrongPlugin()
 
+        with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_get_filename'"):
+            print(my.filename)
 
-        pg = MyPG_2()
-        self.assertIsNotNone(pg)
+        with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_get_modname'"):
+            print(my.modname)
 
 
-        class MyPG_3(PluginModule):
+        class MyPlugin(PluginModule):
 
             def __init__(self):
+                super().__init__('pg-name')
 
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
+            def _get_filename(self):
+                return 'file-name'
 
-                super(MyPG_3, self).__init__(**interface)
+            def _get_modname(self):
+                return 'mod-name'
 
+        my = MyPlugin()
 
-        pg = MyPG_3()
-        self.assertIsNotNone(pg)
+        self.assertEqual(my.filename, 'file-name')
 
+        self.assertEqual(my.modname, 'mod-name')
 
-        class MyPG_4(PluginModule):
-
-            def __init__(self):
-
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
 
-                super(MyPG_4, self).__init__(**interface)
+    def testPluginRequirementIncludePython(self):
+        """Ensure that plugin requirements include the Python bindings."""
 
-
-        pg = MyPG_4()
-        self.assertIsNotNone(pg)
-
-
-        class MyPG_5(PluginModule):
+        class MyPlugin(PluginModule):
 
             def __init__(self):
+                super().__init__('pg-name')
 
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
-
-                super(MyPG_5, self).__init__(**interface)
-
-
-        pg = MyPG_5()
-        self.assertIsNotNone(pg)
+        my = MyPlugin()
 
+        self.assertEqual(len(my.requirements), 1)
+        self.assertEqual(my.requirements[0], 'PyChrysalide')
 
-        gc.collect()
 
+    def testPluginRequirementUniqueness(self):
+        """Ensure that plugin requirements are unique."""
 
-    def testCreation(self):
-        """Validate PluginModule creation from Python."""
-
-
-        class MyPG_0(PluginModule):
-            pass
-
-
-        # TypeError: Required argument 'name' (pos 1) not found
-        with self.assertRaises(TypeError):
-            pg = MyPG_0()
-
-
-        class MyPG_1(PluginModule):
+        class MyPlugin(PluginModule):
 
             def __init__(self):
+                super().__init__('pg-name', required=[ 'PyChrysalide' ])
 
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
-
-                super(MyPG_1, self).__init__(**interface)
+        my = MyPlugin()
 
+        self.assertEqual(my.requirements.count('PyChrysalide'), 1)
 
-        pg = MyPG_1()
-        self.assertIsNotNone(pg)
 
-
-        class MyPG_2(PluginModule):
+        class MyPlugin2(PluginModule):
 
             def __init__(self):
+                super().__init__('pg-name2', required=[ 'AA', 'BB', 'AA' ])
 
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( 'ABC', )
-                }
-
-                super(MyPG_2, self).__init__(**interface)
-
-
-        # TypeError: Invalid type for plugin action.
-        with self.assertRaises(TypeError):
-            pg = MyPG_2()
-
-
-        class MyPG_3(PluginModule):
-
-            def __init__(self):
-
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( PluginModule.PGA_CONTENT_EXPLORER, )
-                }
-
-                super(MyPG_3, self).__init__(**interface)
-
-
-        # TypeError: missing features for the declared actions.
-        with self.assertRaises(TypeError):
-            pg = MyPG_3()
-
-
-        class MyPG_4(PluginModule):
-
-            def __init__(self):
-
-                interface = {
-                    'name' : 'some_name4',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( PluginModule.PGA_CONTENT_EXPLORER, )
-                }
-
-                super(MyPG_4, self).__init__(**interface)
-
-            def handle_binary_content(self, action, content, wid, status):
-                pass
-
-
-        pg = MyPG_4()
-        self.assertIsNotNone(pg)
-
-
-    def testDoubleUsage(self):
-        """Validate PluginModule double usage in Python."""
-
-
-        class MyPG(PluginModule):
-
-            def __init__(self):
-
-                interface = {
-                    'name' : 'some_name',
-                    'desc' : 'Provide some information about the useless plugin',
-                    'version' : '0.1',
-                    'actions' : ( )
-                }
-
-                super(MyPG, self).__init__(**interface)
-
-
-        pg1 = MyPG()
-        self.assertIsNotNone(pg1)
+        my = MyPlugin2()
 
-        pg2 = MyPG()
-        self.assertIsNotNone(pg2)
+        self.assertEqual(my.requirements.count('AA'), 1)
+        self.assertEqual(my.requirements.count('PyChrysalide'), 1)
diff --git a/tests/plugins/python.py b/tests/plugins/python.py
new file mode 100644
index 0000000..1a3dd97
--- /dev/null
+++ b/tests/plugins/python.py
@@ -0,0 +1,27 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.plugins import PythonPlugin
+
+
+class TestPlugin(ChrysalideTestCase):
+    """TestCase for GPythonPlugin."""
+
+
+    def testPluginInfoImplementations(self):
+        """Retrieve plugin basic information provided by __init__()."""
+
+        class MyPlugin(PythonPlugin):
+            """Custom description."""
+
+            def __init__(self):
+                super().__init__(__file__, '0.0.1', 'custom-url')
+
+        my = MyPlugin()
+
+        self.assertEqual(my.name, 'MyPlugin')
+        self.assertEqual(my.desc, 'Custom description.')
+        self.assertEqual(my.version, '0.0.1')
+        self.assertEqual(my.url, 'custom-url')
+
+        self.assertEqual(my.filename, __file__)
+        self.assertEqual(my.modname, 'python')
-- 
cgit v0.11.2-87-g4458