IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

[c#]Destructeur, problème quand je quitte de programme


Sujet :

Windows Forms

  1. #1
    Membre confirmé Avatar de skysee
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 191
    Par défaut [c#]Destructeur, problème quand je quitte de programme
    Bonjour a tous,
    comme vu dans plusieurs tut, le destructeur se déclare comme toujours :

    ~Form1
    {
    }

    Seulement quand je quitte mon programme, le destructeur n'est pas appellé...

    Je suis sous vstudio 2005 et je déclare mon destructeur juste en dessous du constructeur de ma Form.

    merci

  2. #2
    Membre expérimenté Avatar de DarkMolo
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    207
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Maroc

    Informations forums :
    Inscription : Juillet 2006
    Messages : 207
    Par défaut
    Salut,

    Selon l'MSDN:
    Le programmeur n'a aucun contrôle sur le moment où le destructeur est appelé car cela est déterminé par le garbage collector. Le garbage collector recherche les objets qui ne sont plus utilisés par l'application. S'il considère qu'un objet est candidat à la destruction, il appelle le destructeur (s'il y a lieu) et libère la mémoire utilisée pour stocker l'objet. Les destructeurs sont également appelés à la fermeture du programme.
    T'es sûr que le programme ne s'arrête pas brutalement après un bug fatal?
    Qu'est ce que tu as mit comme signal pour vérifier que ton destructeur a été (ou non) bien executé?

  3. #3
    Membre confirmé Avatar de skysee
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 191
    Par défaut
    Je lance une messagebox dans le destructeur. De toutes facon j'ai tester au debugger et le prog ne passe pas dedans.

  4. #4
    Rédacteur

    Avatar de Jérôme Lambert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2003
    Messages
    4 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 4 451
    Par défaut
    Bien que cette syntaxe soit disponible en dotnet C#... Elle est, on peut le dire, complètement inutile. Il est vrai que dotnet s'occupe de libérer automatiquement les objets qui ne sont plus utilisés... Mais celà n'arrivera que quand Dotnet en ressentira le besoin !

    Par contre, si tu veux que ta classe ait une sorte de méthode destructeur, il te faudra implémenter l'interface IDisposable et implémenter la méthode Dispose() dans laquelle tu écris ton code pour libérer les ressources.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class ClassA : IDospable
    {
      public void Dispose()
      { ... }
    }
    Et pour que la méthode Dispose soit autimatiquement appelé, tu devras faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ClassA maClass = new ClassA();
    using(maClass)
    {
       ...
    }

  5. #5
    Membre confirmé Avatar de skysee
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 191
    Par défaut
    Hé bien merci beaucoup.

    Le système est un peu mal fait ce coté la je trouve...
    enfin merci encore

  6. #6
    Rédacteur

    Avatar de Jérôme Lambert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2003
    Messages
    4 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 4 451
    Par défaut
    C'est vrai que dans le cas où on veut que le destructeur soit appelé implicitement à un moment précis, ça donne un peu plus de boulot pour y arriver... Mais les problèmes de saturation de mémoire suite à un oubli de libération de la mémoire occupée par un objet, c'est fini !

    Au final, le développeur utilisera le destructeur (avec Dispose) uniquement si il veut fermer une connexion à une bd, une ouverture de fichier, etc. Et n'aura plus à se demander: Est-ce que je libère bien la mémoire de cet objet ?!

  7. #7
    Membre Expert Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Par défaut
    Citation Envoyé par skysee
    Le système est un peu mal fait ce coté la je trouve...
    Non.
    C'est le codeur qui a du mal à se faire au codage haut-niveau

    La notion de destructeur n'a pas de sens en C#. Elle a été ajoutée pour faire plaisir aux codeurs C++, mais normallement, le gros gros avantage de C# et Java par rapport à C++, c'est qu'ils tournent sur une plateforme managée, dans une machine virtuelle, et donc la gestion de la mémoire n'est plus du ressort du développeur.

    Si tu veux gérer ta mémoire à l'octet prêt, alors il faut faire du Win32, pas du .Net

  8. #8
    Membre confirmé Avatar de skysee
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 191
    Par défaut
    Citation Envoyé par Mose
    Non.
    C'est le codeur qui a du mal à se faire au codage haut-niveau

    La notion de destructeur n'a pas de sens en C#. Elle a été ajoutée pour faire plaisir aux codeurs C++, mais normallement, le gros gros avantage de C# et Java par rapport à C++, c'est qu'ils tournent sur une plateforme managée, dans une machine virtuelle, et donc la gestion de la mémoire n'est plus du ressort du développeur.

    Si tu veux gérer ta mémoire à l'octet prêt, alors il faut faire du Win32, pas du .Net
    Tu as raison oui, mais ce qui me chifonne, c'est que je peux implémenter mon destructeur comme en c++ et que ca ne me retourne aucune erreur lors de la compilation, mais que le pointeur ne passe pas dedans quand je quitte l'application.

  9. #9
    Membre Expert Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Par défaut
    Je comprends.
    Perso, ça fait 4 an et demi que je bosse avec C#.
    J'ai découvert l'existance des destructeurs il y a 3 mois, en bossant sur la grammaire du langage. Et je m'en suis toujours pas utilisé.

    Est-ce que tu es sûr qu'il n'est pas appelé ? Si ça se trouve le débuggeur de VS.Net se ferme avant l'appel aux constructeurs. Si tu essayes de faire un log dans ton destructeur, est-ce qu'il se fait ou pas ?

    Sinon, bein franchement n'utilise pas les destructeurs. C# est pas fait pour.
    Les destruction indispensables doivent être explicites, en utilisant IDispose.
    Oui, c'est chiant, mais c'est la philosophie de la techno

  10. #10
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par Mose Voir le message
    La notion de destructeur n'a pas de sens en C#.
    En effet, d'après ce que je lis à droite et à gauche, le destructeur au sens C++ a perdu toute son utilité en C# si son appel est devenu imprévisible.

    La solution palliative étant à première vue l'interface IDisposable, using(){} et consors.

    Je ne l'ai pas vu documenté, mais après un petit test, je vois qu'il est possible de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using ( Base b = new Derived(1), b2 = new Derived(2) ) {}
    mais pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Base b = new Derived(1), b2 = new Derived(2);
    Derived d = new Derived(3);
    using ( b, b2, d ) {}
    Existe-t-il une solution à ces deux problèmes ? (objets utilisés différents ou créés plus amonts)
    La solution de faire des using imbriqués me semble très peu élégante.

    Citation Envoyé par Mose Voir le message
    Elle a été ajoutée pour faire plaisir aux codeurs C++
    A mon avis, tu t'avances un peu en disant cela
    Si c'est dit sur le ton de la plaisanterie, ok. Sinon c'est prendre un peu les codeurs C++ pour des vieux rigides! On n'apprend pas un nouveau langage sans en accepter les règles. Je ne vois pas pourquoi, en concevant C#, on se serait dit "Oh laissons le destructeur sinon y en a qui vont raler parce qu'ils ont l'habitude de l'utiliser." en sachant très bien que l'utilisation du destructeur allait devenir problématique.

    Non, à mon avis il y a une raison technique, un cas, que je ne vois pas, où le destructeur pourrait servir. Et la je fais appel à vos expériences : quelqu'un l'a-t-il déjà utilisé et pourquoi ?

    Merci

    Oui, c'est chiant
    Je ne vois pas ça comme ça. Je dirais que c'est déroutant au premier abord.

    mais c'est la philosophie de la techno
    Exactement.

    NB : désolé de déterrer les sujets

  11. #11
    Membre averti
    Inscrit en
    Août 2006
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 31
    Par défaut
    En fait, je pense que Dispose() s'applique plus aux objets que tu veux "détruire" de manière explicite (Dispose() doit généralement appeler GC.SuppressFinalize() il me semble, pour éviter le double-emploi ?).

    J'ai utilisé des fois le destructuer, notamment dans le cas de figure où tu crées un wrapper d'un objet COM (le genre de truc que si t'oublies de le libérer, ton processus reste ouvert après Application.exit()) et que tu ne veux/peux pas appeler explicitement une implémentation de IDisposable. Du genre :

    public class TotoExcel
    {
    private _ApplicationClass MonXL;

    ~TotoExcel()
    {
    if(MyXL != null) MyXL.Close();
    }
    }

  12. #12
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Je ne sais pas, en tout cas, ce n'est pas parce que tu as appellé Dispose() que le destructeur de ta classe sera appellé plus tôt, j'ai fait le test.

    Pour moi Dispose() joue le rôle du destructeur en C++, ni plus ni moins.
    Il fait le ménage, dans la classe, des objets qui nécessitent un traitement particulier, décrémente un compteur de références etc.

    La différence est qu'il est optionnel et qu'il se présente sous forme d'interface.

    Pour rappel, en C++, le destructeur ne désalloue pas la mémoire, c'est delete qui s'en occupe. Comme delete appelle, juste avant, le destructeur, alors on fait l'amalgame.

  13. #13
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Tu trouveras pas mal de doc sur le net, mais ce qu'il faut retenir, c'est que Dispose est deterministe et le finaliseur ne l'est pas : l'un est appele quand on lui demande (et uniquement a ce moment la), c'est a dire par un machin.Dispose() ou par l'utilsation d'un bloc using. L'autre est un bout de code qui se declenche quand le GC decide vraiment de supprimer de la memoire l'objet.

  14. #14
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Hey au fait :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class Form1
    {
     ...
     ~Form1()
            {
               DestructionDuForm();
            }
     
    public void DestructionDuForm()
            {
               //JAMAIS APPELLE (en tout cas, sur la form principale)
            }
    }
    Alors que
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    class Form1
    {
            public Form1()
            {
               ...
     
               interceptor = new liveInterceptor(this);
            }
     
            class liveInterceptor
            {
                Form1 form = null;
     
                public liveInterceptor(Form1 form)
                {
                    this.form = form;
                }
     
                ~liveInterceptor()
                {
                    form.DestructionDuForm();
                }
            }
     
            liveInterceptor interceptor;
     
            public void DestructionDuForm()
            {
               //TOUJOURS APPELLE
            }
    Pour x raison (raison que j'ignore), le destructeur ne semble jamais être appelé sur la form principale, mais avec la construction du "liveInterceptor" on peut s'arranger pour toujours appeler une fonction juste avant la destruction de la fenêtre. Bien sur, le "avant" est relatif car le GC s'amuse parfois à disposer les objets dans un peut n'importe quel ordre.

    Voilà, my 2 cents

  15. #15
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Ce que je retiens de ce que tu viens de dire, c'est qu'il vaut mieux s'en remettre au Dispose.

  16. #16
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Libre à chacun de voir

  17. #17
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Par défaut
    Citation Envoyé par smyley Voir le message
    Pour x raison (raison que j'ignore), le destructeur ne semble jamais être appelé sur la form principale, mais avec la construction du "liveInterceptor" on peut s'arranger pour toujours appeler une fonction juste avant la destruction de la fenêtre. Bien sur, le "avant" est relatif car le GC s'amuse parfois à disposer les objets dans un peut n'importe quel ordre.
    Salut,

    ce comportement s'explique par la facon dont .Net gere les form modless. Ces dernieres sont automatiquement disposées à leur fermeture (au contraire des forms modals qui ne le sont pas). De fait, une fois fermé, dispose etant appelé (il remonte à Component pour son implementation), Dispose(true) est appelé, ainsi que SupressFinalize(this), desinscrivant l'objet à l'appel au finalize (~[class]). Pour mette en evidence cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
                Form f = new Form1();
                f.ShowDialog();
                Thread.Sleep(2000);
                GC.Collect(0, GCCollectionMode.Forced);
                Thread.Sleep(1000);
     
    //..
     
            public Form1()
            {
                InitializeComponent();
            }
     
            ~Form1()
            {
                MessageBox.Show("Test");
            }
    Dans ce code, le destructeur sera bien appelé car Dispose n'a pas été appelé (du moins pas Dispose(void)).

    Le probleme du destructeur en .Net est double. Tout d'abord d'un point de vue des ressources acquises, vu que tu ne peux controler quand le thread du GC va passer, tu peux te retrouver avec des ressources immobilisés sur une durée indeterminée (quel que soit la longueur, c'est souvent intolerable). De deux, le fait d'implementer un destructeur sans plus de precautions, va rendre la destruction de tes objets deux fois plus couteuses pour le GC (quand un objet implemente un finalizer, la destruction effective (depuis la mise en evidence d'une reference inatteignable jusqu'à la liberation effective de la memoire) prend au moins deux cycle de GC supplementaire (avec la possibilités que ton objet se fasse promouvoir en generation superieure, ce qui allongera encore sa durée de vie)).

    En bref, pour des ressources sensibles (celles qui tiennent des handles non managés par exemple), le destructeur doit etre implementé, mais dans le cadre d'un pattern disposable "standard" (pour eviter les oublis de dispose()), mais comme tu le dis, mieux vaut compter sur le dispose que sur le finalize, dispose est explicite et determiste, le finalize ne l'est pas, et peut dans l'absolu se produire tres longtemps apres la marque du GC.

  18. #18
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Citation Envoyé par SirJulio Voir le message
    ce comportement s'explique par la facon dont .Net gere les form modless...
    Merci beaucoup pour ces infos, tu m'apprends quelque chose (faut avouer, j'étais jamais allé chercher le pourquoi non plus ).

  19. #19
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par SirJulio Voir le message
    Le probleme du destructeur en .Net est double. Tout d'abord d'un point de vue des ressources acquises, vu que tu ne peux controler quand le thread du GC va passer, tu peux te retrouver avec des ressources immobilisés sur une durée indeterminée (quel que soit la longueur, c'est souvent intolerable).
    Oui.

    Citation Envoyé par SirJulio Voir le message
    De deux, le fait d'implementer un destructeur sans plus de precautions, va rendre la destruction de tes objets deux fois plus couteuses pour le GC (quand un objet implemente un finalizer, la destruction effective (depuis la mise en evidence d'une reference inatteignable jusqu'à la liberation effective de la memoire) prend au moins deux cycle de GC supplementaire (avec la possibilités que ton objet se fasse promouvoir en generation superieure, ce qui allongera encore sa durée de vie)).
    J'ai compris l'idée sans saisir le mécanisme, si tu as des sources sous la main sur le fonctionnement détaillé du GC je veux bien. Sinon j'irai chercher un peu plus tard sur la MSDN car ça m'intéresse.

    Citation Envoyé par SirJulio Voir le message
    En bref, pour des ressources sensibles (celles qui tiennent des handles non managés par exemple), le destructeur doit etre implementé, mais dans le cadre d'un pattern disposable "standard" (pour eviter les oublis de dispose())
    C'est surtout des assert, voir un log, que je mettrais dans le destructeur, moi, si je m'apercevait que les ressources étaient encore présentes. Parce que cela veut dire que le développeur qui a utilisé la classe ne l'a pas fait correctement. Dans l'éventualité où cela se produirait chez le client, effectivement, j'appellerais aussi le Dispose(). Mais tout en sachant que cela peut-être trop tard, notre programme dépendant peut-être d'une libération des ressources dans les règles (un bon gros lecteur HD par exemple).

  20. #20
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Par défaut
    En fait pour expliquer la charge supplémentaire induite par le finalizer, c'est assez simple.

    On a d'abord le GC avec les 3 générations (0 -> 2), 0 étant la génération dans laquelle sont instanciés les objets.
    Premier scénario : prenons un objet simple sans destructeur (finalizer).
    Cet objet a été créé dans une méthode et le garbage collector détecte qu'il n'est plus accessible. Au prochain passage du GC, la mémoire sera libérée. Fin de l'histoire.

    Deuxième scénario : prenons un objet plus complexe possédant un finalizer.
    Même chose, l'objet a été créé dans une méthode et le garbage collector détecte qu'il n'est plus accessible. Sauf que là, le GC détecte une méthode de finalisation, il va donc mettre l'objet dans une autre file d'attente gérée par un thread séparé appelé en général finalizer. Ce thread s'occupe d'appeler les méthodes Finalize des objets contenus dans cette file. Le développeur n'a évidemment aucun contrôle sur le fonctionnement de ce thread et donc aucun contrôle sur le moment où va être appelé Finalize() sur ses objets. C'est le comportement non déterministe dont parlait SirJulio.
    Pendant le temps où les objets sont dans la file du finalizer, il ne peuvent plus être réclamés par le garbage collector (la mémoire n'est toujours pas liberée).
    Une fois la méthode Finalize appelée, le GC peut enfin libérer la mémoire.
    Voila pourquoi l'implémentation d'un finalizer est si pénalisante pour la gestion de la mémoire.

    Note supplémentaires potentiellement intéressantes :
    - Pourquoi l'objet ne peut pas être libéré avant que Finalize ne soit appelé ?
    Parce que la référence vers l'objet qui se trouve dans la file du finalizer ressuscite l'objet, car pour le GC, c'est une nouvelle référence qui pointe vers l'objet, il considère donc que celui-ci est encore vivant.
    Encore mieux si dans la méthode Finalize(), vous ajoutez la référence this vers une liste statique par exemple, vous allez purement et simplement ressusciter l'objet (la mémoire ne sera plus libérée après l'appel à Finalize()).

    - La syntaxe ~NomDeLaClasse() pour le destructeur est en fait transformée à la compilation en une méthode Finalize(). C'est un raccourci d'écriture en C#.

    - Si, pendant que l'objet est dans la file du finalizer, l'objet en question est promu à une génération supérieure (rappelez vous que l'objet est vivant à ce moment-là), cela retarde encore plus le moment où l'objet sera effectivement détruit.
    Besoin d'un MessageBox amélioré ? InformationBox pour .NET 1.1, 2.0, 3.0, 3.5, 4.0 sous license Apache 2.0.

    Bonnes pratiques pour les accès aux données
    Débogage efficace en .NET
    LINQ to Objects : l'envers du décor

    Mon profil LinkedIn - MCT - MCPD WinForms - MCTS Applications Distribuées - MCTS WCF - MCTS WCF 4.0 - MCTS SQL Server 2008, Database Development - Mon blog - Twitter

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 8
    Dernier message: 23/03/2006, 19h30
  2. Conserver des valeurs quand on ferme le programme
    Par Yepazix dans le forum Langage
    Réponses: 1
    Dernier message: 05/02/2006, 15h59
  3. [Debutant] Problème de fraction dans un programme
    Par SAKDOSS dans le forum Débuter
    Réponses: 4
    Dernier message: 22/10/2005, 18h38
  4. Problème installation SQL Server 2000 (programme antérieur)
    Par 404Found dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 25/04/2005, 10h24
  5. Réponses: 1
    Dernier message: 16/05/2004, 17h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo