From 42540e681161aab0a1c27c66541ed5dc833ca411 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 7 Feb 2021 21:30:07 +0100
Subject: Created the right place for plugins in the Python API.

---
 configure.ac                             |    1 +
 plugins/pychrysalide/Makefile.am         |    9 +-
 plugins/pychrysalide/constants.c         |  100 --
 plugins/pychrysalide/constants.h         |   38 -
 plugins/pychrysalide/core.c              |   55 +-
 plugins/pychrysalide/plugin.c            | 1883 -----------------------------
 plugins/pychrysalide/plugin.h            |   75 --
 plugins/pychrysalide/plugins/Makefile.am |   24 +
 plugins/pychrysalide/plugins/constants.c |  100 ++
 plugins/pychrysalide/plugins/constants.h |   38 +
 plugins/pychrysalide/plugins/module.c    |  104 ++
 plugins/pychrysalide/plugins/module.h    |   42 +
 plugins/pychrysalide/plugins/plugin.c    | 1884 ++++++++++++++++++++++++++++++
 plugins/pychrysalide/plugins/plugin.h    |   75 ++
 plugins/python/abackup/plugin.py         |    2 +-
 plugins/python/apkfiles/apkfiles.py      |    2 +-
 plugins/python/cglimpse/core.py          |    2 +-
 plugins/python/checksec/plugin.py        |    2 +-
 plugins/python/liveconv/plugin.py        |    2 +-
 plugins/python/scripting/core.py         |    2 +-
 20 files changed, 2283 insertions(+), 2157 deletions(-)
 delete mode 100644 plugins/pychrysalide/constants.c
 delete mode 100644 plugins/pychrysalide/constants.h
 delete mode 100644 plugins/pychrysalide/plugin.c
 delete mode 100644 plugins/pychrysalide/plugin.h
 create mode 100644 plugins/pychrysalide/plugins/Makefile.am
 create mode 100644 plugins/pychrysalide/plugins/constants.c
 create mode 100644 plugins/pychrysalide/plugins/constants.h
 create mode 100644 plugins/pychrysalide/plugins/module.c
 create mode 100644 plugins/pychrysalide/plugins/module.h
 create mode 100644 plugins/pychrysalide/plugins/plugin.c
 create mode 100644 plugins/pychrysalide/plugins/plugin.h

diff --git a/configure.ac b/configure.ac
index 1ee20a4..5f10574 100644
--- a/configure.ac
+++ b/configure.ac
@@ -502,6 +502,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/pychrysalide/gui/core/Makefile
                  plugins/pychrysalide/gui/panels/Makefile
                  plugins/pychrysalide/mangling/Makefile
+                 plugins/pychrysalide/plugins/Makefile
                  plugins/python/Makefile
                  plugins/python/abackup/Makefile
                  plugins/python/apkfiles/Makefile
diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index d3b5483..b4b20ad 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -1,4 +1,6 @@
 
+DEFAULT_INCLUDES = -I$(top_builddir) -idirafter.
+
 lib_LTLIBRARIES = pychrysalide.la
 
 libdir = $(pluginslibdir)
@@ -6,10 +8,8 @@ libdir = $(pluginslibdir)
 
 pychrysalide_la_SOURCES =				\
 	access.h access.c					\
-	constants.h constants.c				\
 	core.h core.c						\
 	helpers.h helpers.c					\
-	plugin.h plugin.c					\
 	star.h star.c						\
 	strenum.h strenum.c					\
 	struct.h struct.c					\
@@ -25,7 +25,8 @@ pychrysalide_la_LIBADD =				\
 	glibext/libpychrysaglibext.la		\
 	gtkext/libpychrysagtkext.la			\
 	gui/libpychrysagui.la				\
-	mangling/libpychrysamangling.la
+	mangling/libpychrysamangling.la		\
+	plugins/libpychrysaplugins.la
 
 pychrysalide_la_LDFLAGS =					\
 	-module -avoid-version					\
@@ -43,4 +44,4 @@ AM_CPPFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(LIBGTK_CFLAGS) $(LIBX
 
 AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
 
-SUBDIRS = analysis arch common core debug format glibext gtkext gui mangling
+SUBDIRS = analysis arch common core debug format glibext gtkext gui mangling plugins
diff --git a/plugins/pychrysalide/constants.c b/plugins/pychrysalide/constants.c
deleted file mode 100644
index 97cf43b..0000000
--- a/plugins/pychrysalide/constants.c
+++ /dev/null
@@ -1,100 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * constants.c - ajout des constantes principales
- *
- * Copyright (C) 2020 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 "constants.h"
-
-
-#include <plugins/plugin-def.h>
-
-
-#include "helpers.h"
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
-*                                                                             *
-*  Description : Définit les constantes relatives aux greffons Python.        *
-*                                                                             *
-*  Retour      : true en cas de succès de l'opération, false sinon.           *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool define_plugin_module_constants(PyTypeObject *type)
-{
-    bool result;                            /* Bilan à retourner           */
-    PyObject *values;                       /* Groupe de valeurs à établir */
-
-    result = true;
-
-    values = PyDict_New();
-
-    if (result) result = add_const_to_group(values, "BASIC_NONE", PGA_BASIC_NONE);
-    if (result) result = add_const_to_group(values, "PLUGIN_INIT", PGA_PLUGIN_INIT);
-    if (result) result = add_const_to_group(values, "PLUGIN_LOADED", PGA_PLUGIN_LOADED);
-    if (result) result = add_const_to_group(values, "PLUGIN_EXIT", PGA_PLUGIN_EXIT);
-    if (result) result = add_const_to_group(values, "NATIVE_PLUGINS_LOADED", PGA_NATIVE_PLUGINS_LOADED);
-    if (result) result = add_const_to_group(values, "ALL_PLUGINS_LOADED", PGA_ALL_PLUGINS_LOADED);
-    if (result) result = add_const_to_group(values, "TYPE_BUILDING", PGA_TYPE_BUILDING);
-    if (result) result = add_const_to_group(values, "GUI_THEME", PGA_GUI_THEME);
-    if (result) result = add_const_to_group(values, "PANEL_CREATION", PGA_PANEL_CREATION);
-    if (result) result = add_const_to_group(values, "PANEL_DOCKING", PGA_PANEL_DOCKING);
-    if (result) result = add_const_to_group(values, "CONTENT_EXPLORER", PGA_CONTENT_EXPLORER);
-    if (result) result = add_const_to_group(values, "CONTENT_RESOLVER", PGA_CONTENT_RESOLVER);
-    if (result) result = add_const_to_group(values, "CONTENT_ANALYZED", PGA_CONTENT_ANALYZED);
-    if (result) result = add_const_to_group(values, "FORMAT_ANALYSIS_STARTED", PGA_FORMAT_ANALYSIS_STARTED);
-    if (result) result = add_const_to_group(values, "FORMAT_PRELOAD", PGA_FORMAT_PRELOAD);
-    if (result) result = add_const_to_group(values, "FORMAT_ATTACH_DEBUG", PGA_FORMAT_ATTACH_DEBUG);
-    if (result) result = add_const_to_group(values, "FORMAT_ANALYSIS_ENDED", PGA_FORMAT_ANALYSIS_ENDED);
-    if (result) result = add_const_to_group(values, "FORMAT_POST_ANALYSIS_STARTED", PGA_FORMAT_POST_ANALYSIS_STARTED);
-    if (result) result = add_const_to_group(values, "FORMAT_POST_ANALYSIS_ENDED", PGA_FORMAT_POST_ANALYSIS_ENDED);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_STARTED", PGA_DISASSEMBLY_STARTED);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_RAW", PGA_DISASSEMBLY_RAW);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_HOOKED_LINK", PGA_DISASSEMBLY_HOOKED_LINK);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_HOOKED_POST", PGA_DISASSEMBLY_HOOKED_POST);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_LIMITED", PGA_DISASSEMBLY_LIMITED);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_LOOPS", PGA_DISASSEMBLY_LOOPS);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_LINKED", PGA_DISASSEMBLY_LINKED);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_GROUPED", PGA_DISASSEMBLY_GROUPED);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_RANKED", PGA_DISASSEMBLY_RANKED);
-    if (result) result = add_const_to_group(values, "DISASSEMBLY_ENDED", PGA_DISASSEMBLY_ENDED);
-    if (result) result = add_const_to_group(values, "DETECTION_OBFUSCATORS", PGA_DETECTION_OBFUSCATORS);
-
-    if (!result)
-    {
-        Py_DECREF(values);
-        goto exit;
-    }
-
-    result = attach_constants_group_to_type(type, false, "PluginAction", values,
-                                            "Features with which plugins can extend the core of Chrysalide.");
-
- exit:
-
-    return result;
-
-}
diff --git a/plugins/pychrysalide/constants.h b/plugins/pychrysalide/constants.h
deleted file mode 100644
index 21f9d0e..0000000
--- a/plugins/pychrysalide/constants.h
+++ /dev/null
@@ -1,38 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * constants.h - prototypes pour l'ajout des constantes principales
- *
- * Copyright (C) 2020 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_CONSTANTS_H
-#define _PLUGINS_PYCHRYSALIDE_CONSTANTS_H
-
-
-#include <Python.h>
-#include <stdbool.h>
-
-
-/* Définit les constantes relatives aux greffons Python. */
-bool define_plugin_module_constants(PyTypeObject *);
-
-
-
-#endif  /* _PLUGINS_PYCHRYSALIDE_CONSTANTS_H */
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index 7bc46e4..30d4259 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -49,7 +49,6 @@
 
 #include "access.h"
 #include "helpers.h"
-#include "plugin.h"
 #include "star.h"
 #include "strenum.h"
 #include "struct.h"
@@ -63,6 +62,8 @@
 #include "gtkext/module.h"
 #include "gui/module.h"
 #include "mangling/module.h"
+#include "plugins/module.h"
+#include "plugins/plugin.h"
 
 
 
@@ -100,9 +101,6 @@ static bool set_version_for_gtk_namespace(const char *);
 /* Point de sortie pour l'initialisation de Python. */
 static void PyExit_pychrysalide(void);
 
-/* Ajoute le module 'plugins' au module Python. */
-static bool add_plugin_module_to_python_module(PyObject *);
-
 /* Complète les chemins de recherches de Python. */
 static void extend_python_path(const char *);
 
