Application qui charge des DLLs dynamiquement

Résolu
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011 - 27 avril 2011 à 10:32
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011 - 28 avril 2011 à 17:24
Bonjour, à tous!

Je viens vers vous car étant novice en C#, j'aurais besoin d'aide. Je suis actuellement en stage et on me demande de réaliser un service Windows qui puisse appeler des DLLs dynamiquement et qu'elles soient ensuite implanté sur des threads.

Actuellement, j'ai une DLL "dix" qui compte de 10 en 10 et une DLL "vingt" qui compte de 20 en 20 et toutes les deux écrivent sur des fichiers .log. Je les appelles depuis le service Windows avec le même espace de noms et les implantes sur des threads que je démarre ou que j'arrête dans les procédures OnStart() et OnStop(). Le problème est que selon mon maître de stage je ne les appelles pas dynamiquement et je ne comprends pas tellement la différence au niveau du code.

Mon maître de stage m'a mit sur la voie de la classe Activator.CreateInstance... mais après de nombreuses recherches, je bloque un peu car je ne sais pas comment l'utiliser. Si ils y en a qui comprennent mon problème et qui aurait des liens ou des conseils à me donner, j'en serais ravi!

Voici le code du service :

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess; // pour utiliser un service windows
using System.Text; // pour écrire dans un fichier texte
using Service_Thread_comptage; // pour utiliser les 2 DLLs : dixendix et vingtenvingt
using System.Threading; // pour utiliser les Threads
using System.IO; // pour écrire dans un fichier log
using System.Reflection;
using System.Resources;



namespace Service_Thread_comptage
{
public partial class Service1 : ServiceBase
{

}

public Service1()
{
InitializeComponent();

}

Thread dixdix; // Création d'un premier Thread qui sera affecté a la méthode "Thread10"
Thread vingtvingt; // Création d'un deuxième Thread qui sera affecté a la méthode "Thread20"

protected override void OnStart(string[] args)
{


// Ecriture dans "dixendix" de la date et l'heure à laquelle
// le 10 en 10 commence
StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
sw1.WriteLine("Démarrage du 10 en 10 : " + DateTime.Now.ToLongTimeString());
sw1.Close();

// Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
// le 20 en 20 commence
StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
sw2.WriteLine("Démarrage du 20 en 20: " + DateTime.Now.ToLongTimeString());
sw2.Close();


// Appel de la DLL "dix" et création du Thread10
dixdix = new Thread(new ThreadStart(Dixendix.Thread10));
dixdix.Start();

// Appel de la DLL "vngt" et création du Thread20
vingtvingt = new Thread(new ThreadStart(Vingtenvingt.Thread20));
vingtvingt.Start();



}

protected override void OnStop()
{
// Ecriture dans "dixendix" de la date et l'heure à laquelle
// le 10 en 10 s'arrête
StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
sw1.WriteLine("Arrêt du 10 en 10 : " + DateTime.Now.ToLongTimeString());
sw1.Close();

// Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
// le 20 en 20 s'arrête
StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
sw2.WriteLine("Arrêtdu 20 en 20: " + DateTime.Now.ToLongTimeString());
sw2.Close();

dixdix.Abort(); // On demande au runtime d'arrêter le Thread10
vingtvingt.Abort(); // On demande au runtime d'arrêter le Thread20

}

protected override void OnShutdown()
{

// Ecriture dans "dixendix" de la date et l'heure à laquelle
// le 10 en 10 s'arrête
StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
sw1.WriteLine("Arrêt du système à : " + DateTime.Now.ToLongTimeString());
sw1.Close();

// Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
// le 20 en 20 s'arrête
StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
sw2.WriteLine("Arrêt du système à : " + DateTime.Now.ToLongTimeString());
sw2.Close();

dixdix.Abort(); // On demande au runtime d'arrêter le Thread10
vingtvingt.Abort(); // On demande au runtime d'arrêter le Thread20
}
}
}

18 réponses

billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
27 avril 2011 à 11:17
Bonjour,

Par dynamiquement, ton maître de stage parle de non-explicitement dans ton code.
En effet, ton code est figé aux deux dlls (Dix et Vingt) et appelle explicitement ces dernières.

Il te faut faire un code plus générique qui serait capable de charger tout seul les dlls d'un répertoire (par exemple) et de toutes les lancer. L'intérêt réside dans le fait que ton service windows devient aveugle de ce qui se passe dans chaque dll et il devient aisé d'ajouter une nouvelle dll sans modifier le code de ton service. Simple et efficace...

Maintenant, l'informatique n'est pas magique et il va falloir que la méthode de la dll qui est lancée soit spécifié (en constante ou dans un fichier de config, à toi de voir) et que toutes les dlls soient à un emplacement connu (un répertoire dans le fichier de config par exemple).

Personnellement, je te conseillerai (de tête, j'oublie peut-être des choses) la solution suivante:
1) Créé une librairie .Net (dll) qui contient une interface qui obligera toutes les dlls à implémenter le même type de classe pour lancer les traitements.
public interface IProcess
{
  void Start();
}

2) Toutes les dlls de traitement (Dix, Vingt et toutes les prochaines) devront contenir une classe (par souci de simplicité, on va dire que la classe porte le même nom que la dll... ;p ) qui implémente l'interface IProcess.
Exemple: dans la librairie "Dix.dll"
public class Dix : IProcess
{
  public void Start()
  {
    // Ton traitement...
  }
}

3) Ainsi, ton service windows (qui référence aussi la librarie qui contient IProcess) n'a plus qu'à (facile à dire mais va falloir le faire ;p) charger toutes les dlls et lancer les traitements de chacune dans un thread.
Exemple:
protected override void OnStart(string[] args)
{
// Pour toutes les dll de ton répertoire...
foreach (string path in Directory.GetFiles(@"c:\Traitement", "*.dll"))
{
Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie...
IProcess process = (IProcess) Activator.CreateInstance(asm.GetType(Path.GetFileName(path)));// Création du traitement
process.Start();//Lancement du process... à la place ceci, je te laisse faire tout seul le lancement de la méthode Start() dans un thread...
}
}

Ce qui manque:
- Je n'ai pas fait le traitement des exceptions ou autre.
- La gestion du lancement des traitements dans un thread chacun.
Tu excuseras mes erreurs de codage si il y en a mais l'idée est là...

A toi de jouer maintenant !

Bonne journée,

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
3
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
27 avril 2011 à 11:18
Pour le dernier exemple que j'ai oublié de mettre en code ;p
protected override void OnStart(string[] args)
{
// Pour toutes les dll de ton répertoire...
foreach (string path in Directory.GetFiles(@"c:\Traitement", "*.dll"))
{
Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie...
IProcess process = (IProcess) Activator.CreateInstance(asm.GetType(Path.GetFileName(path)));// Création du traitement
process.Start();//Lancement du process... à la place ceci, je te laisse faire tout seul le lancement de la méthode Start() dans un thread...
}
}


Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
3
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
27 avril 2011 à 11:36
Merci beaucoup Billou_13 d'avoir pris un peu de ton temps pour m'expliquer tout ça. J'y vois plus clair maintenant.

Je vais suivre tes conseils et essayer de faire marcher tout ça!

Bonne journée à toi aussi!

Sisilegeek.
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
27 avril 2011 à 15:01
Me revoilà! J'ai des petites questions à te poser sur quelques détails qui m'échappent :

- comment fais-tu le lien entre le l'interface et les différents code des DLLs? car j'ai bien mit le ".. : IProcess" dans chaque DLLs mais IProcess reste introuvable lorsque je compile le tout. Voici le code de ma dll "Dixendix", après il y a le code de l'interface et enfin le bout de code du service qui appelle l'interface. Je précise que je travaille sur VS 2008 et que j'ai bien mit les ajouts de référence entre les différents projets dans l'ordre suivant : Service>>Interface>>(DLL "Dixendix" & DLL "Vingtenvingt") (>> dépend de)
> code de ma DLL "Dixendix"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;

