Ouvrir une Form aussi bien à partir d'une appli Console que d'une Windows Form

Résolu
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008 - 25 juil. 2008 à 17:42
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 - 4 août 2008 à 17:32
Bonjour,
j'ai besoin de créer une classe dans une Dll qui peut ouvrir une Windows Form. Cette classe peut aussi bien être appelée d'une application en mode console que d'une Windows Form. Pour les besoins de l'exemple, nous appellerons cette classe 'CalledForm'.
Pour l'instant, voici les options autour desquelles j'ai prospecté:

1/ la Form est ouverte avec Application.Run(CalledForm):
   a. mode Console: il faut que CalledForm soit fermée pour que ce qui est envoyé à la console soit lu.
   b. mode Form: plein de problèmes, soit des exceptions, soit CalledForm s'affiche à la place de l'autre Form, etc.

2/ la Form est ouvert avec CalledForm.Show()
   a. mode Console: CalledForm s'ouvre, mais ne se dessine pas, et le curseur se met en sablier (la Form se bloque)
   b. mode Form: tout va bien. Ca semble bien la méthode idoine.

après investigation sur le net, j'ai mis en place une solution tierce, qui consiste à 'threader' l'appel à Application.Run, dont voici les bases:
public partial class CalledForm: Form  , ----
{                 , ----
        private Thread m_localThread = new Thread(Run);  , ----
        private static void Run(Object frm)  , ----
        {  , ----
            Application.EnableVisualStyles();  , ----
            Application.Run((Form)frm);  , ----
        }  , ----
        public void ThreadedShow()  , ----
        {  , ----
            if (!m_localThread.IsAlive)  , ----
                m_localThread.Start(this);  , ----
        }  , ----
 }
 
3/ dans ce cas là, si la Form est ouverte avec CalledForm.ThreadedShow()
   a. mode Console. Tout va bien. C'est clairement la méthode recommandée.
   b. mode Form: ça marche, mais ce n'est pas optimale (CalledForm est clairement plus lente) et elle n'est pas fermée quand on quitte l'appli principale.

Ma question est donc, comment puis-je, par programmation, savoir dans quel mode je suis, pour pouvoir appeler la bonne méthode (Show() ouThreadedShow()) ?

A savoir:
 j'ai essayé Application.OpenForms, qui s'avère peu fiable, on peut se trouver dans des cas ou ça renvoie 0 alors que des formes sont en construction.
 j'ai égalemet essayé GetStdHandle et GetConsoleModemais ce n'est pas plus fiable non plus.
A voir également:

33 réponses

eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
31 juil. 2008 à 17:49
Non, c'est pas ça. ça plante dans tous les cas. Ces options n'ont de sens que lorsqu'on veut récupérer/rediriger la sortie standard. Ce n'est pas ce qu'on cherche, ça peut être activé/désactivé aussi bien pour des appli CUI que GUI. Mais je vois que tu t'accroche . J'apprécie.
0
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
1 août 2008 à 09:26
tiens ça devrait être mieux
[DllImport("kernel32.dll")]
public static extern int GetConsoleWindow();

-- Pourquoi faire simple quand on peut faire compliquer --
0
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
1 août 2008 à 11:12
aussi si tu test avec une winform : console.Title


ça plante mais pas avec une appli console

