Application STAThread qui s'execute en MTAThread

cs_McJules Messages postés 5 Date d'inscription samedi 21 novembre 2009 Statut Membre Dernière intervention 25 juillet 2011 - 21 juil. 2011 à 14:14
cs_McJules Messages postés 5 Date d'inscription samedi 21 novembre 2009 Statut Membre Dernière intervention 25 juillet 2011 - 25 juil. 2011 à 10:11
Messieurs dames bonjour,

Une petite mise en situation:
J'essai de développer une appli incluant plusieurs dll, contenant entre autre forms et usercontrols, que j'utilise/insère dans l'application au besoin.
J'avais jusqu'à il y a peu quelque chose qui tournait plutôt pas mal, mais maintenant, une exception ThreadStateException est levée lorsque j'essai de fair appel à un FileBrowserDialog appartenant à une form d'une des dll...

Message de l'erreur:
[i]
"Le thread actuel doit être en mode STA (Single Thread Apartment) avant que des appels OLE puissent être effectués. Assurez-vous que votre fonction Main est marquée comme STAThreadAttribute. Cette exception n'est déclenchée que si un débogueur est attaché au processus."
/i

Je suis dans l'impasse, car mes Main sont bien déclarés STAThread.
Pour verrifier, j'ai inseré la ligne suivante avant la première ligne de code de mon Main:
        Debug.Print("CurrentThread.GetApartmentState: {0}", Threading.Thread.CurrentThread.GetApartmentState.ToString)

ce qui me retourne inlassablement MTA.
Essayer de passer le thread en STA (Threading.Thread.CurrentThread.SetApartmentState(Threading.ApartmentState.STA)) me lève l'exception suivante: Impossible de définir l'état de cloisonnement COM spécifié.

Je viens de passer un certain temps à chercher trace d'une solution au problème sur le net, ce qui m'a offert beaucoup de lecture sur les threads, COM et multiples autres sujets, mais jusque là, rien n'a fonctionné, bien que j'eu trouvé traces de problèmes similaires.

Toutefois, une chose fonctionne, créer un nouveau thread en STA qui executerais le code de la fonction appelant mon FileBrowserDialog.
J'aimerais autant éviter cette solution pour diverse raisons, mais surtout, j'aimerais comprendre le problème STA / MTA qui m'a déjà couté plusieurs poignées de tignasse


Merci d'avance

(PS: difficil de trouver la bonne cathéorie pour ce sujet, je le poste ici en espérant ne pas être trop à côté de la plaque)

3 réponses

cs_McJules Messages postés 5 Date d'inscription samedi 21 novembre 2009 Statut Membre Dernière intervention 25 juillet 2011
21 juil. 2011 à 14:46
Petite précision, l'appli est codée en vb.net sous vb2008 express
0
Utilisateur anonyme
22 juil. 2011 à 20:50
Bonsoir,

Pour te répondre, il faudrait qu'on ait un peu de matière.
- Le code qui montre comment tu lance ton thread.
- L'entête de ta fonction Main()
- Le type des objets COM utilisés.

Bonne soirée.
0
cs_McJules Messages postés 5 Date d'inscription samedi 21 novembre 2009 Statut Membre Dernière intervention 25 juillet 2011
25 juil. 2011 à 10:11
Pour ce qui est du Main de l'executable:


<STAThread()> Public Shared Sub Main()
        Debug.Print("CurrentThread.Name: {0}    CurrentThread.GetApartmentState: {1}", Threading.Thread.CurrentThread.Name, Threading.Thread.CurrentThread.GetApartmentState.ToString)
    
        Me._configuration = New Configuration

        ' On charge les plugins principaux dans l'application
        Dim dirs() As String = Directory.GetFiles(Application.StartupPath, "*SysBody.dll")
        If UBound(dirs) >= 0 Then
            For i As Integer = 0 To UBound(dirs)
                Dim asmbly As Assembly = Assembly.LoadFrom(dirs(i))
                Dim ty As Type = asmbly.GetType(asmbly.GetName.Name + ".CBody")
                Dim BImplement As Boolean = GetType(IBody).IsAssignableFrom(ty)
                If BImplement Then
                    Dim body As IBody = CType(Activator.CreateInstance(ty), IBody)
                    If Me._bodies Is Nothing Then Me._bodies = New Collection
                    Me._bodies.Add(body)
                    ChargerPlugin(body)
                End If
            Next i
        End If
        Threading.Thread.CurrentThread.Name = "ThreadFrmMain"

End Sub



La fonction ChargerPlugin récupère des composants depuis ma dll et les ajoute à la From principale. J'ajoute entre autre une ToolStrip avec un bouton Ouvrir qui crée une boite de dialogue. C'est cette boite de dialogue (originalement nommée "Ouvrir.vb") qui contient le bouton ou l'erreur survient:


 Private Sub Btn_browse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn_browse.Click

        Debug.Print("CurrentThread.Name: {0}    CurrentThread.GetApartmentState: {1}", Threading.Thread.CurrentThread.Name, Threading.Thread.CurrentThread.GetApartmentState.ToString)

        If OpenFile.ShowDialog = Windows.Forms.DialogResult.OK Then    ' Et là, c'est le drame !!
        '
        ' Le code qui suit mets à jour des composants de la form,
        ' pas de souci à ce niveau là.
        '
    End Sub



Les Debug.Print me donnent la Thread en MTA.

A ce moment là, l'application était une application console.
Depuis, je l'ai repassé en Application Windows Form, passé le main en constructeur public, et créé un thread STA pour lancer la boite de dialogue qui me posait problème.
De la sorte, ça tourne, donc j'ai fait comme ça en attendant pour pouvoir continuer à bosser, mais je voudrais quand même bien comprendre.
Je vais utiliser un certain nombre d'autres dll, et encore plus de composants définis dans ces dernières. J'imagine que je vais retomber sur le problème à un moment ou un autre.

Sinon, j'en profite pour glisser une autre question un peu liée:
Ayant enlevé la fonction Main au profit d'un constructeur, l'attribut <STAThread()> ne peut plus être utilisé, et le même problème se pose lorsque j'atteins le code de mon bouton browse. OK, mais comment je pourrais alors définir le thread apartment dans cette situation ?
0
Rejoignez-nous