From 64b690f0038e01e807c1ec8d62041057fd38b4b8 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 16 Jan 2025 02:00:28 +0100
Subject: Improve the plugins management.

---
 plugins/pe/core.c               |  15 +++--
 plugins/pychrysalide/bindings.c | 125 ++++++++++++----------------------
 plugins/pychrysalide/bindings.h |  14 ++--
 plugins/pychrysalide/core-ui.c  |   3 +-
 plugins/pychrysalide/core.c     |  42 +++++++++++-
 src/core/core.h                 |   8 ++-
 src/plugins/native-int.h        |  13 +++-
 src/plugins/native.c            |  29 ++++++--
 src/plugins/native.h            |   7 ++
 src/plugins/pglist.c            | 144 ++++++++++++++++++++++------------------
 src/plugins/plugin.c            |  12 +++-
 11 files changed, 240 insertions(+), 172 deletions(-)

diff --git a/plugins/pe/core.c b/plugins/pe/core.c
index 42f712d..9d30a34 100644
--- a/plugins/pe/core.c
+++ b/plugins/pe/core.c
@@ -62,8 +62,8 @@ static void g_pe_plugin_finalize(GPePlugin *);
 /* Prend acte de l'activation du greffon. */
 static bool g_pe_plugin_enable(GPePlugin *);
 
-/* Prend acte de l'extinction du greffon. */
-static void g_pe_plugin_disable(GPePlugin *);
+/* Prend acte de la désactivation du greffon. */
+static bool g_pe_plugin_disable(GPePlugin *);
 
 
 
@@ -288,16 +288,21 @@ static bool g_pe_plugin_enable(GPePlugin *plugin)
 *                                                                             *
 *  Paramètres  : plugin = greffon à manipuler.                                *
 *                                                                             *
-*  Description : Prend acte de l'extinction du greffon.                       *
+*  Description : Prend acte de la désactivation du greffon.                   *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void g_pe_plugin_disable(GPePlugin *plugin)
+static bool g_pe_plugin_disable(GPePlugin *plugin)
 {
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    return result;
 
 }
 
diff --git a/plugins/pychrysalide/bindings.c b/plugins/pychrysalide/bindings.c
index 02850d1..99491d6 100644
--- a/plugins/pychrysalide/bindings.c
+++ b/plugins/pychrysalide/bindings.c
@@ -25,16 +25,15 @@
 #include "bindings.h"
 
 
-#ifdef PYTHON_PACKAGE
-#   include <dlfcn.h>
-#endif
+#include <assert.h>
+#include <dlfcn.h>
 #include <pygobject.h>
 #include <stdio.h>
 
 
-#include <config.h>
 #include <common/cpp.h>
 #include <common/extstr.h>
+#include <core/core.h>
 #include <plugins/pglist.h>
 #include <plugins/self.h>
 
@@ -125,6 +124,8 @@ static void restore_original_pygobject_type(PyTypeObject *);
 /* ------------------------ FONCTIONS GLOBALES DE CHRYSALIDE ------------------------ */
 
 
+/* Assure le plein chargement dans un interpréteur Python. */
+static bool init_python_interpreter_for_standalone_mode(const pyinit_details_t *);
 
 /* Point de sortie pour l'initialisation de Python. */
 static void PyExit_pychrysalide(void);
@@ -915,7 +916,7 @@ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details)
             PyErr_SetString(PyExc_SystemError, "failed to load all PyChrysalide components.");
 
         else if (details->standalone)