namespace Service_Thread_comptage // même espace de noms pour les DLLs
{
    public class Dixendix : IProcess
    {
        public static void Thread10()
        {
            int Nombre = 0; 
             
            // Tant que le thread n'est pas tué, on travaille
            while (Thread.CurrentThread.IsAlive)
            {
                // Attente de 1s
                Thread.Sleep(1000);
                Nombre = Nombre + 10;

                // Ecriture du Nombre dans le fichier "dixendix"
                StreamWriter sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine(Nombre);
                sw.Close();
            }
        }
    }
}



=> Le code de mon interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

public interface IProcess
{
    void Start();

}


=> bout de code du service
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;   // pour utiliser un service windows
using System.Text;  // pour écrire dans un fichier texte
using Service_Thread_comptage; // pour utiliser les 2  DLLs : dixendix et vingtenvingt
using System.Threading; // pour utiliser les Threads
using System.IO; // pour écrire dans un fichier log
using System.Reflection;
using System.Resources;

namespace Service_Thread_comptage
{
    public partial class Service1 : ServiceBase
    {

       
        public Service1()
        {
            InitializeComponent();
            
        }

        Thread dll; // création du thread sur lequel sera implémenté les dlls

        protected override void OnStart(string[] args)
        {
            
            
            // Ecriture dans "dixendix" de la date et l'heure à laquelle
            // le 10 en 10 commence
            StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
            sw1.WriteLine("Démarrage du 10 en 10 : " + DateTime.Now.ToLongTimeString());
            sw1.Close();

            // Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
            // le 20 en 20 commence
            StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
            sw2.WriteLine("Démarrage du 20 en 20: " + DateTime.Now.ToLongTimeString());
            sw2.Close();

            int i = 0;
            // Pour toutes les DLLs de ton répertoire...
            foreach (string path in Directory.GetFiles(@"C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\Service_Thread_comptage\Service_Thread_comptage\bien\Debug", "Dixendix.dll"))
            {
                Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie
                IProcess process = (IProcess)Activator.CreateInstance(asm.GetType(Path.GetFileName(path)));// Création du traitement
            
                dll = new Thread(new ThreadStart(process.Start)); // on implémente la méthode Start de l'interface dans un thread.
                dll.Start(); // Lancement du thread
               
            }


- Deuixième question : comment peux-tu implanter chaque DLL sur un thread différent en utilisant "for each..."? car sur le bout de code qui est écrit au dessus, le thread porte le même nom lors de chaque création du traitement donc c'est comme si il réécrivait dessus.


Merci de ta réponse!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
27 avril 2011 à 15:12
Salut,

Je suis désolé, je n'ai pas beaucoup de temps pour répondre, tu m'excuseras donc de faire court (si besoin, je repasserai qd j'aurai plus de temps, tu me diras).

Pour tes questions:
1) c'est pour cela que je t'ai proposé de faire un librairie à part qui contient uniquement l'interface. Tu créé un nouveau projet de type librairie de classes .Net (dll) qui sera référencé par tous les autres projets: Dix.dll, Vingt.dll et ton projet service windows.
Ainsi, Dix et Vingt peuvent implémenter l'interface et le service windows ne connait que celle-ci (l'interface) mais ça lui suffit car son but est juste de lancer la méthode (ce qu'il se passe dedans, il s'en fiche... ;p).

2) Tout simplement en utilisant une liste de Thread:
List<Thread> allThreads = new List<Thread>();
Thread thread = new Thread(new ThreadStart(process.Start));
thread.Start();
allThreads.Add(thread);


Ainsi, pour arrêter tous les threads dans le OnStop():
foreach(Thread thread in allThreads)
{
  thread.Abort();
}


Le Abort() est peut-être un peu trop brutal... à toi de voir ;p

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
27 avril 2011 à 18:09
Merci pour la liste des threads, je ne connaissais pas!

Par contre j'ai toujours des petits soucis avec la connexion entre les éléments. J'expose ma situation :

J'ai crée comme tu m'avais dit une bibliotèque de classe, à part, pour l'interface, avec le code tout simple que tu m'avais montré et je l'ai ajouté dans le projet, c'est à dire que dans l'explorateur de solutions, il y avait le projet : Dixendix (dll), Vingtenvingt(dll), Service_Thread_comptage (service) et Interface (interface en dll) avec dans chacun des 3 premiers que je viens de citer, une référence vers Interface. Le projet se compile bien, le code me semble correct et les références entre les différents éléments me paraissent bonnes. Ensuite, j'ai copier les dll dix.dll et vingt.dll dans le répertoire suivant : "C:\Traitement".

J'installe ensuite le service Windows via la commande "InstallUtil" et voici ce qu'il me met lorsque je le lance :

" Le service a démarré puis s'est arrêté. Certains services peuvent s'arrêter automatiquement s'ils n'ont aucune tâche à effectuer."

J'ai donc bien l'impression que le service n'a aucune tâche à effectuer donc qu'il ne fait la relation avec l'interface, ou peut-être les dlls ne font pas la relation avec l'interface.

Voici le code de tout mon projet si ça peut t'aider :

En tout cas, merci de ton aide, j'apprécie beaucoup!

=> Code du Service
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess; // pour utiliser un service windows
using System.Text;  // pour écrire dans un fichier texte
using Service_Thread_comptage; // pour utiliser les 2  DLLs : dixendix et vingtenvingt
using System.Threading; // pour utiliser les Threads
using System.IO; // pour écrire dans un fichier log
using System.Reflection;
using System.Resources;

namespace Service_Thread_comptage
{
    public partial class Service1 : ServiceBase
    {

       
        public Service1()
        {
            InitializeComponent();            
        }

