2010-08-30 2 views
0

Je suis un débutant en C# et je veux faire ce qui suit:méthode ne fonctionne pas lorsqu'il est exécuté dans un thread, mais fonctionne autrement - C#

Thread t = new Thread(new ThreadStart(this.play)); 
t.Start(); 

Ceci est la méthode play:

private void play() 
    { 
     playSong("path\\to\\song.mp3"); 
    } 

    private static void playSong(String path) 
    { 
     mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero); 
     mciSendString("play MediaFile", null, 0, IntPtr.Zero); 
    } 

    [DllImport("winmm.dll")] 
    private static extern long mciSendString(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback); 

Quand j'exécute la méthode juste comme ceci: play();, sans utiliser le filetage, la chanson joue parfaitement, mais elle ne joue pas si j'aime bien dans le premier extrait de code.

Je suppose que cela se produit parce que j'ai besoin d'appeler la méthode mciSendString dans le thread principal. Si oui, quelqu'un me dira comment je peux faire ça? Ou dites-moi comment je peux le faire en utilisant un fil?

J'apprécie votre aide.

- Edité d'ici -

Je ne sais pas si je posterai le code, car il est un peu grande, mais je le réduire, pour montrer ce que je veux faire:

J'ai une application Windows Forms qui démarre un socket écoutant sur un port quand il commence, qui fonctionne comme un serveur. Ce serveur reçoit en tant que demandes les chemins vers les chansons qu'il va jouer. Si j'utilise la méthode play comme indiqué ci-dessous, le formulaire se bloque, mais l'application continue d'écouter mes demandes. Je comprends que je dois le faire en arrière-plan, de sorte que les contrôles de formulaire ne planteront pas, je ne sais pas la meilleure façon de le faire.

//Constructor 
    public Main() 
    { 
     InitializeComponent(); 
     play(); 
    } 

play() est quelque chose comme ceci:

private void play() 
    { 
     //Does the socket initialization 
     do 
     { 
     //... 
       while (true) 
       { 
        //Reads text from client 
        //The text contains a string, indicating the path to the song. 
        byte[] bytesFrom = new byte[10025]; 
        networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize); 
        string dataFromClient = System.Text.Encoding.Default.GetString(bytesFrom); 

        //Plays the song from the received path 
        playSong(dataFromClient); 

        //...Do other stuff 
       } 
     } while (_serverOn); 

     //Closes the socket connection 
    } 

    private static void playSong(String path) 
    { 
     mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero); 
     mciSendString("play MediaFile", null, 0, IntPtr.Zero); 
    } 
+1

Une chose à vérifier est que le fil est donné le temps de exécuter. Le thread principal doit être vivant pendant que celui-ci est en cours d'exécution. Pouvez-vous poster un exemple très simple ou le programme qui a l'erreur s'il vous plaît? –

+0

Qu'arrive-t-il à votre thread principal après le démarrage du second thread? –

+0

J'ai ajouté plus de détails à mon poste. J'espère que cela aide à résoudre mon problème. Merci! – AntonioJunior

Répondre

1

J'ai eu le même problème un certain temps ... La douleur dans le cul.

Vous effectuez des opérations croisées, ce qui n'est pas sûr. C'est la raison pour laquelle ça plante. Vous avez absolument raison de savoir où vous êtes.

Voici la documentation msdn sur cette opérations de fil http://msdn.microsoft.com/en-us/library/ms171728.aspx

Vous avez besoin d'ajouter la définition de délégué pour mciSendString => mciSendStringCallBack

delegate void mciSendStringCallBack(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);

Dans private static void regarderSong (String path) dont vous avez besoin pour vérifier si InvokeRequired, si c'est vous avez besoin d'instancier le rappel et l'invoquer.

mciSendStringCallBack method = new mciSendStringCallBack(....); this.Invoke(method , new object[] { .....});

Regardez à travers l'exemple sur le site msdn, ils font un bon travail qui démontre qu'il fonctionne.

-

Vous pouvez essayer d'utiliser travailleur de fond, il vous donne plusieurs voies filetées de faire les choses, plus facile à travailler.

+0

Merci à tous, spécialement Alex. Ce que vous avez suggéré a parfaitement résolu mon problème! – AntonioJunior

1

Je suppose que les fonctions MCI peuvent nécessiter l'exécution d'une boucle de messages. De plus, les requêtes MCI sont débloquées, ainsi votre thread va mourir une fois que vous aurez invoqué l'opération MCI. Vous devez continuer à exécuter la boucle de message sur ce thread (en utilisant Application.Run) jusqu'à la fin de MCI (vous le saurez en demandant le rappel en passant la poignée de la fenêtre). Voir l'article this qui illustre comment cela est fait. Editer: Peut-être qu'une forme cachée lancée sur un nouveau thread peut réduire le travail à faire. Mais vous devez toujours recevoir un rappel de MCI pour terminer le thread.

0

La réponse acceptée ci-dessus s'exécute toujours mciSendString sur le thread UI. Je avais besoin de le déplacer hors du thread d'interface utilisateur, car il était trop long (> 200ms pour enregistrer un fichier), alors je suis venu avec cette solution:

var t = new Thread(Dispatcher.Run); 
t.SetApartmentState(ApartmentState.STA); 
t.IsBackground = true; 
t.Start(); 
var d = Dispatcher.FromThread(t) 

d.InvokeAsync(() => mciSendString(command, null, 0, IntPtr.Zero)); 
Questions connexes