-            status = do_global_init();
+            status = init_python_interpreter_for_standalone_mode(details);
 
         if (!status)
         {
@@ -1060,13 +1061,11 @@ void log_pychrysalide_exception(const char *prefix, ...)
 /* ---------------------------------------------------------------------------------- */
 
 
-
-
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : py_gobj_def = définition de type actuelle. [OUT]             *
+*  Paramètres  : details = précisions de chargement complémentaires.          *
 *                                                                             *
-*  Description : Restore une ancienne définition de type GObject au besoin.   *
+*  Description : Assure le plein chargement dans un interpréteur Python.      *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -1074,103 +1073,77 @@ void log_pychrysalide_exception(const char *prefix, ...)
 *                                                                             *
 ******************************************************************************/
 
-bool do_global_init(void)
+static bool init_python_interpreter_for_standalone_mode(const pyinit_details_t *details)
 {
-
-    return true;
-    return false;
-
-
-#if 0
-
-
     bool result;                            /* Bilan à retourner           */
     int ret;                                /* Bilan de préparatifs        */
-#ifdef PYTHON_PACKAGE
     Dl_info info;                           /* Informations dynamiques     */
-#endif
+    GModule *module;                        /* Structure de chargement GLib*/
     GPluginModule *self;                    /* Représentation interne      */
-    PluginStatusFlags self_flags;           /* Fanions à mettre à jour     */
+
+    result = false;
 
     ret = Py_AtExit(PyExit_pychrysalide);
     if (ret == -1)
     {
         PyErr_SetString(PyExc_SystemError, "failed to register a cleanup function.");
-        goto exit_and_restore;
+        goto exit;
+    }
+
+    if (!load_core_components(ACC_ALL_COMPONENTS))
+    {
+        PyErr_SetString(PyExc_SystemError, "unable to load core components.");
+        goto exit;
     }
 
     /**
-     * Si cette extension pour Python est chargée depuis un dépôt Python,
-     * elle ne se trouve pas dans le répertoire classique des extensions et
-     * n'est donc pas chargée et enregistrée comme attendu.
+     * Le module chargé par Python n'apparaît pas dans la liste des greffons de
+     * Chrysalide et ne peut donc pas être référencé comme dépendance par d'autres
+     * extensions.
      *
-     * Cet enregistrement est donc forcé ici.
+     * Par ailleurs, lors de la recherche d'autres greffons via l'appel à la
+     * fonction init_all_plugins() ci-après, il faut que le nom du greffon soit
+     * déjà réservé pour faire échouer le second chargement du greffon courant
+     * lors du parcours des répertoires conservant les fichiers d'extensions.
      */
 
-#ifdef PYTHON_PACKAGE
-
     ret = dladdr(__FUNCTION__, &info);
     if (ret == 0)
     {
         LOG_ERROR_DL_N("dladdr");
 
-
-        // err msg
-
-
-        Py_DECREF(result);
-        result = NULL;
-
-        goto exit_and_restore;
-    }
-
-    self = g_plugin_module_new(info.dli_fname);
-    assert(self != NULL);
-
-    register_plugin(self);
-
-#endif
-
-
-    if (!load_core_components(ACC_GLOBAL_VARS))
-    {
-        PyErr_SetString(PyExc_SystemError, "unable to load core components.");
+        PyErr_SetString(PyExc_SystemError, "failed to force bindings registration.");
         goto exit;
-    }
 
-    init_all_plugins(false);
+    }
 
-    lock_plugin_list_for_reading();
+    module = g_module_open(info.dli_fname, G_MODULE_BIND_LAZY);
+    assert(module != NULL);
 
-    self = get_plugin_by_name("PyChrysalide", NULL);
-    assert(self != NULL);
+    self = details->create_self(module);
 
-    self_flags = g_plugin_module_get_flags(self);
-    self_flags &= ~(PSF_FAILURE | PSF_LOADED);
-    self_flags |= (status ? PSF_LOADED : PSF_FAILURE);
+    /* A ce stade, le greffon a été chargé correctement */
+    g_plugin_module_override_flags(self, PSF_LOADED);
 
-    g_plugin_module_override_flags(self, self_flags);
+    register_plugin(self);
 
     unref_object(self);
 
-    unlock_plugin_list_for_reading();
-
-    load_remaning_plugins();
-
-
+    /**
+     * Intégration des fonctionnalités portées par d'autres greffons.
+     */
 
+    result = true;
 
+    init_all_plugins(true);
 
- done:
+ exit:
 
     return result;
 
-#endif
-
 }
 
 
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : -                                                            *
@@ -1185,24 +1158,8 @@ bool do_global_init(void)
 
 static void PyExit_pychrysalide(void)
 {
-    //assert(_standalone);
-
-    /*
-    extern void set_current_project(void *project);
-
-    set_current_project(NULL);
-    */
-
-#ifdef TRACK_GOBJECT_LEAKS
-    remember_gtypes_for_leaks();
-#endif
-
     exit_all_plugins();
 
-    //unload_all_core_components(true);
-
-#ifdef TRACK_GOBJECT_LEAKS
-    dump_remaining_gtypes();
-#endif
+    unload_core_components(ACC_ALL_COMPONENTS);
 
 }