        // Création d'une liste de Thread
        List<Thread> allThreads = new List<Thread>();

        protected override void OnStart(string[] args)
        {
            
            
            // Ecriture dans "dixendix" de la date et l'heure à laquelle
            // le 10 en 10 commence
            StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
            sw1.WriteLine("Démarrage du 10 en 10 : " + DateTime.Now.ToLongTimeString());
            sw1.Close();

            // Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
            // le 20 en 20 commence
            StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
            sw2.WriteLine("Démarrage du 20 en 20: " + DateTime.Now.ToLongTimeString());
            sw2.Close();

            
            // Pour toutes les DLLs du répertoire: ("C:\Traitement) 
            foreach (string path in Directory.GetFiles(@"C:\Traitement", "*.dll"))
            {
                Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie
                IProcess process = (IProcess)Activator.CreateInstance(asm.GetType(Path.GetFileName(path)));// Création du traitement
                
                // Création d'un thread à partir de la fonction récupérée dans l'interface
                Thread thread = new Thread(new ThreadStart(process.Start));
                // Démarrage du thread
                thread.Start();
                // On ajoute le thread qui vient d'être créé dans la liste de
                // thread créé précédemment
                allThreads.Add(thread);
               
            }           
            
        }

        protected override void OnStop()
        {
            // Ecriture dans "dixendix" de la date et l'heure à laquelle
            // le 10 en 10 s'arrête
            StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
            sw1.WriteLine("Arrêt du 10 en 10 : " + DateTime.Now.ToLongTimeString());
            sw1.Close();

            // Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
            // le 20 en 20 s'arrête
            StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
            sw2.WriteLine("Arrêtdu 20 en 20: " + DateTime.Now.ToLongTimeString());
            sw2.Close();

            // Pour chaque thread de la liste
            foreach (Thread thread in allThreads)
            {
                thread.Abort(); // On arrête le thread
            }

        }

        protected override void OnShutdown()
        {

            // Ecriture dans "dixendix" de la date et l'heure à laquelle
            // le 10 en 10 s'arrête
            StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
            sw1.WriteLine("Arrêt du système à : " + DateTime.Now.ToLongTimeString());
            sw1.Close();

            // Ecriture dans "vingtenvingt" de la date et l'heure à laquelle
            // le 20 en 20 s'arrête
            StreamWriter sw2 = new StreamWriter(@"C:/vingtenvingt.log", true);
            sw2.WriteLine("Arrêt du système à : " + DateTime.Now.ToLongTimeString());
            sw2.Close();

            // Pour chaque thread de la liste
            foreach (Thread thread in allThreads)
            {
                thread.Abort(); // On arrête le thread
            }
           
        }
    }
}



=> Code de la DLL Dixendix
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;

namespace Service_Thread_comptage // même espace de noms pour les DLLs
{
    public class Dixendix : IProcess
    {
        public static void Thread10()
        {
            int Nombre = 0; 
             
            // Tant que le thread n'est pas tué, on travaille
            while (Thread.CurrentThread.IsAlive)
            {
                // Attente de 1s
                Thread.Sleep(1000);
                Nombre = Nombre + 10;

                // Ecriture du Nombre dans le fichier "dixendix"
                StreamWriter sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine(Nombre);
                sw.Close();
            }
        }
        