-- Pourquoi faire simple quand on peut faire compliquer --
0
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
1 août 2008 à 15:23
Il faudrait que j'essaye un peu plus avant ces solutions (du moins l'avant dernière), car je les ai vues suggérées pour des questions similaires aux miennes.
Mais mon analyse est que ça donne des infos sur la console du process en cours.
Or dans mon cas de figure, quand bien même la fenêtre est appelée par une appli en mode GUI (donc c'est un Show() qui doit être utilisé), rien ne me dit qu'il n'y a pas quand même de Console d'ouverte (il suffit d'avoir fait un AllocConsole pour ça).
Donc si je m'appuie sur une info de ce genre, je lancerais un 'ThreadedShow()' ce que je veux éviter...
0

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

Posez votre question
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
1 août 2008 à 15:39
j'ai testé l'api pour voir et ça semble marcher

-- Pourquoi faire simple quand on peut faire compliquer --
0
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
1 août 2008 à 15:42
Tu aurais un bout de code pour ça?
0
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
1 août 2008 à 15:52
en fait c'est pas comliqué
[DllImport("kernel32.dll")]
public static extern int GetConsoleWindow();

ensuite si GetConsoleWindow==0 alors c'est une application windows

-- Y a autant de bugs dans un programme que de malles-façons dans une maison. Tout dépend de la taille --
0
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
1 août 2008 à 16:20
A creuser, mais il y a des cas de figures où GetConsoleWindow!=0 et c'est une appli windows quand même (cf précédement, un AllocConsole a été appellé juste avant)...
J'ai testé, c'est bien ce qui se passe. Donc l'info n'est pas 100% équivalente.
0
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
1 août 2008 à 16:28
purée...  on est pas rendu si tu te mets à faire un switch par cas existant dans le monde
si tu fais juste ce qui suit tu t'emmerderas moins :) (même si c'est un showdialog, le fait qu'il soit dans un thread à part te laisse la main pour continuer ton programme)
void A()
{
   Threading.Thread TH=new Threading.Thread(B);
   Th.Start
   /*Code de ton programme dos ou windows*/
}
void B()
{
   Threading.Thread.Sleep(1)
   System.Windows.Forms.Form F=new Form;
   F.ShowDialog();
}

-- Y a autant de bugs dans un programme que de malles-façons dans une maison. Tout dépend de la taille --
0
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
1 août 2008 à 16:53
Comprends bien que le but est de faire une Dll robuste, utilisable par tout le monde sans trop de 'Flags' obscures. Donc je me dois de penser à tous les cas de figure dans lesquels elle peut être utilisée, au minimum détecter les raisons de son malfonctionnement.
Ce que tu me proposes est équivalent à la solution ThreadedShow que je proposais dans le début de la discussion (donc tout à fait pertinente ).
Comme je m'en suis apperçu, cette solution n'est pas performante dans 90% des cas, à savoir une bonne appli GUI standard (comparée à un simple Show)
C'est bien pour ça que je pose la question, je me suis rendu compte que la réponse à mon problème était assez tordue, et que j'avais besoin de la comunautée et des experts pour aller jusqu'au bout du truc.

J'ai tj considéré que mon rôle de programmeur n'était pas de me faire chier le moins possible à programmer, mais d'utiliser toutes les ressources à ma disposition pour faciliter la vie de l'utilisateur.
Si on peut faire du code simple et élégant, tant mieux. Si on doit un peu mettre la main dans le cambouis, et bien... tant pis, on retrousse ses manches, et on y va.
Ca n'engage que moi, évidemment...
0
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
1 août 2008 à 17:08
ben tu comprendras d'ici quelques années qu'un code simple est beaucoup plus robuste qu'une usine à gaz... (à méditer longuement)

-- Y a autant de bugs dans un programme que de malles-façons dans une maison. Tout dépend de la taille --
0
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
1 août 2008 à 18:10
Ta remarque est très vraie en général, mais ça ne m'aide pas beaucoup dans le cas présent.
Bon, tâchons de simplifier le pb.

1/ La Dll est appellée à partir d'une Appli qui va executer un Application.Run à un moment où à un autre (90% des cas de figure, voire plus) => il me semble bien que la meilleure solution est un simple Show(). Me trompe-je?

2/ La Dll est appellée et sera la seule à lancer un Application.Run, (je pense que c'est préférable à ShowDialog) => ThreadedShow ou équivalent.

Y a-t-il un moyen simple pour savoir si on est dans un des deux cas?

Suis-je passé à côté de qq chose et on peut aborder le pb autrement?

Il y a évidement une solution très simple, c'est que le module appellant choisisse.
Si je post, c'est pour savoir si on peu envisager une alternative automatisable.
0
eTill Messages postés 16 Date d'inscription jeudi 11 janvier 2007 Statut Membre Dernière intervention 4 août 2008
4 août 2008 à 17:03
J'avais également posté la même question sur le forum de 'developpez.com' (Ici.).
SirJulio m'a proposé une solution qui m'a l'air tout à fait acceptable, je l'en remercie. Je vais tâcher de la résumer ici.

Une application de type Console a priori ne gère pas de boucle de message. Donc l'information Application.MessageLoop donne une info très pertinente dans 99 % des cas. Du moins au sein d'un même Thread.
J'ai fait qq tests un peu tordus, en mixant des Threads, et ça réagit bien. Pour la robustesse, il va falloir border tout ça, mais ça me semble une bonne base de départ, et ça m'évite de pousser l'utilisateur (de la Dll) à gérer le contexte d'utilisation (jusqu'à ce que je me trouve face à un cas extrêmement tarabiscoté, ceci dit...).

Sinon, il a une recommandation également à prendre en compte en ce qui concerne le mode 'threaded'. A savoir que toute la gestion de la Form devrait être 'threaded' plutôt que seulement l'affichage (instantiation et autre manipulation comprises). Ce qui rend l'implantation un peu plus complexe que ce qu'on avait envisagé.
Un certain degré de complexité visiblement difficile à ignorer.

Merci à toi eldim pour avoir suivi cette discussion et creusé comme tu l'as fait.
0
Rejoignez-nous