@@ -371,50 +369,6 @@ static void PyExit_pychrysalide(void)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : super = module dont la définition est à compléter.           *
-*                                                                             *
-*  Description : Ajoute le module 'plugins' au module Python.                 *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool add_plugin_module_to_python_module(PyObject *super)
-{
-    bool result;                            /* Bilan à retourner           */
-    PyObject *module;                       /* Sous-module mis en place    */
-
-#define PYCHRYSALIDE_PLUGINS_DOC                    \
-    "Home for all plugins without another home."
-
-    static PyModuleDef py_chrysalide_deguard_module = {
-
-        .m_base = PyModuleDef_HEAD_INIT,
-
-        .m_name = "pychrysalide.plugins",
-        .m_doc = PYCHRYSALIDE_PLUGINS_DOC,
-
-        .m_size = -1,
-
-    };
-
-    result = false;
-
-    module = build_python_module(super, &py_chrysalide_deguard_module);
-
-    result = (module != NULL);
-
-    assert(result);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Point d'entrée pour l'initialisation de Python.              *
@@ -514,8 +468,6 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
 
     if (status) status = add_features_module(result);
 
-    if (status) add_plugin_module_to_python_module(result);
-
     if (status) status = add_analysis_module(result);
     if (status) status = add_arch_module(result);
     if (status) status = add_common_module(result);
@@ -526,8 +478,8 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
     if (status) status = add_gtkext_module(result);
     if (status) status = add_gui_module(result);
     if (status) status = add_mangling_module(result);
+    if (status) status = add_plugins_module(result);
 
-    if (status) status = ensure_python_plugin_module_is_registered();
     if (status) status = ensure_python_string_enum_is_registered();
     if (status) status = ensure_python_py_struct_is_registered();
 
@@ -541,6 +493,7 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
     if (status) status = populate_gtkext_module();
     if (status) status = populate_gui_module();
     if (status) status = populate_mangling_module();
+    if (status) status = populate_plugins_module();
 
     if (!status)
     {
diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c
deleted file mode 100644
index 88b20de..0000000
--- a/plugins/pychrysalide/plugin.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * plugin.c - interactions avec un greffon Python
- *
- * Copyright (C) 2018-2019 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 "plugin.h"
-
-
-#include <assert.h>
-#include <libgen.h>
-#include <malloc.h>
-#include <pygobject.h>
-#include <string.h>
-
-
-#include <common/extstr.h>
-#include <plugins/dt.h>
-#include <plugins/pglist.h>
-#include <plugins/self.h>
-
-
-#include "access.h"
-#include "constants.h"
-#include "core.h"
-#include "helpers.h"
-#include "core/constants.h"
-
-
-
-/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-
-
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *);
-
-/* Initialise la classe des greffons d'extension. */
-static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer);
-
-/* 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 *);
-
-/* Accompagne la fin du chargement des modules natifs. */
-static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction);
-
-/* 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);
-
-/* 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 *);
-
-/* 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 *);
-
-/* 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 *);
-
-
-
-/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
-
-
-/* Ligne de représentation de code binaire (instance) */
-struct _GPythonPlugin
-{
-    GPluginModule parent;                   /* Instance parente            */
-
-};
-
-
-/* Ligne de représentation de code binaire (classe) */
-struct _GPythonPluginClass
-{
-    GPluginModuleClass parent;              /* Classe parente              */
-
-};
-
-
-/* Initialise la classe des greffons Python. */
-static void g_python_plugin_class_init(GPythonPluginClass *);
-
-/* Initialise l'instance d'un greffon Python. */
-static void g_python_plugin_init(GPythonPlugin *);
-
-/* Supprime toutes les références externes. */
-static void g_python_plugin_dispose(GPythonPlugin *);
-
-/* Description : Procède à la libération totale de la mémoire. */
-static void g_python_plugin_finalize(GPythonPlugin *);
-
-/* Fournit le nom brut associé au greffon. */
-static char *g_python_plugin_get_modname(const GPythonPlugin *);
-
-
-
-/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
-
-
-/* Construit le nom d'un fichier de configuration du greffon. */
-static PyObject *py_plugin_module_build_config_filename(PyObject *, PyObject *);
-
-/* Affiche un message dans le journal des messages système. */
-static PyObject *py_plugin_module_log_message(PyObject *, PyObject *);
-
-/* Fournit le nom brut associé au greffon. */
-static PyObject *py_plugin_module_get_modname(PyObject *, void *);
-
-/* Indique le fichier contenant le greffon manipulé. */
-static PyObject *py_plugin_module_get_filename(PyObject *, void *);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : type = type du nouvel objet à mettre en place.               *
-*                args = éventuelle liste d'arguments.                         *
-*                kwds = éventuel dictionnaire de valeurs mises à disposition. *
-*                                                                             *
-*  Description : Accompagne la création d'une instance dérivée en Python.     *
-*                                                                             *
-*  Retour      : Nouvel objet Python mis en place ou NULL en cas d'échec.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    PyObject *result;                       /* Objet à retourner           */
-    PyTypeObject *base;                     /* Type de base à dériver      */
-    bool first_time;                        /* Evite les multiples passages*/
-    GType gtype;                            /* Nouveau type de processeur  */
-    bool status;                            /* Bilan d'un enregistrement   */
-
-    /* Validations diverses */
-
-    base = get_python_plugin_module_type();
-
-    if (type == base)
-    {
-        result = NULL;
-        PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
-        goto exit;
-    }
-
-    /* Mise en place d'un type dédié */
-
-    first_time = (g_type_from_name(type->tp_name) == 0);
-
-    gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name,
-                               (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL);
-
-    if (first_time)
-    {
-        status = register_class_for_dynamic_pygobject(gtype, type, base);
-
-        if (!status)
-        {
-            result = NULL;
-            goto exit;
-        }
-
-    }
-
-    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
-
-    result = PyType_GenericNew(type, args, kwds);
-
- exit:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : class  = classe à initialiser.                               *
-*                unused = données non utilisées ici.                          *
-*                                                                             *
-*  Description : Initialise la classe des greffons d'extension.               *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unused)
-{
-    class->init = NULL;
-    class->manage = py_plugin_module_manage_wrapper;
-    class->exit = NULL;
-
-    class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper;
-
-    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;
-
-    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;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  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_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
-    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    */
-
-#define PLUGIN_MODULE_DOC                                                   \
-    "PythonModule is the class allowing the creation of Chrysalide plugins" \
-    " for Python."                                                          \
-    "\n"                                                                    \
-    "Calls to the *__init__* constructor of this abstract object expect"    \
-    " no particular argument.\n"                                            \
-    "\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.PluginModule.PluginAction"       \
-    " defining the features the plugin is bringing; this list can be"       \
-    " empty.\n"                                                             \
-    "\n"                                                                    \
-    "Depending on the implemented actions, some of the following methods"   \
-    " have to be defined for new classes:\n"                                \
-    "* pychrysalide.PluginModule._init_config();\n"                         \
-    "* pychrysalide.PluginModule._notify_plugins_loaded();\n"               \
-    "* pychrysalide.PluginModule._include_theme();\n"                       \
-    "* pychrysalide.PluginModule._on_panel_creation;\n"                     \
-    "* pychrysalide.PluginModule._on_panel_docking();\n"                    \
-    "* pychrysalide.PluginModule._handle_binary_content();\n"               \
-    "* pychrysalide.PluginModule._handle_loaded_content();\n"               \
-    "* pychrysalide.PluginModule._handle_format_analysis();\n"              \
-    "* pychrysalide.PluginModule._preload_format();\n"                      \
-    "* pychrysalide.PluginModule._attach_debug_format();\n"                 \
-    "* pychrysalide.PluginModule._process_disassembly_event();\n"           \
-    "* pychrysalide.PluginModule._detect_external_tools()."
-
-    /* Initialisation d'un objet GLib */
-
-    ret = forward_pygobjet_init(self);
-    if (ret == -1) return -1;
-
-    /* Eléments de base */
-
-    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;
-
-    /* Validation du reste de l'interface */
-
-    value = PyObject_GetAttrString(self, "_actions");
-
-    if (value == NULL)
-    {
-        PyErr_SetString(PyExc_TypeError, _("An '_actions' class attributes is missing."));
-        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);
-
-    return 0;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                                                                             *
-*  Description : Encadre une étape de la vie d'un greffon.                    *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool py_plugin_module_manage_wrapper(GPluginModule *plugin)
-{
-    bool result;                            /* Bilan à faire remonter      */
-    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.PluginModule.PluginAction"   \
-    " value.\n"                                                         \
-    "\n"                                                                \
-    "This method has to be defined in order to handle actions such as"  \
-    " *PLUGIN_LOADED*."                                                 \
-)
-
-    result = true;
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_manage"))
-    {
-        args = PyTuple_New(1);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(PGA_PLUGIN_LOADED));
-
-        pyret = run_python_method(pyobj, "_manage", args);
-
-        result = (pyret == Py_True);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                                                                             *
-*  Description : Accompagne la fin du chargement des modules natifs.          *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin, PluginAction action)
-{
-    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.PluginModule.PluginAction"   \
-    " value.\n"                                                         \
-    "\n"                                                                \
-    "This method has to be defined in order to handle actions such as"  \
-    " *NATIVE_PLUGINS_LOADED* or *PLUGINS_LOADED*."                     \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_notify_plugins_loaded"))
-    {
-        args = PyTuple_New(1);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-
-        pyret = run_python_method(pyobj, "_notify_plugins_loaded", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin    = greffon à manipuler.                             *
-*                action    = type d'action attendue.                          *
-*                dark      = indique une préférence pour la variante foncée.  *
-*                resources = liste de ressources à constituer. [OUT]          *
-*                count     = taille de cette liste. [OUT]                     *
-*                                                                             *
-*  Description : Complète une liste de resources pour thème.                  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, gboolean dark, char ***resources, size_t *count)
-{
-    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    PyObject *pyobj;                        /* Objet Python concerné       */
-    PyObject *darkness;                     /* Valeur booléenne à joindre  */
-    PyObject *args;                         /* Arguments pour l'appel      */
-    PyObject *pyret;                        /* Bilan d'exécution           */
-    Py_ssize_t length;                      /* Nombre d'éléments collectés */
-    Py_ssize_t i;                           /* Boucle de parcours          */
-    PyObject *res;                          /* Ressource à ajouter         */
-
-#define PLUGIN_MODULE_INCLUDE_THEME_WRAPPER PYTHON_WRAPPER_DEF          \
-(                                                                       \
-    _include_theme, "$self, action, dark, /",                           \
-    METH_VARARGS,                                                       \
-    "Abstract method called once all the native plugins are loaded.\n"  \
-    "\n"                                                                \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"   \
-    " value and the *dark* parameter indicates if a dark theme is"      \
-    " being to get loaded.\n"                                           \
-    "\n"                                                                \
-    "The expected result is a list of CSS definition resource URIs,"    \
-    " provided as strings such as 'resource:///org/xxx/extra.css'"      \
-    " for instance.\n"                                                  \
-    "\n"                                                                \
-    "This method has to be defined in order to handle action such as"   \
-    " *GUI_THEME*."                                                     \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_include_theme"))
-    {
-        args = PyTuple_New(2);
-
-        darkness = (dark ? Py_True : Py_False);
-        Py_INCREF(darkness);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, darkness);
-
-        pyret = run_python_method(pyobj, "_include_theme", args);
-
-        if (!PySequence_Check(pyret))
-            g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list"));
-
-        else
-        {
-            length = PySequence_Length(pyret);
-
-            for (i = 0; i < length; i++)
-            {
-                res = PySequence_GetItem(pyret, i);
-
-                if (!PyUnicode_Check(res))
-                    g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
-                                                         _("The returned #%zd value must be a string"));
-
-                else
-                {
-                    *resources = realloc(*resources, ++(*count) * sizeof(char **));
-                    *resources[*count - 1] = strdup(PyUnicode_DATA(res));
-                }
-
-                Py_DECREF(res);
-
-            }
-
-        }
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                item   = nouveau panneau créé.                               *
-*                                                                             *
-*  Description : Rend compte de la création d'un panneau.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item)
-{
-    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_ON_PANEL_CREATION_WRAPPER PYTHON_WRAPPER_DEF      \
-(                                                                       \
-    _on_panel_creation, "$self, action, item, /",                       \
-    METH_VARARGS,                                                       \
-    "Abstract method called when a new instance of panel is created.\n" \
-    "\n"                                                                \
-    "The expected *action* is a pychrysalide.PluginModule.PluginAction" \
-    " value and the *item* is a pychrysalide.gui.PanelItem instance.\n" \
-    "\n"                                                                \
-    "This method has to be defined in order to handle action such as"   \
-    " *PANEL_CREATION*."                                                \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_on_panel_creation"))
-    {
-        args = PyTuple_New(2);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item)));
-
-        pyret = run_python_method(pyobj, "_on_panel_creation", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                item   = panneau marqué par un changement d'affichage.       *
-*                dock   = indique une accroche et non un décrochage.          *
-*                                                                             *
-*  Description : Rend compte d'un affichage ou d'un retrait de panneau.       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item, bool dock)
-{
-    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    PyObject *pyobj;                        /* Objet Python concerné       */
-    PyObject *pydock;                       /* Valeur booléenne à joindre  */
-    PyObject *args;                         /* Arguments pour l'appel      */
-    PyObject *pyret;                        /* Bilan d'exécution           */
-
-#define PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER PYTHON_WRAPPER_DEF       \
-(                                                                       \
-    _on_panel_docking, "$self, action, item, dock, /",                  \
-    METH_VARARGS,                                                       \
-    "Abstract method called when a panel is docked or undocked into"    \
-    " the Chrysalide main graphical interface.\n"                       \
-    "\n"                                                                \
-    "The expected *action* is a pychrysalide.PluginModule.PluginAction" \
-    " value, the *item* is a pychrysalide.gui.PanelItem instance and"   \
-    " the *dock* parameter indicates if the panel request a docking"    \
-    " operation or an undocking one.\n"                                 \
-    "\n"                                                                \
-    "This method has to be defined in order to handle action such as"   \
-    " *PANEL_DOCKING*."                                                 \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_on_panel_docking"))
-    {
-        args = PyTuple_New(3);
-
-        pydock = (dock ? Py_True : Py_False);
-        Py_INCREF(pydock);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item)));
-        PyTuple_SetItem(args, 2, pydock);
-
-        pyret = run_python_method(pyobj, "_on_panel_docking", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin  = greffon à manipuler.                               *
-*                action  = type d'action attendue.                            *
-*                content = contenu binaire à traiter.                         *
-*                wid     = identifiant du groupe de traitement.               *
-*                status  = barre de statut à tenir informée.                  *
-*                                                                             *
-*  Description : Procède à une opération liée à un contenu binaire.           *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status)
-{
-    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_HANDLE_BINARY_CONTENT_WRAPPER PYTHON_WRAPPER_DEF              \
-(                                                                                   \
-    _handle_binary_content, "$self, action, content, wid, status, /",               \
-    METH_VARARGS,                                                                   \
-    "Abstract method used to explore a binary content (and possibly to add new"     \
-    " contents to explore) or to load a recognized binary content into a"           \
-    " pychrysalide.analysis.LoadedContent instance.\n"                              \
-    "\n"                                                                            \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
-    " value and the initial binary content is a pychrysalide.analysis.BinContent"   \
-    " instance. A tracking identifier is provided and is aimed to be"               \
-    " used with methods from pychrysalide.analysis.ContentExplorer and"             \
-    " pychrysalide.analysis.ContentResolver. A reference to the main status bar"    \
-    " may also be provided, as a pychrysalide.gtkext.StatusStack instance if"       \
-    " running in graphical mode or None otherwise.\n"                               \
-    "\n"                                                                            \
-    "This method has to be defined in order to handle actions such as"              \
-    " *CONTENT_EXPLORER* or *CONTENT_RESOLVER*."                                    \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_handle_binary_content"))
-    {
-        args = PyTuple_New(4);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content)));
-        PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid));
-        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
-
-        pyret = run_python_method(pyobj, "_handle_binary_content", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin  = greffon à manipuler.                               *
-*                action  = type d'action attendue.                            *
-*                content = contenu chargé à traiter.                          *
-*                gid     = identifiant du groupe de traitement.               *
-*                status  = barre de statut à tenir informée.                  *
-*                                                                             *
-*  Description : Procède à une opération liée à un contenu chargé.            *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t gid, GtkStatusStack *status)
-{
-    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_HANDLE_LOADED_CONTENT_WRAPPER PYTHON_WRAPPER_DEF              \
-(                                                                                   \
-    _handle_loaded_content, "$self, action, content, gid, status, /",               \
-    METH_VARARGS,                                                                   \
-    "Abstract method run once a loaded binary has been analyzed with success.\n"    \
-    "\n"                                                                            \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
-    " value and the analyzed content is a pychrysalide.analysis.LoadedContent"      \
-    " instance. The identifier refers to the working queue used to process the"     \
-    " analysis. A reference to the main status bar may also be provided, as a"      \
-    " pychrysalide.gtkext.StatusStack instance if running in graphical mode or"     \
-    " None otherwise.\n"                                                            \
-    "\n"                                                                            \
-    "This method has to be defined in order to handle action such as"               \
-    " *CONTENT_ANALYZED*."                                                          \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_handle_loaded_content"))
-    {
-        args = PyTuple_New(4);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content)));
-        PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid));
-        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
-
-        pyret = run_python_method(pyobj, "_handle_loaded_content", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                format = format de binaire à manipuler pendant l'opération.  *
-*                gid    = groupe de travail dédié.                            *
-*                status = barre de statut à tenir informée.                   *
-*                                                                             *
-*  Description : Procède à une opération liée à l'analyse d'un format.        *
-*                                                                             *
-*  Retour      : Bilan de l'exécution du traitement.                          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool py_plugin_module_handle_known_format_analysis_wrapper(const GPluginModule *plugin, PluginAction action, GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status)
-{
-    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_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER PYTHON_WRAPPER_DEF      \
-(                                                                                   \
-    _handle_binary_format_analysis, "$self, action, format, gid, status, /",        \
-    METH_VARARGS,                                                                   \
-    "Abstract method run at several different steps of a binary format analysis:\n" \
-    "* at the beginning and at the end of the main analysis pass;\n"                \
-    "* at the beginning and at the end of the extra final pass.\n"                  \
-    "\n"                                                                            \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
-    " value and the provided format is a pychrysalide.format.KnownFormat"           \
-    " instance. The identifier refers to the working queue used to process the"     \
-    " analysis. A reference to the main status bar may also be provided, as a"      \
-    " pychrysalide.gtkext.StatusStack instance if running in graphical mode or"     \
-    " None otherwise.\n"                                                            \
-    "\n"                                                                            \
-    "This method has to be defined in order to handle actions such as"              \
-    " *FORMAT_ANALYSIS_STARTED*, *FORMAT_ANALYSIS_ENDED*,"                          \
-    " *FORMAT_POST_ANALYSIS_STARTED* or *FORMAT_POST_ANALYSIS_ENDED*."              \
-)
-
-    result = false;
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_handle_format_analysis"))
-    {
-        args = PyTuple_New(4);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
-        PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid));
-        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
-
-        pyret = run_python_method(pyobj, "_handle_format_analysis", args);
-
-        result = (pyret == Py_True);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                format = format de binaire à manipuler pendant l'opération.  *
-*                info   = informations à constituer en avance de phase.       *
-*                status = barre de statut à tenir informée.                   *
-*                                                                             *
-*  Description : Procède à un préchargement de format de fichier.             *
-*                                                                             *
-*  Retour      : Bilan de l'exécution du traitement.                          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status)
-{
-    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_PRELOAD_BINARY_FORMAT_WRAPPER PYTHON_WRAPPER_DEF              \
-(                                                                                   \
-    _preload_binary_format, "$self, action, format, info, status, /",               \
-    METH_VARARGS,                                                                   \
-    "Abstract method which is an opportunity to setup instructions or comments"     \
-    " ahead of the disassembling process.\n"                                        \
-    "\n"                                                                            \
-    "Format fields do not need to get disassembled and may be annotated for"        \
-    " instance.\n"                                                                  \
-    "\n"                                                                            \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
-    " value and the provided format is a pychrysalide.format.BinFormat"             \
-    " instance. The information holder to fill is a pychrysalide.format.PreloadInfo"\
-    " instance. A reference to the main status bar may also be provided, as a"      \
-    " pychrysalide.gtkext.StatusStack instance if running in graphical mode or"     \
-    " None otherwise.\n"                                                            \
-    "\n"                                                                            \
-    "This method has to be defined in order to handle action such as"               \
-    " *FORMAT_PRELOAD*."                                                            \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_preload_format"))
-    {
-        args = PyTuple_New(4);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
-        PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(info)));
-        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
-
-        pyret = run_python_method(pyobj, "_preload_format", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-    return true;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                format = format de binaire à manipuler pendant l'opération.  *
-*                                                                             *
-*  Description : Procède au rattachement d'éventuelles infos de débogage.     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *plugin, PluginAction action, GExeFormat *format)
-{
-    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_ATTACH_DEBUG_FORMAT_WRAPPER PYTHON_WRAPPER_DEF                \
-(                                                                                   \
-    _attach_debug_format, "$self, action, format, /",                               \
-    METH_VARARGS,                                                                   \
-    "Abstract method called when a debugger is attached to a binary format.\n"      \
-    "\n"                                                                            \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
-    " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \
-    "\n"                                                                            \
-    "This method has to be defined in order to handle action such as"               \
-    " *FORMAT_ATTACH_DEBUG*."                                                       \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_attach_debug_format"))
-    {
-        args = PyTuple_New(2);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
-
-        pyret = run_python_method(pyobj, "_attach_debug_format", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à manipuler.                                *
-*                action = type d'action attendue.                             *
-*                binary = binaire dont le contenu est en cours de traitement. *
-*                status  = barre de statut à tenir informée.                  *
-*                context = contexte de désassemblage.                         *
-*                                                                             *
-*  Description : Exécute une action pendant un désassemblage de binaire.      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
-{
-    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_PROCESS_DISASSEMBLY_EVENT_WRAPPER PYTHON_WRAPPER_DEF          \
-(                                                                                   \
-    _process_disassembly_event, "$self, action, format, /",                         \
-    METH_VARARGS,                                                                   \
-    "Abstract method run at several different steps of a binary analysis.\n"        \
-    "\n"                                                                            \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
-    " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \
-    "\n"                                                                            \
-    "This method has to be defined in order to handle actions such as"              \
-    " *DISASSEMBLY_STARTED*, *DISASSEMBLY_RAW*, *DISASSEMBLY_HOOKED_LINK*,"         \
-    " *DISASSEMBLY_HOOKED_POST*, *DISASSEMBLY_LIMITED*, *DISASSEMBLY_LOOPS*,"       \
-    " *DISASSEMBLY_LINKED*, *DISASSEMBLY_GROUPED*, *DISASSEMBLY_RANKED*,"           \
-    " *DISASSEMBLY_ENDED*."                                                         \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_process_disassembly_event"))
-    {
-        args = PyTuple_New(4);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(binary)));
-        PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(status)));
-        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(context)));
-
-        pyret = run_python_method(pyobj, "_process_disassembly_event", args);
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin  = greffon à manipuler.                               *
-*                action  = type d'action attendue.                            *
-*                content = élément chargé à consulter.                        *
-*                version = précise si les versions doivent être recherchées.  *
-*                names   = désignations humaines correspondantes, à libérer.  *
-*                count   = nombre de types d'obscurcissement trouvés. [OUT]   *
-*                                                                             *
-*  Description : Effectue la détection d'effets d'outils externes.            *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count)
-{
-    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    PyObject *pyobj;                        /* Objet Python concerné       */
-    PyObject *details;                      /* Valeur booléenne à joindre  */
-    PyObject *args;                         /* Arguments pour l'appel      */
-    PyObject *pyret;                        /* Bilan d'exécution           */
-    Py_ssize_t length;                      /* Nombre d'éléments collectés */
-    Py_ssize_t i;                           /* Boucle de parcours          */
-    PyObject *res;                          /* Ressource à ajouter         */
-
-#define PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER PYTHON_WRAPPER_DEF  \
-(                                                                       \
-    _detect_external_tools, "$self, action, content, version, /",       \
-    METH_VARARGS,                                                       \
-    "Abstract method called when a detection of tools used the build"   \
-    " the analyzed content is required.\n"                              \
-    "\n"                                                                \
-    "The expected action is a pychrysalide.PluginModule.PluginAction"   \
-    " value and the content is a pychrysalide.analysis.LoadedContent"   \
-    " instance. The *version* parameter is a boolean value indicating"  \
-    " if some extra details about the tools version are wished.\n"      \
-    "\n"                                                                \
-    "The expected result is a list of strings.\n"                       \
-    "\n"                                                                \
-    "This method has to be defined in order to handle action such as"   \
-    " *DETECTION_OBFUSCATORS*."                                         \
-)
-
-    gstate = PyGILState_Ensure();
-
-    pyobj = pygobject_new(G_OBJECT(plugin));
-
-    if (has_python_method(pyobj, "_detect_external_tools"))
-    {
-        args = PyTuple_New(3);
-
-        details = (version ? Py_True : Py_False);
-        Py_INCREF(details);
-
-        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
-        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content)));
-        PyTuple_SetItem(args, 2, details);
-
-        pyret = run_python_method(pyobj, "_detect_external_tools", args);
-
-        if (!PySequence_Check(pyret))
-            g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list"));
-
-        else
-        {
-            length = PySequence_Length(pyret);
-
-            for (i = 0; i < length; i++)
-            {
-                res = PySequence_GetItem(pyret, i);
-
-                if (!PyUnicode_Check(res))
-                    g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
-                                                         _("The returned #%zd value must be a string"));
-
-                else
-                {
-                    *names = realloc(*names, ++(*count) * sizeof(char **));
-                    *names[*count - 1] = strdup(PyUnicode_DATA(res));
-                }
-
-                Py_DECREF(res);
-
-            }
-
-        }
-
-        Py_XDECREF(pyret);
-        Py_DECREF(args);
-
-    }
-
-    Py_DECREF(pyobj);
-
-    PyGILState_Release(gstate);
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                       INTERFACE INTERNE POUR GREFFONS PYTHON                       */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini par la GLib pour le greffon Python. */
-G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
-*                                                                             *
-*  Description : Initialise la classe des greffons Python.                    *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_python_plugin_class_init(GPythonPluginClass *klass)
-{
-    GObjectClass *object;                   /* Autre version de la classe  */
-    GPluginModuleClass *plugin;             /* Version parente de la classe*/
-
-    object = G_OBJECT_CLASS(klass);
-
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize;
-
-    plugin = G_PLUGIN_MODULE_CLASS(klass);
-
-    plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = instance à initialiser.                             *
-*                                                                             *
-*  Description : Initialise l'instance d'un greffon Python.                   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_python_plugin_init(GPythonPlugin *plugin)
-{
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  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)
-{
-#if 0
-    PyThreadState *tstate;                  /* Contexte d'environnement    */
-
-    /**
-     * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock
-     *
-     * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur,
-     * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante :
-     *
-     *    Fatal Python error: drop_gil: GIL is not locked
-     *
-     * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée
-     * comme dépréciée depuis Python 3.2.
-     *
-     * Donc on choisit les alternatives officielles.
-     *
-     * Cependant, PyThreadState_Get() renvoit l'erreur suivante :
-     *
-     *    Fatal Python error: PyThreadState_Get: no current thread
-     *
-     * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur
-     * est intégré dans l'éditeur.
-     */
-
-    tstate = get_pychrysalide_main_tstate();
-
-    if (tstate != NULL)
-        PyEval_RestoreThread(tstate);
-
-    if (tstate != NULL)
-        PyEval_SaveThread();
-#endif
-
-    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)
-{
-    plugin_interface *final;                /* Interface finale conservée  */
-
-    final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
-
-    if (final != NULL)
-    {
-        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);
-
-        assert(final->required_count == 1);
-
-        if (final->required != NULL)
-            free(final->required);
-
-        if (final->actions != NULL)
-            free(final->actions);
-
-        free(final);
-
-    }
-
-    G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  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 *path;                             /* Chemin à traiter            */
-
-    path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin)));
-
-    result = strdup(basename(path));
-
-    free(path);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  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 *g_python_plugin_new(const char *modname, const char *filename)
-{
-    GPythonPlugin *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_PYTHON_PLUGIN(pygobject_get(instance));
-
-    G_PLUGIN_MODULE(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 G_PLUGIN_MODULE(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;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                           MODULE PYTHON POUR LES SCRIPTS                           */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-*                                                                             *
-*  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.   *
-*                                                                             *
-*  Retour      : Chemin d'accès déterminé, ou NULL en cas d'erreur.           *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_plugin_module_build_config_filename(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é    */
-
-#define PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD PYTHON_METHOD_DEF        \
-(                                                                           \
-    build_config_filename, "final, /, create=False",                        \
-    METH_VARARGS, py_plugin_module,                                         \
-    "Build a filename suitable for the plugin configuration, ending with"   \
-    " the *final* suffix.\n"                                                \
-    "\n"                                                                    \
-    "If the *create* parameter is set, the path to this filename is"        \
-    " created.\n"                                                           \
-    "\n"                                                                    \
-    "The result is a string or None on failure."                            \
-)
-
-    create = 0;
-
-    if (!PyArg_ParseTuple(args, "s|p", &final, &create))
-        return NULL;
-
-    filename = g_plugin_module_build_config_filename(G_PLUGIN_MODULE(pygobject_get(self)), final, create);
-
-    if (filename != NULL)
-    {
-        result = PyUnicode_FromString(filename);
-        free(filename);
-    }
-    else
-    {
-        result = Py_None;
-        Py_INCREF(result);
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : self = objet Python concerné par l'appel.                    *
-*                args = arguments fournis à l'appel.                          *
-*                                                                             *
-*  Description : Affiche un message dans le journal des messages système.     *
-*                                                                             *
-*  Retour      : Rien en équivalent Python.                                   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args)
-{
-    PyObject *result;                       /* Bilan à retourner           */
-    LogMessageType type;                    /* Espèce du message           */
-    const char *msg;                        /* Contenu du message          */
-
-#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."                                                           \
-)
-
-    if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg))
-        return NULL;
-
-    g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg);
-
-    result = Py_None;
-    Py_INCREF(result);
-
-    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));
-    modname = g_plugin_module_get_modname(plugin);
-
-    result = PyUnicode_FromString(modname);
-
-    free(modname);
-
-    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   */
-    const 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);
-
-    result = PyUnicode_FromString(filename);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : self    = objet Python concerné par l'appel.                 *
-*                closure = non utilisé ici.                                   *
-*                                                                             *
-*  Description : Fournit la configuration mise en place pour le greffon.      *
-*                                                                             *
-*  Retour      : Configuration dédiée à l'extension.                          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_plugin_module_get_config(PyObject *self, void *closure)
-{
-    PyObject *result;                       /* Valeur à retourner          */
-    GPluginModule *plugin;                  /* Version native du greffon   */
-    GGenConfig *config;                     /* Configuration associée      */
-
-#define PLUGIN_MODULE_CONFIG_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"            \
-)
-
-    plugin = G_PLUGIN_MODULE(pygobject_get(self));
-    config = g_plugin_module_get_config(plugin);
-
-    if (config == NULL)
-    {
-        result = Py_None;
-        Py_INCREF(result);
-    }
-
-    else
-    {
-        result = pygobject_new(G_OBJECT(config));
-
-        g_object_unref(G_OBJECT(config));
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : -                                                            *
-*                                                                             *
-*  Description : Fournit un accès à une définition de type à diffuser.        *
-*                                                                             *
-*  Retour      : Définition d'objet pour Python.                              *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-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_INCLUDE_THEME_WRAPPER,
-        PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER,
-        PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER,
-        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,
-        PLUGIN_MODULE_LOG_MESSAGE_METHOD,
-        { NULL }
-    };
-
-    static PyGetSetDef py_plugin_module_getseters[] = {
-        PLUGIN_MODULE_MODNAME_ATTRIB,
-        PLUGIN_MODULE_FILENAME_ATTRIB,
-        PLUGIN_MODULE_CONFIG_ATTRIB,
-        { NULL }
-    };
-
-    static PyTypeObject py_plugin_module_type = {
-
-        PyVarObject_HEAD_INIT(NULL, 0)
-
-        .tp_name        = "pychrysalide.PluginModule",
-        .tp_basicsize   = sizeof(PyGObject),
-
-        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-
-        .tp_doc         = PLUGIN_MODULE_DOC,
-
-        .tp_methods     = py_plugin_module_methods,
-        .tp_getset      = py_plugin_module_getseters,
-
-        .tp_init        = py_plugin_module_init,
-        .tp_new         = py_plugin_module_new,
-
-    };
-
-    return &py_plugin_module_type;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : -                                                            *
-*                                                                             *
-*  Description : Prend en charge l'objet 'pychrysalide.PluginModule'.         *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool ensure_python_plugin_module_is_registered(void)
-{
-    PyTypeObject *type;                     /* Type Python 'PluginModule'  */
-    PyObject *module;                       /* Module à recompléter        */
-    PyObject *dict;                         /* Dictionnaire du module      */
-
-    type = get_python_plugin_module_type();
-
-    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
-    {
-        module = get_access_to_python_module("pychrysalide");
-
-        dict = PyModule_GetDict(module);
-
-        if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type))
-            return false;
-
-        if (!define_plugin_module_constants(type))
-            return false;
-
-    }
-
-    return true;
-
-}
diff --git a/plugins/pychrysalide/plugin.h b/plugins/pychrysalide/plugin.h
deleted file mode 100644
index 183ae4a..0000000
--- a/plugins/pychrysalide/plugin.h
+++ /dev/null
@@ -1,75 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * plugin.h - prototypes pour les interactions avec un greffon Python
- *
- * Copyright (C) 2018 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_PLUGIN_H
-#define _PLUGINS_PYCHRYSALIDE_PLUGIN_H
-
-
-#include <Python.h>
-#include <glib-object.h>
-#include <stdbool.h>
-
-
-#include <plugins/plugin.h>
-
-
-
-/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
-
-
-#define G_TYPE_PYTHON_PLUGIN                (g_python_plugin_get_type())
-#define G_PYTHON_PLUGIN(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin))
-#define G_IS_PYTHON_PLUGIN(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN))
-#define G_PYTHON_PLUGIN_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
-#define G_IS_PYTHON_PLUGIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN))
-#define G_PYTHON_PLUGIN_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
-
-
-/* Ligne de représentation de code binaire (instance) */
-typedef struct _GPythonPlugin GPythonPlugin;
-
-/* Ligne de représentation de code binaire (classe) */
-typedef struct _GPythonPluginClass GPythonPluginClass;
-
-
-/* Indique le type défini par la GLib pour le greffon Python. */
-GType g_python_plugin_get_type(void);
-
-/* Crée un greffon à partir de code Python. */
-GPluginModule *g_python_plugin_new(const char *, const char *);
-
-
-
-/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
-
-
-/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_plugin_module_type(void);
-
-/* Prend en charge l'objet 'pychrysalide.PluginModule'. */
-bool ensure_python_plugin_module_is_registered(void);
-
-
-
-#endif  /* _PLUGINS_PYCHRYSALIDE_PLUGIN_H */
diff --git a/plugins/pychrysalide/plugins/Makefile.am b/plugins/pychrysalide/plugins/Makefile.am
new file mode 100644
index 0000000..0ab8c15
--- /dev/null
+++ b/plugins/pychrysalide/plugins/Makefile.am
@@ -0,0 +1,24 @@
+
+noinst_LTLIBRARIES = libpychrysaplugins.la
+
+libpychrysaplugins_la_SOURCES =			\
+	constants.h constants.c				\
+	plugin.h plugin.c					\
+	module.h module.c
+
+libpychrysaplugins_la_LIBADD = 
+
+libpychrysaplugins_la_LDFLAGS = 
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libpychrysaplugins_la_SOURCES:%c=)
+
+
+AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+	-I$(top_srcdir)/src
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+
+SUBDIRS = 
diff --git a/plugins/pychrysalide/plugins/constants.c b/plugins/pychrysalide/plugins/constants.c
new file mode 100644
index 0000000..9de044a
--- /dev/null
+++ b/plugins/pychrysalide/plugins/constants.c
@@ -0,0 +1,100 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.c - ajout des constantes principales
+ *
+ * Copyright (C) 2020 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 "constants.h"
+
+
+#include <plugins/plugin-def.h>
+
+
+#include "../helpers.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
+*  Description : Définit les constantes relatives aux greffons Python.        *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_plugin_module_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    result = true;
+
+    values = PyDict_New();
+
+    if (result) result = add_const_to_group(values, "BASIC_NONE", PGA_BASIC_NONE);
+    if (result) result = add_const_to_group(values, "PLUGIN_INIT", PGA_PLUGIN_INIT);
+    if (result) result = add_const_to_group(values, "PLUGIN_LOADED", PGA_PLUGIN_LOADED);
+    if (result) result = add_const_to_group(values, "PLUGIN_EXIT", PGA_PLUGIN_EXIT);
+    if (result) result = add_const_to_group(values, "NATIVE_PLUGINS_LOADED", PGA_NATIVE_PLUGINS_LOADED);
+    if (result) result = add_const_to_group(values, "ALL_PLUGINS_LOADED", PGA_ALL_PLUGINS_LOADED);
+    if (result) result = add_const_to_group(values, "TYPE_BUILDING", PGA_TYPE_BUILDING);
+    if (result) result = add_const_to_group(values, "GUI_THEME", PGA_GUI_THEME);
+    if (result) result = add_const_to_group(values, "PANEL_CREATION", PGA_PANEL_CREATION);
+    if (result) result = add_const_to_group(values, "PANEL_DOCKING", PGA_PANEL_DOCKING);
+    if (result) result = add_const_to_group(values, "CONTENT_EXPLORER", PGA_CONTENT_EXPLORER);
+    if (result) result = add_const_to_group(values, "CONTENT_RESOLVER", PGA_CONTENT_RESOLVER);
+    if (result) result = add_const_to_group(values, "CONTENT_ANALYZED", PGA_CONTENT_ANALYZED);
+    if (result) result = add_const_to_group(values, "FORMAT_ANALYSIS_STARTED", PGA_FORMAT_ANALYSIS_STARTED);
+    if (result) result = add_const_to_group(values, "FORMAT_PRELOAD", PGA_FORMAT_PRELOAD);
+    if (result) result = add_const_to_group(values, "FORMAT_ATTACH_DEBUG", PGA_FORMAT_ATTACH_DEBUG);
+    if (result) result = add_const_to_group(values, "FORMAT_ANALYSIS_ENDED", PGA_FORMAT_ANALYSIS_ENDED);
+    if (result) result = add_const_to_group(values, "FORMAT_POST_ANALYSIS_STARTED", PGA_FORMAT_POST_ANALYSIS_STARTED);
+    if (result) result = add_const_to_group(values, "FORMAT_POST_ANALYSIS_ENDED", PGA_FORMAT_POST_ANALYSIS_ENDED);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_STARTED", PGA_DISASSEMBLY_STARTED);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_RAW", PGA_DISASSEMBLY_RAW);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_HOOKED_LINK", PGA_DISASSEMBLY_HOOKED_LINK);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_HOOKED_POST", PGA_DISASSEMBLY_HOOKED_POST);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_LIMITED", PGA_DISASSEMBLY_LIMITED);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_LOOPS", PGA_DISASSEMBLY_LOOPS);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_LINKED", PGA_DISASSEMBLY_LINKED);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_GROUPED", PGA_DISASSEMBLY_GROUPED);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_RANKED", PGA_DISASSEMBLY_RANKED);
+    if (result) result = add_const_to_group(values, "DISASSEMBLY_ENDED", PGA_DISASSEMBLY_ENDED);
+    if (result) result = add_const_to_group(values, "DETECTION_OBFUSCATORS", PGA_DETECTION_OBFUSCATORS);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, false, "PluginAction", values,
+                                            "Features with which plugins can extend the core of Chrysalide.");
+
+ exit:
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/plugins/constants.h b/plugins/pychrysalide/plugins/constants.h
new file mode 100644
index 0000000..71abcff
--- /dev/null
+++ b/plugins/pychrysalide/plugins/constants.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.h - prototypes pour l'ajout des constantes principales
+ *
+ * Copyright (C) 2020 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_CONSTANTS_H
+#define _PLUGINS_PYCHRYSALIDE_PLUGINS_CONSTANTS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+/* Définit les constantes relatives aux greffons Python. */
+bool define_plugin_module_constants(PyTypeObject *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_CONSTANTS_H */
diff --git a/plugins/pychrysalide/plugins/module.c b/plugins/pychrysalide/plugins/module.c
new file mode 100644
index 0000000..c38caa3
--- /dev/null
+++ b/plugins/pychrysalide/plugins/module.c
@@ -0,0 +1,104 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire plugins en tant que module
+ *
+ * Copyright (C) 2021 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 "module.h"
+
+
+#include <assert.h>
+
+
+#include "plugin.h"
+#include "../helpers.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : super = module dont la définition est à compléter.           *
+*                                                                             *
+*  Description : Ajoute le module 'plugins' à un module Python.               *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool add_plugins_module(PyObject *super)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *module;                       /* Sous-module mis en place    */
+
+#define PYCHRYSALIDE_PLUGINS_DOC                                            \
+    "This module provides features to deal with plugins: the definitions"   \
+    " required to build new Python plugins as well as functions to"         \
+    " interact with existing plugins.\n"                                    \
+    "\n"                                                                    \
+    "The module is also the place for all plugins without another home."
+
+    static PyModuleDef py_chrysalide_plugins_module = {
+
+        .m_base = PyModuleDef_HEAD_INIT,
+
+        .m_name = "pychrysalide.plugins",
+        .m_doc = PYCHRYSALIDE_PLUGINS_DOC,
+
+        .m_size = -1,
+
+    };
+
+    module = build_python_module(super, &py_chrysalide_plugins_module);
+
+    result = (module != NULL);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Intègre les objets du module 'plugins'.                      *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool populate_plugins_module(void)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    if (result) result = ensure_python_plugin_module_is_registered();
+
+    assert(result);
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/plugins/module.h b/plugins/pychrysalide/plugins/module.h
new file mode 100644
index 0000000..e2b10b9
--- /dev/null
+++ b/plugins/pychrysalide/plugins/module.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire plugins en tant que module
+ *
+ * Copyright (C) 2021 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_MODULE_H
+#define _PLUGINS_PYCHRYSALIDE_PLUGINS_MODULE_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins' à un module Python. */
+bool add_plugins_module(PyObject *);
+
+/* Intègre les objets du module 'plugins'. */
+bool populate_plugins_module(void);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_MODULE_H */
diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c
new file mode 100644
index 0000000..e5ee1ad
--- /dev/null
+++ b/plugins/pychrysalide/plugins/plugin.c
@@ -0,0 +1,1884 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plugin.c - interactions avec un greffon Python
+ *
+ * Copyright (C) 2018-2019 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 "plugin.h"
+
+
+#include <assert.h>
+#include <libgen.h>
+#include <malloc.h>
+#include <pygobject.h>
+#include <string.h>
+
+
+#include <common/extstr.h>
+#include <plugins/dt.h>
+#include <plugins/plugin-int.h>
+#include <plugins/pglist.h>
+#include <plugins/self.h>
+
+
+#include "constants.h"
+#include "../access.h"
+#include "../core.h"
+#include "../helpers.h"
+#include "../core/constants.h"
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise la classe des greffons d'extension. */
+static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer);
+
+/* 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 *);
+
+/* Accompagne la fin du chargement des modules natifs. */
+static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction);
+
+/* 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);
+
+/* 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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+
+
+/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
+
+
+/* Ligne de représentation de code binaire (instance) */
+struct _GPythonPlugin
+{
+    GPluginModule parent;                   /* Instance parente            */
+
+};
+
+
+/* Ligne de représentation de code binaire (classe) */
+struct _GPythonPluginClass
+{
+    GPluginModuleClass parent;              /* Classe parente              */
+
+};
+
+
+/* Initialise la classe des greffons Python. */
+static void g_python_plugin_class_init(GPythonPluginClass *);
+
+/* Initialise l'instance d'un greffon Python. */
+static void g_python_plugin_init(GPythonPlugin *);
+
+/* Supprime toutes les références externes. */
+static void g_python_plugin_dispose(GPythonPlugin *);
+
+/* Description : Procède à la libération totale de la mémoire. */
+static void g_python_plugin_finalize(GPythonPlugin *);
+
+/* Fournit le nom brut associé au greffon. */
+static char *g_python_plugin_get_modname(const GPythonPlugin *);
+
+
+
+/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
+
+
+/* Construit le nom d'un fichier de configuration du greffon. */
+static PyObject *py_plugin_module_build_config_filename(PyObject *, PyObject *);
+
+/* Affiche un message dans le journal des messages système. */
+static PyObject *py_plugin_module_log_message(PyObject *, PyObject *);
+
+/* Fournit le nom brut associé au greffon. */
+static PyObject *py_plugin_module_get_modname(PyObject *, void *);
+
+/* Indique le fichier contenant le greffon manipulé. */
+static PyObject *py_plugin_module_get_filename(PyObject *, void *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type du nouvel objet à mettre en place.               *
+*                args = éventuelle liste d'arguments.                         *
+*                kwds = éventuel dictionnaire de valeurs mises à disposition. *
+*                                                                             *
+*  Description : Accompagne la création d'une instance dérivée en Python.     *
+*                                                                             *
+*  Retour      : Nouvel objet Python mis en place ou NULL en cas d'échec.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result;                       /* Objet à retourner           */
+    PyTypeObject *base;                     /* Type de base à dériver      */
+    bool first_time;                        /* Evite les multiples passages*/
+    GType gtype;                            /* Nouveau type de processeur  */
+    bool status;                            /* Bilan d'un enregistrement   */
+
+    /* Validations diverses */
+
+    base = get_python_plugin_module_type();
+
+    if (type == base)
+    {
+        result = NULL;
+        PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
+        goto exit;
+    }
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name,
+                               (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL);
+
+    if (first_time)
+    {
+        status = register_class_for_dynamic_pygobject(gtype, type, base);
+
+        if (!status)
+        {
+            result = NULL;
+            goto exit;
+        }
+
+    }
+
+    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class  = classe à initialiser.                               *
+*                unused = données non utilisées ici.                          *
+*                                                                             *
+*  Description : Initialise la classe des greffons d'extension.               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unused)
+{
+    class->init = NULL;
+    class->manage = py_plugin_module_manage_wrapper;
+    class->exit = NULL;
+
+    class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper;
+
+    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;
+
+    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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    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    */
+
+#define PLUGIN_MODULE_DOC                                                   \
+    "PythonModule is the class allowing the creation of Chrysalide plugins" \
+    " for Python."                                                          \
+    "\n"                                                                    \
+    "Calls to the *__init__* constructor of this abstract object expect"    \
+    " no particular argument.\n"                                            \
+    "\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.PluginModule.PluginAction"       \
+    " defining the features the plugin is bringing; this list can be"       \
+    " empty.\n"                                                             \
+    "\n"                                                                    \
+    "Depending on the implemented actions, some of the following methods"   \
+    " have to be defined for new classes:\n"                                \
+    "* pychrysalide.PluginModule._init_config();\n"                         \
+    "* pychrysalide.PluginModule._notify_plugins_loaded();\n"               \
+    "* pychrysalide.PluginModule._include_theme();\n"                       \
+    "* pychrysalide.PluginModule._on_panel_creation;\n"                     \
+    "* pychrysalide.PluginModule._on_panel_docking();\n"                    \
+    "* pychrysalide.PluginModule._handle_binary_content();\n"               \
+    "* pychrysalide.PluginModule._handle_loaded_content();\n"               \
+    "* pychrysalide.PluginModule._handle_format_analysis();\n"              \
+    "* pychrysalide.PluginModule._preload_format();\n"                      \
+    "* pychrysalide.PluginModule._attach_debug_format();\n"                 \
+    "* pychrysalide.PluginModule._process_disassembly_event();\n"           \
+    "* pychrysalide.PluginModule._detect_external_tools()."
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    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;
+
+    /* Validation du reste de l'interface */
+
+    value = PyObject_GetAttrString(self, "_actions");
+
+    if (value == NULL)
+    {
+        PyErr_SetString(PyExc_TypeError, _("An '_actions' class attributes is missing."));
+        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);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Encadre une étape de la vie d'un greffon.                    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_plugin_module_manage_wrapper(GPluginModule *plugin)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    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.PluginModule.PluginAction"   \
+    " value.\n"                                                         \
+    "\n"                                                                \
+    "This method has to be defined in order to handle actions such as"  \
+    " *PLUGIN_LOADED*."                                                 \
+)
+
+    result = true;
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_manage"))
+    {
+        args = PyTuple_New(1);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(PGA_PLUGIN_LOADED));
+
+        pyret = run_python_method(pyobj, "_manage", args);
+
+        result = (pyret == Py_True);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                                                                             *
+*  Description : Accompagne la fin du chargement des modules natifs.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin, PluginAction action)
+{
+    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.PluginModule.PluginAction"   \
+    " value.\n"                                                         \
+    "\n"                                                                \
+    "This method has to be defined in order to handle actions such as"  \
+    " *NATIVE_PLUGINS_LOADED* or *PLUGINS_LOADED*."                     \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_notify_plugins_loaded"))
+    {
+        args = PyTuple_New(1);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+
+        pyret = run_python_method(pyobj, "_notify_plugins_loaded", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin    = greffon à manipuler.                             *
+*                action    = type d'action attendue.                          *
+*                dark      = indique une préférence pour la variante foncée.  *
+*                resources = liste de ressources à constituer. [OUT]          *
+*                count     = taille de cette liste. [OUT]                     *
+*                                                                             *
+*  Description : Complète une liste de resources pour thème.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, gboolean dark, char ***resources, size_t *count)
+{
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *darkness;                     /* Valeur booléenne à joindre  */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan d'exécution           */
+    Py_ssize_t length;                      /* Nombre d'éléments collectés */
+    Py_ssize_t i;                           /* Boucle de parcours          */
+    PyObject *res;                          /* Ressource à ajouter         */
+
+#define PLUGIN_MODULE_INCLUDE_THEME_WRAPPER PYTHON_WRAPPER_DEF          \
+(                                                                       \
+    _include_theme, "$self, action, dark, /",                           \
+    METH_VARARGS,                                                       \
+    "Abstract method called once all the native plugins are loaded.\n"  \
+    "\n"                                                                \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"   \
+    " value and the *dark* parameter indicates if a dark theme is"      \
+    " being to get loaded.\n"                                           \
+    "\n"                                                                \
+    "The expected result is a list of CSS definition resource URIs,"    \
+    " provided as strings such as 'resource:///org/xxx/extra.css'"      \
+    " for instance.\n"                                                  \
+    "\n"                                                                \
+    "This method has to be defined in order to handle action such as"   \
+    " *GUI_THEME*."                                                     \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_include_theme"))
+    {
+        args = PyTuple_New(2);
+
+        darkness = (dark ? Py_True : Py_False);
+        Py_INCREF(darkness);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, darkness);
+
+        pyret = run_python_method(pyobj, "_include_theme", args);
+
+        if (!PySequence_Check(pyret))
+            g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list"));
+
+        else
+        {
+            length = PySequence_Length(pyret);
+
+            for (i = 0; i < length; i++)
+            {
+                res = PySequence_GetItem(pyret, i);
+
+                if (!PyUnicode_Check(res))
+                    g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                                         _("The returned #%zd value must be a string"));
+
+                else
+                {
+                    *resources = realloc(*resources, ++(*count) * sizeof(char **));
+                    *resources[*count - 1] = strdup(PyUnicode_DATA(res));
+                }
+
+                Py_DECREF(res);
+
+            }
+
+        }
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                item   = nouveau panneau créé.                               *
+*                                                                             *
+*  Description : Rend compte de la création d'un panneau.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item)
+{
+    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_ON_PANEL_CREATION_WRAPPER PYTHON_WRAPPER_DEF      \
+(                                                                       \
+    _on_panel_creation, "$self, action, item, /",                       \
+    METH_VARARGS,                                                       \
+    "Abstract method called when a new instance of panel is created.\n" \
+    "\n"                                                                \
+    "The expected *action* is a pychrysalide.PluginModule.PluginAction" \
+    " value and the *item* is a pychrysalide.gui.PanelItem instance.\n" \
+    "\n"                                                                \
+    "This method has to be defined in order to handle action such as"   \
+    " *PANEL_CREATION*."                                                \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_on_panel_creation"))
+    {
+        args = PyTuple_New(2);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item)));
+
+        pyret = run_python_method(pyobj, "_on_panel_creation", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                item   = panneau marqué par un changement d'affichage.       *
+*                dock   = indique une accroche et non un décrochage.          *
+*                                                                             *
+*  Description : Rend compte d'un affichage ou d'un retrait de panneau.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item, bool dock)
+{
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pydock;                       /* Valeur booléenne à joindre  */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan d'exécution           */
+
+#define PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER PYTHON_WRAPPER_DEF       \
+(                                                                       \
+    _on_panel_docking, "$self, action, item, dock, /",                  \
+    METH_VARARGS,                                                       \
+    "Abstract method called when a panel is docked or undocked into"    \
+    " the Chrysalide main graphical interface.\n"                       \
+    "\n"                                                                \
+    "The expected *action* is a pychrysalide.PluginModule.PluginAction" \
+    " value, the *item* is a pychrysalide.gui.PanelItem instance and"   \
+    " the *dock* parameter indicates if the panel request a docking"    \
+    " operation or an undocking one.\n"                                 \
+    "\n"                                                                \
+    "This method has to be defined in order to handle action such as"   \
+    " *PANEL_DOCKING*."                                                 \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_on_panel_docking"))
+    {
+        args = PyTuple_New(3);
+
+        pydock = (dock ? Py_True : Py_False);
+        Py_INCREF(pydock);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item)));
+        PyTuple_SetItem(args, 2, pydock);
+
+        pyret = run_python_method(pyobj, "_on_panel_docking", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin  = greffon à manipuler.                               *
+*                action  = type d'action attendue.                            *
+*                content = contenu binaire à traiter.                         *
+*                wid     = identifiant du groupe de traitement.               *
+*                status  = barre de statut à tenir informée.                  *
+*                                                                             *
+*  Description : Procède à une opération liée à un contenu binaire.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status)
+{
+    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_HANDLE_BINARY_CONTENT_WRAPPER PYTHON_WRAPPER_DEF              \
+(                                                                                   \
+    _handle_binary_content, "$self, action, content, wid, status, /",               \
+    METH_VARARGS,                                                                   \
+    "Abstract method used to explore a binary content (and possibly to add new"     \
+    " contents to explore) or to load a recognized binary content into a"           \
+    " pychrysalide.analysis.LoadedContent instance.\n"                              \
+    "\n"                                                                            \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
+    " value and the initial binary content is a pychrysalide.analysis.BinContent"   \
+    " instance. A tracking identifier is provided and is aimed to be"               \
+    " used with methods from pychrysalide.analysis.ContentExplorer and"             \
+    " pychrysalide.analysis.ContentResolver. A reference to the main status bar"    \
+    " may also be provided, as a pychrysalide.gtkext.StatusStack instance if"       \
+    " running in graphical mode or None otherwise.\n"                               \
+    "\n"                                                                            \
+    "This method has to be defined in order to handle actions such as"              \
+    " *CONTENT_EXPLORER* or *CONTENT_RESOLVER*."                                    \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_handle_binary_content"))
+    {
+        args = PyTuple_New(4);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content)));
+        PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid));
+        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
+
+        pyret = run_python_method(pyobj, "_handle_binary_content", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin  = greffon à manipuler.                               *
+*                action  = type d'action attendue.                            *
+*                content = contenu chargé à traiter.                          *
+*                gid     = identifiant du groupe de traitement.               *
+*                status  = barre de statut à tenir informée.                  *
+*                                                                             *
+*  Description : Procède à une opération liée à un contenu chargé.            *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t gid, GtkStatusStack *status)
+{
+    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_HANDLE_LOADED_CONTENT_WRAPPER PYTHON_WRAPPER_DEF              \
+(                                                                                   \
+    _handle_loaded_content, "$self, action, content, gid, status, /",               \
+    METH_VARARGS,                                                                   \
+    "Abstract method run once a loaded binary has been analyzed with success.\n"    \
+    "\n"                                                                            \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
+    " value and the analyzed content is a pychrysalide.analysis.LoadedContent"      \
+    " instance. The identifier refers to the working queue used to process the"     \
+    " analysis. A reference to the main status bar may also be provided, as a"      \
+    " pychrysalide.gtkext.StatusStack instance if running in graphical mode or"     \
+    " None otherwise.\n"                                                            \
+    "\n"                                                                            \
+    "This method has to be defined in order to handle action such as"               \
+    " *CONTENT_ANALYZED*."                                                          \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_handle_loaded_content"))
+    {
+        args = PyTuple_New(4);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content)));
+        PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid));
+        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
+
+        pyret = run_python_method(pyobj, "_handle_loaded_content", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                format = format de binaire à manipuler pendant l'opération.  *
+*                gid    = groupe de travail dédié.                            *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Procède à une opération liée à l'analyse d'un format.        *
+*                                                                             *
+*  Retour      : Bilan de l'exécution du traitement.                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_plugin_module_handle_known_format_analysis_wrapper(const GPluginModule *plugin, PluginAction action, GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+{
+    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_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER PYTHON_WRAPPER_DEF      \
+(                                                                                   \
+    _handle_binary_format_analysis, "$self, action, format, gid, status, /",        \
+    METH_VARARGS,                                                                   \
+    "Abstract method run at several different steps of a binary format analysis:\n" \
+    "* at the beginning and at the end of the main analysis pass;\n"                \
+    "* at the beginning and at the end of the extra final pass.\n"                  \
+    "\n"                                                                            \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
+    " value and the provided format is a pychrysalide.format.KnownFormat"           \
+    " instance. The identifier refers to the working queue used to process the"     \
+    " analysis. A reference to the main status bar may also be provided, as a"      \
+    " pychrysalide.gtkext.StatusStack instance if running in graphical mode or"     \
+    " None otherwise.\n"                                                            \
+    "\n"                                                                            \
+    "This method has to be defined in order to handle actions such as"              \
+    " *FORMAT_ANALYSIS_STARTED*, *FORMAT_ANALYSIS_ENDED*,"                          \
+    " *FORMAT_POST_ANALYSIS_STARTED* or *FORMAT_POST_ANALYSIS_ENDED*."              \
+)
+
+    result = false;
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_handle_format_analysis"))
+    {
+        args = PyTuple_New(4);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
+        PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid));
+        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
+
+        pyret = run_python_method(pyobj, "_handle_format_analysis", args);
+
+        result = (pyret == Py_True);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                format = format de binaire à manipuler pendant l'opération.  *
+*                info   = informations à constituer en avance de phase.       *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Procède à un préchargement de format de fichier.             *
+*                                                                             *
+*  Retour      : Bilan de l'exécution du traitement.                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status)
+{
+    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_PRELOAD_BINARY_FORMAT_WRAPPER PYTHON_WRAPPER_DEF              \
+(                                                                                   \
+    _preload_binary_format, "$self, action, format, info, status, /",               \
+    METH_VARARGS,                                                                   \
+    "Abstract method which is an opportunity to setup instructions or comments"     \
+    " ahead of the disassembling process.\n"                                        \
+    "\n"                                                                            \
+    "Format fields do not need to get disassembled and may be annotated for"        \
+    " instance.\n"                                                                  \
+    "\n"                                                                            \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
+    " value and the provided format is a pychrysalide.format.BinFormat"             \
+    " instance. The information holder to fill is a pychrysalide.format.PreloadInfo"\
+    " instance. A reference to the main status bar may also be provided, as a"      \
+    " pychrysalide.gtkext.StatusStack instance if running in graphical mode or"     \
+    " None otherwise.\n"                                                            \
+    "\n"                                                                            \
+    "This method has to be defined in order to handle action such as"               \
+    " *FORMAT_PRELOAD*."                                                            \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_preload_format"))
+    {
+        args = PyTuple_New(4);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
+        PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(info)));
+        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
+
+        pyret = run_python_method(pyobj, "_preload_format", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                format = format de binaire à manipuler pendant l'opération.  *
+*                                                                             *
+*  Description : Procède au rattachement d'éventuelles infos de débogage.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *plugin, PluginAction action, GExeFormat *format)
+{
+    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_ATTACH_DEBUG_FORMAT_WRAPPER PYTHON_WRAPPER_DEF                \
+(                                                                                   \
+    _attach_debug_format, "$self, action, format, /",                               \
+    METH_VARARGS,                                                                   \
+    "Abstract method called when a debugger is attached to a binary format.\n"      \
+    "\n"                                                                            \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
+    " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \
+    "\n"                                                                            \
+    "This method has to be defined in order to handle action such as"               \
+    " *FORMAT_ATTACH_DEBUG*."                                                       \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_attach_debug_format"))
+    {
+        args = PyTuple_New(2);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
+
+        pyret = run_python_method(pyobj, "_attach_debug_format", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                action = type d'action attendue.                             *
+*                binary = binaire dont le contenu est en cours de traitement. *
+*                status  = barre de statut à tenir informée.                  *
+*                context = contexte de désassemblage.                         *
+*                                                                             *
+*  Description : Exécute une action pendant un désassemblage de binaire.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+{
+    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_PROCESS_DISASSEMBLY_EVENT_WRAPPER PYTHON_WRAPPER_DEF          \
+(                                                                                   \
+    _process_disassembly_event, "$self, action, format, /",                         \
+    METH_VARARGS,                                                                   \
+    "Abstract method run at several different steps of a binary analysis.\n"        \
+    "\n"                                                                            \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"               \
+    " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \
+    "\n"                                                                            \
+    "This method has to be defined in order to handle actions such as"              \
+    " *DISASSEMBLY_STARTED*, *DISASSEMBLY_RAW*, *DISASSEMBLY_HOOKED_LINK*,"         \
+    " *DISASSEMBLY_HOOKED_POST*, *DISASSEMBLY_LIMITED*, *DISASSEMBLY_LOOPS*,"       \
+    " *DISASSEMBLY_LINKED*, *DISASSEMBLY_GROUPED*, *DISASSEMBLY_RANKED*,"           \
+    " *DISASSEMBLY_ENDED*."                                                         \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_process_disassembly_event"))
+    {
+        args = PyTuple_New(4);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(binary)));
+        PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(status)));
+        PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(context)));
+
+        pyret = run_python_method(pyobj, "_process_disassembly_event", args);
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin  = greffon à manipuler.                               *
+*                action  = type d'action attendue.                            *
+*                content = élément chargé à consulter.                        *
+*                version = précise si les versions doivent être recherchées.  *
+*                names   = désignations humaines correspondantes, à libérer.  *
+*                count   = nombre de types d'obscurcissement trouvés. [OUT]   *
+*                                                                             *
+*  Description : Effectue la détection d'effets d'outils externes.            *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count)
+{
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *details;                      /* Valeur booléenne à joindre  */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan d'exécution           */
+    Py_ssize_t length;                      /* Nombre d'éléments collectés */
+    Py_ssize_t i;                           /* Boucle de parcours          */
+    PyObject *res;                          /* Ressource à ajouter         */
+
+#define PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER PYTHON_WRAPPER_DEF  \
+(                                                                       \
+    _detect_external_tools, "$self, action, content, version, /",       \
+    METH_VARARGS,                                                       \
+    "Abstract method called when a detection of tools used the build"   \
+    " the analyzed content is required.\n"                              \
+    "\n"                                                                \
+    "The expected action is a pychrysalide.PluginModule.PluginAction"   \
+    " value and the content is a pychrysalide.analysis.LoadedContent"   \
+    " instance. The *version* parameter is a boolean value indicating"  \
+    " if some extra details about the tools version are wished.\n"      \
+    "\n"                                                                \
+    "The expected result is a list of strings.\n"                       \
+    "\n"                                                                \
+    "This method has to be defined in order to handle action such as"   \
+    " *DETECTION_OBFUSCATORS*."                                         \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_detect_external_tools"))
+    {
+        args = PyTuple_New(3);
+
+        details = (version ? Py_True : Py_False);
+        Py_INCREF(details);
+
+        PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content)));
+        PyTuple_SetItem(args, 2, details);
+
+        pyret = run_python_method(pyobj, "_detect_external_tools", args);
+
+        if (!PySequence_Check(pyret))
+            g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list"));
+
+        else
+        {
+            length = PySequence_Length(pyret);
+
+            for (i = 0; i < length; i++)
+            {
+                res = PySequence_GetItem(pyret, i);
+
+                if (!PyUnicode_Check(res))
+                    g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                                         _("The returned #%zd value must be a string"));
+
+                else
+                {
+                    *names = realloc(*names, ++(*count) * sizeof(char **));
+                    *names[*count - 1] = strdup(PyUnicode_DATA(res));
+                }
+
+                Py_DECREF(res);
+
+            }
+
+        }
+
+        Py_XDECREF(pyret);
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       INTERFACE INTERNE POUR GREFFONS PYTHON                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini par la GLib pour le greffon Python. */
+G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des greffons Python.                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_python_plugin_class_init(GPythonPluginClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GPluginModuleClass *plugin;             /* Version parente de la classe*/
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize;
+
+    plugin = G_PLUGIN_MODULE_CLASS(klass);
+
+    plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise l'instance d'un greffon Python.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_python_plugin_init(GPythonPlugin *plugin)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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)
+{
+#if 0
+    PyThreadState *tstate;                  /* Contexte d'environnement    */
+
+    /**
+     * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock
+     *
+     * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur,
+     * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante :
+     *
+     *    Fatal Python error: drop_gil: GIL is not locked
+     *
+     * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée
+     * comme dépréciée depuis Python 3.2.
+     *
+     * Donc on choisit les alternatives officielles.
+     *
+     * Cependant, PyThreadState_Get() renvoit l'erreur suivante :
+     *
+     *    Fatal Python error: PyThreadState_Get: no current thread
+     *
+     * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur
+     * est intégré dans l'éditeur.
+     */
+
+    tstate = get_pychrysalide_main_tstate();
+
+    if (tstate != NULL)
+        PyEval_RestoreThread(tstate);
+
+    if (tstate != NULL)
+        PyEval_SaveThread();
+#endif
+
+    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)
+{
+    plugin_interface *final;                /* Interface finale conservée  */
+
+    final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
+
+    if (final != NULL)
+    {
+        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);
+
+        assert(final->required_count == 1);
+
+        if (final->required != NULL)
+            free(final->required);
+
+        if (final->actions != NULL)
+            free(final->actions);
+
+        free(final);
+
+    }
+
+    G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 *path;                             /* Chemin à traiter            */
+
+    path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin)));
+
+    result = strdup(basename(path));
+
+    free(path);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 *g_python_plugin_new(const char *modname, const char *filename)
+{
+    GPythonPlugin *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_PYTHON_PLUGIN(pygobject_get(instance));
+
+    G_PLUGIN_MODULE(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 G_PLUGIN_MODULE(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;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                           MODULE PYTHON POUR LES SCRIPTS                           */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  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.   *
+*                                                                             *
+*  Retour      : Chemin d'accès déterminé, ou NULL en cas d'erreur.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_build_config_filename(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é    */
+
+#define PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD PYTHON_METHOD_DEF        \
+(                                                                           \
+    build_config_filename, "final, /, create=False",                        \
+    METH_VARARGS, py_plugin_module,                                         \
+    "Build a filename suitable for the plugin configuration, ending with"   \
+    " the *final* suffix.\n"                                                \
+    "\n"                                                                    \
+    "If the *create* parameter is set, the path to this filename is"        \
+    " created.\n"                                                           \
+    "\n"                                                                    \
+    "The result is a string or None on failure."                            \
+)
+
+    create = 0;
+
+    if (!PyArg_ParseTuple(args, "s|p", &final, &create))
+        return NULL;
+
+    filename = g_plugin_module_build_config_filename(G_PLUGIN_MODULE(pygobject_get(self)), final, create);
+
+    if (filename != NULL)
+    {
+        result = PyUnicode_FromString(filename);
+        free(filename);
+    }
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Affiche un message dans le journal des messages système.     *
+*                                                                             *
+*  Retour      : Rien en équivalent Python.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    LogMessageType type;                    /* Espèce du message           */
+    const char *msg;                        /* Contenu du message          */
+
+#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."                                                           \
+)
+
+    if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg))
+        return NULL;
+
+    g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg);
+
+    result = Py_None;
+    Py_INCREF(result);
+
+    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));
+    modname = g_plugin_module_get_modname(plugin);
+
+    result = PyUnicode_FromString(modname);
+
+    free(modname);
+
+    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   */
+    const 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);
+
+    result = PyUnicode_FromString(filename);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit la configuration mise en place pour le greffon.      *
+*                                                                             *
+*  Retour      : Configuration dédiée à l'extension.                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_get_config(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    GPluginModule *plugin;                  /* Version native du greffon   */
+    GGenConfig *config;                     /* Configuration associée      */
+
+#define PLUGIN_MODULE_CONFIG_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"            \
+)
+
+    plugin = G_PLUGIN_MODULE(pygobject_get(self));
+    config = g_plugin_module_get_config(plugin);
+
+    if (config == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    else
+    {
+        result = pygobject_new(G_OBJECT(config));
+
+        g_object_unref(G_OBJECT(config));
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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_INCLUDE_THEME_WRAPPER,
+        PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER,
+        PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER,
+        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,
+        PLUGIN_MODULE_LOG_MESSAGE_METHOD,
+        { NULL }
+    };
+
+    static PyGetSetDef py_plugin_module_getseters[] = {
+        PLUGIN_MODULE_MODNAME_ATTRIB,
+        PLUGIN_MODULE_FILENAME_ATTRIB,
+        PLUGIN_MODULE_CONFIG_ATTRIB,
+        { NULL }
+    };
+
+    static PyTypeObject py_plugin_module_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.plugins.PluginModule",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = PLUGIN_MODULE_DOC,
+
+        .tp_methods     = py_plugin_module_methods,
+        .tp_getset      = py_plugin_module_getseters,
+
+        .tp_init        = py_plugin_module_init,
+        .tp_new         = py_plugin_module_new,
+
+    };
+
+    return &py_plugin_module_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.PluginModule'.         *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_plugin_module_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'PluginModule'  */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_plugin_module_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.plugins");
+
+        dict = PyModule_GetDict(module);
+
+        if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type))
+            return false;
+
+        if (!define_plugin_module_constants(type))
+            return false;
+
+    }
+
+    return true;
+
+}
diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h
new file mode 100644
index 0000000..2a31cf2
--- /dev/null
+++ b/plugins/pychrysalide/plugins/plugin.h
@@ -0,0 +1,75 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * plugin.h - prototypes pour les interactions avec un greffon Python
+ *
+ * Copyright (C) 2018 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_PLUGIN_H
+#define _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H
+
+
+#include <Python.h>
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <plugins/plugin.h>
+
+
+
+/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
+
+
+#define G_TYPE_PYTHON_PLUGIN                (g_python_plugin_get_type())
+#define G_PYTHON_PLUGIN(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin))
+#define G_IS_PYTHON_PLUGIN(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN))
+#define G_PYTHON_PLUGIN_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
+#define G_IS_PYTHON_PLUGIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN))
+#define G_PYTHON_PLUGIN_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
+
+
+/* Ligne de représentation de code binaire (instance) */
+typedef struct _GPythonPlugin GPythonPlugin;
+
+/* Ligne de représentation de code binaire (classe) */
+typedef struct _GPythonPluginClass GPythonPluginClass;
+
+
+/* Indique le type défini par la GLib pour le greffon Python. */
+GType g_python_plugin_get_type(void);
+
+/* Crée un greffon à partir de code Python. */
+GPluginModule *g_python_plugin_new(const char *, const char *);
+
+
+
+/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_plugin_module_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.PluginModule'. */
+bool ensure_python_plugin_module_is_registered(void);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */
diff --git a/plugins/python/abackup/plugin.py b/plugins/python/abackup/plugin.py
index aea9a9c..a3222c9 100644
--- a/plugins/python/abackup/plugin.py
+++ b/plugins/python/abackup/plugin.py
@@ -23,10 +23,10 @@
 
 import io
 import tarfile