diff --git a/plugins/pychrysalide/bindings.h b/plugins/pychrysalide/bindings.h
index e9ee421..1758747 100644
--- a/plugins/pychrysalide/bindings.h
+++ b/plugins/pychrysalide/bindings.h
@@ -36,9 +36,13 @@
 #include <Python.h>
 
 
+#include <gmodule.h>
 #include <stdbool.h>
 
 
+#include <plugins/plugin.h>
+
+
 
 /* Charge un module GI dans Python avec une version attendue. */
 bool import_namespace_from_gi_repository(const char *, const char *);
@@ -50,6 +54,12 @@ typedef struct _pyinit_details_t
 
     bool (* populate_extra) (void);         /* Ajout de types ?            */
 
+    /**
+     * Prototype de la fonction de création, à garder synchronisé avec
+     * NATIVE_PLUGIN_ENTRYPOINT() (cf. native-int.h).
+     */
+    GPluginModule * (* create_self) (GModule *);
+
 } pyinit_details_t;
 
 /* Implémente le point d'entrée pour l'initialisation de Python. */
@@ -60,8 +70,4 @@ void log_pychrysalide_exception(const char *, ...);
 
 
 
-bool do_global_init(void);
-
-
-
 #endif  /* _PLUGINS_PYCHRYSALIDE_BINDINGS_H */
diff --git a/plugins/pychrysalide/core-ui.c b/plugins/pychrysalide/core-ui.c
index 32d3516..1b332b7 100644
--- a/plugins/pychrysalide/core-ui.c
+++ b/plugins/pychrysalide/core-ui.c
@@ -179,7 +179,7 @@ GPluginModule *g_pychrysalide_plugin_ui_new(GModule *module)
 {
     GPyChrysalidePluginUI *result;          /* Structure à retourner       */
 
-    result = g_object_new(G_TYPE_PYCHRYSALIDE_PLUGIN, NULL);
+    result = g_object_new(G_TYPE_PYCHRYSALIDE_PLUGIN_UI, NULL);
 
     if (!g_pychrysalide_plugin_ui_create(result, module))
         g_clear_object(&result);
@@ -310,6 +310,7 @@ PyMODINIT_FUNC PyInit_pychrysalideui(void)
     details.standalone = _standalone;
 
     details.populate_extra = NULL;
+    details.create_self = g_pychrysalide_plugin_ui_new;
 
     result = init_python_pychrysalide_module(&details);
 
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index fde1028..0e72b46 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -390,16 +390,53 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin)
 
 static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin)
 {
+    bool result;                            /* Bilan à retourner           */
+    bool standalone;                        /* Nature du chargement        */
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
 
-    gstate = PyGILState_Ensure();
+    result = true;
+
+    /**
+     * Le champ plugin->py_module n'est défini que via la fonction
+     * g_pychrysalide_plugin_enable(), qui n'est pas sollicitée lorsque
+     * le module PyChrysalide est mis en place directement par Python.
+     *
+     * L'analyse de ce champ pour retrouver la situation courante est
+     * plus fiable que celle du champ _standalone, potentiellement
+     * cohérent dans la version UI du greffon et resté à son état
+     * initial ici.
+     */
+
+    standalone = (plugin->py_module == NULL);
+
+    /**
+     * Si on se trouve embarqué dans un interpréteur Python, le déchargement
+     * des greffons est organisé à partir de la fonction PyExit_pychrysalide(),
+     * directement appelée depuis un contexte Python.
+     *
+     * Un verrou n'est alors pas souhaité ici :
+     *
+     *   python3d: ../Python/pystate.c:1687: PyGILState_Ensure: Assertion `gilstate->autoInterpreterState' failed.
+     *
+     * Avec :
+     *
+     *   $ python3d --version
+     *   Python 3.11.2
+     *
+     */
+
+    if (!standalone)
+        gstate = PyGILState_Ensure();
 
     clear_all_accesses_to_python_modules();
 
     Py_XDECREF(plugin->py_module);
     plugin->py_module = NULL;
 
-    PyGILState_Release(gstate);
+    if (!standalone)
+        PyGILState_Release(gstate);
+
+    return result;
 
 }
 