        #region IProcess Membres

        public void Start()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}



=> Code de la DLL Vingtenvingt
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;

namespace Service_Thread_comptage // même espace de noms pour les DLLs
{
    public class Vingtenvingt : IProcess
    {        
        public static void Thread20()
        {
            int Nombre = 0;

            // Tant que le thread n'est pas tué, on travaille
            while (Thread.CurrentThread.IsAlive)
            {
                // Attente de 2s
                Thread.Sleep(2000);
                Nombre = Nombre + 20;

                // Ecriture du Nombre dans le fichier "dixendix"
                StreamWriter sw = new StreamWriter(@"C:/vingtenvingt.log", true);
                sw.WriteLine(Nombre);
                sw.Close();
            }
        }
                
        #region IProcess Membres

        public void Start()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}



=> Code de l'Interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

public interface IProcess
{
    void Start();

}
0
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
28 avril 2011 à 08:04
Bonjour,

Ceci est peut-être du au fait que la méthode "OnStart()" lance tous les threads puis se termine... Il faudrait peut-être que celle-ci attende la fin de traitement de tous les threads pour se terminer (à voir: Thread.Join(...)).
C'est une hypothèse que j'avance mais je n'en suis pas certains (je n'ai pas le temps de vérifier).

Si ce n'est pas ça, il va falloir t'en remettre à toi même. Je te propose alors de logguer (plein de librairies existe à ce niveau là, tu trouveras ton bonheur facilement) afin de pouvoir enquêter sur ce qui se passe (et surtout logguer en cas d'exception...). Ceci ne sera pas du travail de perdu car les logs sont très souvent une chose indispensable lors de l'implémentation d'un projet.

Une petite question que je me pose: le but d'un service Windows consiste souvent à tourner en tâche de fond et ne jamais se terminer. Donc, je te propose de revoir les fonctionnalités demandées par ton maitre de stage pour t'assurer qu'il veuille bien que le service se termine à la fin du traitement de chaque dll (et si non, adapter le code en fonction de la demande).


Sinon, je change de sujet mais je voulais te parler de ton code et surtout au niveau des codes du type:
StreamWriter sw1 = new StreamWriter(@"C:/dixendix.log", true);
sw1.WriteLine("Arrêt du 10 en 10 : " + DateTime.Now.ToLongTimeString());
sw1.Close();

Je pense que ce code est au mauvais endroit et devrait être dans la dll appropriée (pour l'exemple, dix.dll). Car, comme je te parlais plus haut, le service windows n'est pas censé connaître les dlls... et donc, ce n'est pas son boulot de faire ça.
De plus, je te conseillerai (si tu ne l'as pas déjà fait) de retirer les références du projet service windows vers les projets dlls afin d'être sûr de bien appeler les dlls par réflection.

Voila tout,

Bonne journée,

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 10:49
Bonjour Billou_13,

Tu as entièrement raison pour l'écriture de la date et l'heure dans le fichier texte, je l'ai changé. J'ai vérifié aussi que le service Windows n'était pas référencé aux dlls, et ils sont tous référencés à l'interface IProcess.

Par contre, pour le cahier des charges, mon maître de stage m'a bien demandé de créer un service Windows qui tourne en tâche de fond, qui travaille tant qu'on ne l'arrête pas, en l'occurrence il compte de 10 en 10 et de 20 en 20 toutes les secondes et l'écrit dans un fichier texte. Et c'est bien le cas de mon service qui compte de 10 en 10 ou de 20 en 20 tant que l'on lui a pas dit d'arrêter. Les dlls effectuent donc leur travail tant qu'on leur a pas dit d'arrêter (tant qu'on a pas tué le thread) :
while (Thread.CurrentThread.IsAlive)


Je ne comprends pas non plus l'idée du Thread.Join qui sert à : "bloquer le thread appelant jusqu'à l'arrêt du thread" car on veut lancer nos threads et pas les bloquer. Désolé si je comprends pas tout...

J"ai aussi fait un test de mon service Windows, en l'installant et en l’exécutant et il me mettait toujours l'erreur que j'ai écris précédemment. J'ai ensuite voulu connaître où s'arrêtait le service dans mon code, j'ai donc fais écrire dans un fichier texte "Actif(numéro)" entre chaque étape de la méthode OnStart(). Et le résultat est qu'il s'arrête à Actif3 dans mon fichier texte. Il s'arrête donc à la création du traitement et je suis incapable de dire pourquoi. J'ai des hypothèses comme :
- Peut être qu'il charge mal la librairie juste avant. Pourtant lorsque je modifie les dll je les remets bien dans "C:\Traitement"
- Peut être que la déclaration qui suit n'est pas adaptée :
IProcess process = (IProcess)Activator.CreateInstance(asm.GetType(Path.GetFileName(path)));

Mais ça reste des hypothèses...
Voici le code de la méthode OnStart() avec les "Actif(numéro)" si ça peut te donner des idées :

 protected override void OnStart(string[] args)
        {
            StreamWriter sw = new StreamWriter(@"C:/dixendix.log", true);
            sw.WriteLine("Actif1");
            sw.Close();

            // Pour toutes les DLLs du répertoire: ("C:\Traitement) 
            foreach (string path in Directory.GetFiles(@"C:\Traitement", "*.dll"))
            {
                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif2");
                sw.Close();

                Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie
                
                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif3");
                sw.Close();

                IProcess process = (IProcess)Activator.CreateInstance(asm.GetType(Path.GetFileName(path)));// Création du traitement

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif4");
                sw.Close();

                // Création d'un thread à partir de la fonction récupérée dans l'interface
                Thread thread = new Thread(new ThreadStart(process.Start));

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif5");
                sw.Close();

                // Démarrage du thread
                thread.Start();

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif6");
                sw.Close();

                // On ajoute le thread qui vient d'être créé dans la liste de thread créé
                // précédemment pour éviter d'écraser un nouveau thread lors du prochain
                // passage dans la boucle
                allThreads.Add(thread);

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif7");
                sw.Close();

            }         
        }
0
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
28 avril 2011 à 11:38
Salut,

Mon idée du Thread.Join(...) venait de l'hypothèse que le main thread (ie, celui de la méthode OnStart()) risque de se terminer et donc de faire croire que le process est terminé. C'est pour cela que j'avais suggéré que le main thread attente tous les threads qui font des traitements.
Note: Et cela n'empêchera pas les traitements de tourner qd même.
Mais mon idée est à vérifier et validée car je ne suis pas sûr que la fin de la méthode OnStart() entraine ce type d'erreur.
Enfin, c'est un test à faire de ton côté et à valider.

Sinon, vu qu'apparement ton traitement s'arrête après le log de "Actif3", je te propose de logguer aussi les exceptions en mettant tout ton code de OnStart() dans une instruction de type:
try
{
  //...
}
catch(Exception ex)
{
  //Log de l'exception
}


Car peut-être as-tu une erreur comme tu le dis sur le "Activator.CreateInstance" et dans ce cas, tu ne la vois pas et tout s'arrête.

Fais ce test et si tu as plus de détail sur l'erreur (Exception.Message, Exception.CallStack...), fais nous en part et nous pourrons mieux connaître ton problème.

Voila,

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 13:46
Re-bonjour,

J'ai donc essayer ta méthode avec toute la méthode OnStart() dans "try" et le log de l'exception dans "catch" et j'obtient la chose suivante dans mon fichier texte :
Actif1
Actif2
Actif3
System.ArgumentNullException: La valeur ne peut pas être null.
Nom du paramètre : type
   à System.Activator.CreateInstance(Type type, Boolean nonPublic)
   à System.Activator.CreateInstance(Type type)
   à Service_Thread_comptage.Service1.OnStart(String[] args) dans C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\Service_Thread_comptage\Multithread\Service1.cs:ligne 53
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 13:49
Re-bonjour,

J'ai donc essayer ta méthode avec toute la méthode OnStart() dans "try" et le log de l'exception dans "catch" et j'obtiens la chose suivante dans mon fichier texte :


Actif1
Actif2
Actif3
System.ArgumentNullException: La valeur ne peut pas être null.
Nom du paramètre : type
à System.Activator.CreateInstance(Type type, Boolean nonPublic)
à System.Activator.CreateInstance(Type type)
à Service_Thread_comptage.Service1.OnStart(String[] args) dans C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\Service_Thread_comptage\Multithread\Service1.cs:ligne 53
0
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
28 avril 2011 à 14:15
Bein voila, tu as ta réponse: le type que tu envoies est null.
Ce qui veut dire que:
Type type =  asm.GetType(Path.GetFileName(path));//est null

En analysant un peu plus:
string className = Path.GetFileName(path);// n'existe pas dans ta librairie (celle de Dix ou de Vingt)

Tout simplement parce que j'avais fait une erreur car "Path.GetFileName(...)" retourne le nom du fichier avec l'extension ...
Il te faut plutôt utiliser Path.GetFileNameWithoutExtension(...):
string className  = Path.GetFileNameWithoutExtension(path);
Type type = asm.GetType(className);//vérifie bien que la valeur de className correspond bien à une classe de ta dll


Il ne faut jamais prendre au pied de la lettre ce que je dis car je n'ai pas le temps de tester et cela peut contenir des erreurs...

De plus, au lieu de t'embêter à installer à chaque fois le service windows pour tester, pourquoi ne crées-tu pas un projet console qui permettrai de faire la même chose que dans ton OnStart() ???
Cela te permettrait de debugguer plus facilement.

Bonne après midi,

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 15:09
J'ai essayé ta méthode mais ça me remet exactement la même chose qu'auparavant. Par contre il arrive à lire le nom de la dll mais pas le nom de la classe de la dll. J'ai essayé une fois avec le nom de dll : Dixendix.dll, et une autre avec dixenx.dll et le nom qui sort de "classname" c'est le nom de la dll et non sa classe. A moins que lorsqu'on le renomme la dll, ça renomme la classe de dll. J'obtiens ça sur le fichier texte avec le code de OnStart() qui suit :

Actif1
Actif2
Actif31
Dixendix
Actif4
System.ArgumentNullException: La valeur ne peut pas être null.
Nom du paramètre : type
   à System.Activator.CreateInstance(Type type, Boolean nonPublic)
   à System.Activator.CreateInstance(Type type)
   à Service_Thread_comptage.Service1.OnStart(String[] args) dans C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\Service_Thread_comptage\Multithread\Service1.cs:ligne 70
Actif1
Actif2
Actif31
Dixenx
Actif4
System.ArgumentNullException: La valeur ne peut pas être null.
Nom du paramètre : type
   à System.Activator.CreateInstance(Type type, Boolean nonPublic)
   à System.Activator.CreateInstance(Type type)
   à Service_Thread_comptage.Service1.OnStart(String[] args) dans C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\Service_Thread_comptage\Multithread\Service1.cs:ligne 70



        protected override void OnStart(string[] args)
        {
            try
            {

            StreamWriter sw = new StreamWriter(@"C:/dixendix.log", true);
            sw.WriteLine("Actif1");
            sw.Close();

            // Pour toutes les DLLs du répertoire: ("C:\Traitement) 
            foreach (string path in Directory.GetFiles(@"C:\Traitement", "*.dll"))
            {
                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif2");
                sw.Close();

                Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif31");
                sw.Close();
                
                // On récupère le nom de la classe
                string className = Path.GetFileNameWithoutExtension(path);

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine(className);
                sw.Close();

                Type type = asm.GetType(className);

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif4");
                sw.Close();

                // Création du traitement
                IProcess process = (IProcess)Activator.CreateInstance(type);

                sw = new StreamWriter(@"C:/dixendix.log", true);
                sw.WriteLine("Actif5");
                sw.Close();
0
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
28 avril 2011 à 15:57
L'informatique, c'est pas magique :D

C'est normal car l'idée que je t'avais donné au départ et que tu as suivi implique que le nom de classe soit le même que le nom du fichier dll...

Tu as deux solutions:
1) Tu changes le nom de ta classe (ou ta dll) pour qu'elle soit identique.
2) Tu fais évoluer ton code en inspectant la dll (par reflection) afin de trouver la (ou les) classe qui implémente ton interface.

A toi de choisir...

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 16:05
La première solution était déjà faite, j'avais la classe de ma dll Dixendix.dll qui s'appelait:
public class Dixendix : IProcess


A moins que tu ais voulu dire qu'elles doivent porté un nom différent?
0
billou_13 Messages postés 860 Date d'inscription jeudi 4 mars 2004 Statut Membre Dernière intervention 19 août 2014 29
28 avril 2011 à 16:20
Bizarre !
La solution ne doit pas être loin.

Désolé, je ne vais pas pouvoir investiguer plus aujourd'hui.

Essai de passer en DEBUG avec ton visual en créant un projet console qui fait la même chose que la méthode OnStart() et inspecter chaque objet pour vérifier que tout est ok.

Courage, le bout du tunnel arrive ;p

Billou_13

--------------------------------------------------------------------
Connaître la réponse est une chose, savoir pourquoi en est une autre
---------------------
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 16:24
Ok je vais essayer ça !

Encore Merci pour ton aide !
0
sisilegeek Messages postés 11 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 avril 2011
28 avril 2011 à 17:24
J'ai crée un projet Console pour tester OnStart() comme tu m'as dit. Dans ce code de test j'écris toutes les variables dans la console pour voir ce qu'elles valent et voilà ce que j'ai quand je compile avec le code qui suit :

L'assembly ASM -> PublicKeyToken=null

Cela joue-t-il un rôle? J'ajoute aussi que l'assistant de dépannage de VS 2008 me conseille d'ajouter un "new" pour créer une instance d'objet mais où ??

=> Console :
Path : C:\Traitement\DLL DIX.dll
ASM : DLL DIX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
className : DLL DIX
type :

Exception non gérée : System.ArgumentNullException: La valeur ne peut pas être n
ull.
Nom du paramètre : type
   à System.Activator.CreateInstance(Type type, Boolean nonPublic)
   à System.Activator.CreateInstance(Type type)
   à TEST.Program.Main(String[] args) dans C:\Documents and Settings\Administrat
eur\Mes documents\Visual Studio 2008\Projects\PROJETS SERVICE\TEST\TEST\Program.
cs:ligne 45
Appuyez sur une touche pour continuer...


=> Code de OnStart()
 static void Main(string[] args)
        {

                // Création d'une liste de Thread
                List<Thread> allThreads = new List<Thread>();

                // Pour toutes les DLLs du répertoire: ("C:\Traitement) 
                foreach (string path in Directory.GetFiles(@"C:\Traitement", "*.dll"))
                {

                    Console.WriteLine("Path : "+path);

                    Assembly asm = Assembly.LoadFrom(path);// Chargement de la librairie

                    Console.WriteLine("ASM : "+asm);

                    // On récupère le nom de la classe
                    string className = Path.GetFileNameWithoutExtension(path);

                    Console.WriteLine("className : "+className);
                 
                    Type type = asm.GetType(className);

                    Console.WriteLine("type :"+type);

                    // Création du traitement
                    IProcess process = (IProcess)Activator.CreateInstance(type);

                    Console.WriteLine("Actif4");
         
                    // Création d'un thread à partir de la fonction récupérée dans l'interface
                    Thread thread = new Thread(new ThreadStart(process.Start));

        
                    // Démarrage du thread
                    thread.Start();

          
                    // On ajoute le thread qui vient d'être créé dans la liste de thread créé
                    // précédemment pour éviter d'écraser un nouveau thread lors du prochain
                    // passage dans la boucle
                    allThreads.Add(thread);

                
                }
        }
0
Rejoignez-nous