-from pychrysalide import PluginModule
 from pychrysalide import core
 from pychrysalide.analysis.contents import EncapsulatedContent
 from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.plugins import PluginModule
 from .backup import AndroidBackup
 from .password import PasswordReader
 
diff --git a/plugins/python/apkfiles/apkfiles.py b/plugins/python/apkfiles/apkfiles.py
index 98d31c7..d0fe5b4 100644
--- a/plugins/python/apkfiles/apkfiles.py
+++ b/plugins/python/apkfiles/apkfiles.py
@@ -1,10 +1,10 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-from pychrysalide import PluginModule
 from pychrysalide import core
 from pychrysalide.analysis.contents import EncapsulatedContent
 from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.plugins import PluginModule
 import io
 import zipfile
 
diff --git a/plugins/python/cglimpse/core.py b/plugins/python/cglimpse/core.py
index 29fb535..145d41d 100644
--- a/plugins/python/cglimpse/core.py
+++ b/plugins/python/cglimpse/core.py
@@ -1,7 +1,7 @@
 
-from pychrysalide import PluginModule
 from pychrysalide.glibext import ConfigParam
 from pychrysalide.gui import core
+from pychrysalide.plugins import PluginModule
 
 from .panel import CGlimpsePanel
 
diff --git a/plugins/python/checksec/plugin.py b/plugins/python/checksec/plugin.py
index 6ab213f..7471681 100644
--- a/plugins/python/checksec/plugin.py
+++ b/plugins/python/checksec/plugin.py
@@ -2,9 +2,9 @@
 # -*- coding: utf-8 -*-
 
 from .mitigations import ElfMitigations