@@ -720,6 +757,7 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
     details.standalone = _standalone;
 
     details.populate_extra = NULL;
+    details.create_self = g_pychrysalide_plugin_new;
 
     result = init_python_pychrysalide_module(&details);
 
diff --git a/src/core/core.h b/src/core/core.h
index 7c50f6c..e5f0a60 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -32,9 +32,11 @@
 /* Eléments à (dé)charger disponibles */
 typedef enum _AvailableCoreComponent
 {
-    ACC_NONE          = (0 << 0),           /* Statut initial              */
-    ACC_GLOBAL_VARS   = (1 << 0),           /* Singletons globaux          */
-    ACC_SCAN_FEATURES = (1 << 0),           /* Espace de noms pour scan    */
+    ACC_NONE            = (0 << 0),         /* Statut initial              */
+    ACC_GLOBAL_VARS     = (1 << 0),         /* Singletons globaux          */
+    ACC_SCAN_FEATURES   = (1 << 1),         /* Espace de noms pour scan    */
+
+    ACC_ALL_COMPONENTS  = (1 << 2) - 1
 
 } AvailableCoreComponent;
 
diff --git a/src/plugins/native-int.h b/src/plugins/native-int.h
index 8b8e0eb..575994f 100644
--- a/src/plugins/native-int.h
+++ b/src/plugins/native-int.h
@@ -41,7 +41,18 @@ struct _GNativePlugin
 {
     GPluginModule parent;                   /* A laisser en premier        */
 
-    GModule *module;                        /* Abstration de manipulation  */
+    /**
+     * Le module porte le code et les données en mémoire.
+     *
+     * Les fonctions *_dispose() et *_finalize() accompagnant la libération des
+     * greffons de la mémoire ne peuvent donc pas libérer ce module car elles
+     * scieraient la branche sur laquelle elles se trouvent.
+     *
+     * Par ailleurs, même s'ils sont conservés dans chaque greffon, les modules
+     * sont mis en place dans le code principal. C'est donc ce dernier qui les
+     * libère, dans la fonction on_plugin_ref_toggle().
+     */
+    GModule *module;                        /* Structure de chargement GLib*/
 
 };
 
diff --git a/src/plugins/native.c b/src/plugins/native.c
index fedccbe..de20abe 100644
--- a/src/plugins/native.c
+++ b/src/plugins/native.c
@@ -131,12 +131,6 @@ static void g_native_plugin_init(GNativePlugin *plugin)
 
 static void g_native_plugin_dispose(GNativePlugin *plugin)
 {
-    if (plugin->module != NULL)
-    {
-        g_module_close(plugin->module);
-        plugin->module = NULL;
-    }
-
     G_OBJECT_CLASS(g_native_plugin_parent_class)->dispose(G_OBJECT(plugin));
 
 }
@@ -194,6 +188,29 @@ bool g_native_plugin_create(GNativePlugin *plugin, const char *name, const char
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                                                                             *
+*  Description : Renvoie la structure opaque associée au module en mémoire.   *
+*                                                                             *
+*  Retour      : Structure de chargement côté GLib.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GModule *g_native_plugin_get_module(const GNativePlugin *plugin)
+{
+    GModule *result;                        /* Accès au module à renvoyer  */
+
+    result = plugin->module;
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
diff --git a/src/plugins/native.h b/src/plugins/native.h
index 205342c..18039c8 100644
--- a/src/plugins/native.h
+++ b/src/plugins/native.h
@@ -26,6 +26,9 @@
 #define _PLUGINS_NATIVE_H
 
 
+#include <gmodule.h>
+
+
 #include "../glibext/helpers.h"
 
 
@@ -35,5 +38,9 @@
 DECLARE_GTYPE(GNativePlugin, g_native_plugin, G, NATIVE_PLUGIN);
 
 
+/* Renvoie la structure opaque associée au module en mémoire. */
+GModule *g_native_plugin_get_module(const GNativePlugin *);
+
+
 
 #endif  /* _PLUGINS_NATIVE_H */
diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c
index 277e4f5..6dc2d9c 100644
--- a/src/plugins/pglist.c
+++ b/src/plugins/pglist.c
@@ -37,9 +37,10 @@
 
 
 #include "manager.h"
+#include "native.h"
 #include "plugin-int.h"
 #include "../common/cpp.h"
-#include "../common/extstr.h"       // REMME ?
+#include "../common/extstr.h"
 #include "../core/logs.h"
 #include "../core/nox.h"
 #include "../core/paths.h"
@@ -69,6 +70,9 @@ static void browse_directory_for_plugins(const char *);
 /* Suit les variations du compteur de références d'un greffon. */
 static void on_plugin_ref_toggle(gpointer, GPluginModule *, gboolean);
 
+/* Fournit le greffon répondant à un nom donné. */
+static GPluginModule *_find_plugin_by_name(const char *, size_t *);
+
 
 
 /******************************************************************************
@@ -134,71 +138,23 @@ bool init_all_plugins(bool load)
 
 void exit_all_plugins(void)
 {
-
-#if 0 //////
-
-
     size_t i;                               /* Boucle de parcours          */
-    const plugin_interface *pg_iface;       /* Définition du greffon       */
 
     lock_plugin_list_for_reading();
 
-    if (_pg_list != NULL)
+    for (i = 0; i < _pg_count; i++)
     {
-        for (i = 0; i < _pg_count; i++)
-        {
-            assert(_pg_list[i] != NULL);
-
-            /**
-             * Si le greffon a conduit à la mise en place d'autres greffons, le
-             * système de dépendances ne suffit pas pour le décompte des références :
-             * le greffon voit à un instant T son compteur décroître ici ; à un
-             * instant T+1, un greffon fils décrémente à son tour le compteur vers
-             * le greffon principal.
-             *
-             * Le compteur du conteneur tombe alors à 0, et le code correspondant
-             * est retiré. Lorsque que le flot d'exécution revient à la procédure
-             * de sortie du second greffon, son code n'est plus en mémoire.
-             *
-             * On s'assure donc que les greffons qui génèrent d'autres greffons
-             * sont bien traités en dernier.
-             */
-
-            pg_iface = g_plugin_module_get_interface(_pg_list[i]);
-
-            if (pg_iface != NULL && pg_iface->container)
-                g_object_ref(_pg_list[i]);
-
-            g_object_unref(_pg_list[i]);
-
-        }
-
-        for (i = 0; i < _pg_count; i++)
-        {
-            if (_pg_list[i] == NULL)
-                continue;
-
-            pg_iface = g_plugin_module_get_interface(_pg_list[i]);
-
-            if (pg_iface == NULL || !pg_iface->container)
-                continue;
-
-            g_object_unref(_pg_list[i]);
-
-        }
+        assert(_pg_list[i] != NULL);
+        unref_object(_pg_list[i]);
+    }
 
+    if (_pg_list != NULL)
         free(_pg_list);
 
-    }
-
     unlock_plugin_list_for_reading();
 
     g_rw_lock_clear(&_pg_lock);
 
-
-
-#endif
-
 }
 
 
@@ -485,6 +441,7 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea
     const char *name;                       /* Désignation du greffon      */
     size_t index;                           /* Indice du greffon           */
     GPluginModule *same;                    /* Juste pour la récupération  */
+    GModule *module;                        /* Structure de chargement GLib*/
 
     if (last)
     {
@@ -492,15 +449,44 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea
 
         name = g_plugin_module_get_name(plugin);
 
-        same = get_plugin_by_name(name, &index);
+        /**
+         * Les mécanismes de g_object_unref() prennent en compte la bascule d'un
+         * compteur de références initialement à 2 avant appel pour déclencher
+         * cet appel à on_plugin_ref_toggle() mis en place par g_object_add_toggle_ref().
+         *
+         * Incrémenter ce compteur à nouveau, via get_plugin_by_name(), puis le
+         * décrémenter ensuite via unref_object() va conduire à une nouvelle
+         * bascule des statuts de suivi dans g_object_unref().
+         *
+         * Il est ainsi impératif de rechercher une instance du greffon dans
+         * la liste des extensions sans toucher au compteur de références.
+         */
+
+        same = _find_plugin_by_name(name, &index);
+
         assert(same != NULL);
         assert(same == plugin);
 
-        g_clear_object(&_pg_list[index]);
+        _pg_list[index] = NULL;
+
+        /**
+         * Suppression de la dernière référence.
+         */
+
+        if (G_IS_NATIVE_PLUGIN(plugin))
+            module = g_native_plugin_get_module(G_NATIVE_PLUGIN(plugin));
+        else
+            module = NULL;
 
         g_object_remove_toggle_ref(G_OBJECT(same), (GToggleNotify)on_plugin_ref_toggle, NULL);
 
-        unref_object(same);
+        /**
+         * Plus aucun code issu du greffon n'est désormais utile. Le module associé peut
+         * être libéré de la mémoire.
+         */
+
+        if (module != NULL)
+            g_module_close(module);
 
     }
 