-from pychrysalide import PluginModule
 from pychrysalide.core import log_message, LogMessageType
 from pychrysalide.format.elf import ElfFormat
+from pychrysalide.plugins import PluginModule
 
 
 class CheckSec(PluginModule):
diff --git a/plugins/python/liveconv/plugin.py b/plugins/python/liveconv/plugin.py
index 8caeb17..cacdf09 100644
--- a/plugins/python/liveconv/plugin.py
+++ b/plugins/python/liveconv/plugin.py
@@ -1,6 +1,6 @@
 
-from pychrysalide import PluginModule
 from pychrysalide.gui import core
+from pychrysalide.plugins import PluginModule
 
 from .panel import ConvPanel
 
diff --git a/plugins/python/scripting/core.py b/plugins/python/scripting/core.py
index 1b91688..ff912ed 100644
--- a/plugins/python/scripting/core.py
+++ b/plugins/python/scripting/core.py
@@ -2,11 +2,11 @@
 from gi.repository import GLib, Gtk
 import os
 
-from pychrysalide import PluginModule
 from pychrysalide import core
 from pychrysalide.gui import core as gcore
 from pychrysalide.gui import MenuBar
 from pychrysalide.gtkext import EasyGtk
+from pychrysalide.plugins import PluginModule
 
 from .panel import ScriptPanel
 
-- 
cgit v0.11.2-87-g4458