@@ -622,13 +608,18 @@ void load_remaning_plugins(void)
 
     /* Supprime les greffons non chargés */
 
-    for (i = 0; i < _pg_count; i++)
+    for (i = 0; i < _pg_count;)
     {
         flags = g_plugin_module_get_flags(_pg_list[i]);
 
-        if ((flags & PSF_LOADED) == 0)
+        if (flags & PSF_LOADED)
+            i++;
+
+        else
         {
-            g_object_unref(G_OBJECT(_pg_list[i]));
+            unref_object(_pg_list[i]);
+
+            assert(_pg_list[i] == NULL);
 
             memmove(&_pg_list[i], &_pg_list[i + 1], (_pg_count - i - 1) * sizeof(GPluginModule *));
             _pg_count--;
@@ -655,11 +646,12 @@ void load_remaning_plugins(void)
 *                                                                             *
 *  Retour      : Instance du greffon trouvé ou NULL si aucun.                 *
 *                                                                             *
-*  Remarques   : -                                                            *
+*  Remarques   : Le compteur de référence d'un greffon trouvé n'est pas       *
+*                modifié.                                                     *
 *                                                                             *
 ******************************************************************************/
 
-GPluginModule *get_plugin_by_name(const char *name, size_t *index)
+static GPluginModule *_find_plugin_by_name(const char *name, size_t *index)
 {
     GPluginModule *result;                  /* Greffon trouvé à renvoyer   */
     size_t i;                               /* Boucle de parcours          */
@@ -682,7 +674,6 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
         if (strcmp(current, name) == 0)
         {
             result = _pg_list[i];
-            ref_object(result);
 
             if (index != NULL)
                 *index = i;
@@ -698,6 +689,33 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : name  = désignation du greffon recherché.                    *
+*                index = indice du greffon trouvé. [OUT]                      *
+*                                                                             *
+*  Description : Fournit le greffon répondant à un nom donné.                 *
+*                                                                             *
+*  Retour      : Instance du greffon trouvé ou NULL si aucun.                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GPluginModule *get_plugin_by_name(const char *name, size_t *index)
+{
+    GPluginModule *result;                  /* Greffon trouvé à renvoyer   */
+
+    result = _find_plugin_by_name(name, index);
+
+    if (result != NULL)
+        ref_object(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : count = nombre de greffons trouvés. [OUT]                    *
 *                                                                             *
 *  Description : Fournit la liste de l'ensemble des greffons.                 *
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index d14e656..9438f9f 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -159,10 +159,14 @@ static void g_plugin_module_dispose(GPluginModule *plugin)
 
     unlock_plugin_list_for_reading();
 
-    class = G_PLUGIN_MODULE_GET_CLASS(plugin);
+    if (plugin->flags & PSF_LOADED)
+    {
+        class = G_PLUGIN_MODULE_GET_CLASS(plugin);
 
-    if (class->disable != NULL)
-        class->disable(plugin);
+        if (class->disable != NULL)
+            class->disable(plugin);
+
+    }
 
     G_OBJECT_CLASS(g_plugin_module_parent_class)->dispose(G_OBJECT(plugin));
 
@@ -185,6 +189,8 @@ static void g_plugin_module_finalize(GPluginModule *plugin)
 {
     size_t i;                               /* Boucle de parcours          */
 
+    printf("[!!!] Finalizing plugin %s\n", plugin->name);
+
     if (plugin->name != NULL)
         free(plugin->name);
 
-- 
cgit v0.11.2-87-g4458