2009-06-30 14 views
1

Je dois inclure une application .NET dans une autre application .NET en tant que plugin. L'interface du plugin nécessite que je hérite d'un formulaire de modèle. Le formulaire est ensuite attaché dans un MDI lorsque le plugin est chargé.Cauchemar STA, MTA et OLE

Tout fonctionne à ce jour, mais chaque fois que j'enregistrer des événements glisser-déposer, régler le mode de saisie semi-automatique pour un combobox ou à d'autres situations que je reçois l'exception suivante:

... le fil en cours doit être défini sur en mode STA (Single Thread Apartment) avant que les appels OLE puissent être effectués. Assurez-vous que votre fonction principale a STAThreadAttribute marqué sur elle ...

La principale application est en cours d'exécution dans le MTA et développé par une autre société, donc il n'y a rien que je puisse faire à ce sujet.

J'ai essayé de faire les choses qui provoquent ces exceptions dans les threads STA, mais cela n'a pas résolu le problème non plus.

Est-ce que quelqu'un a été dans la même situation? Est-ce que je peux faire quelque chose pour résoudre le problème?

Répondre

0

Mise à jour: La société a publié une nouvelle version STA. La question n'est plus pertinente.

2

Vous pouvez essayer de générer un nouveau thread et d'appeler CoInitialize avec 0 dessus (aparment threaded) et exécuter votre application dans ce thread. Cependant, vous ne devez pas mettre à jour les contrôles directement dans ce thread, vous devez utiliser Control.Invoke pour chaque modification de l'interface utilisateur.

Je ne sais pas si cela va fonctionner, mais vous pouvez l'essayer.

+0

Nous vous remercions de votre suggestion. J'ai essayé cela mais j'ai eu la même erreur quand j'appelle un élément d'interface utilisateur qui a été créé par un thread de MTA. – xsl

+1

Peut contrôler le démarrage de l'application? Que vous pourriez envelopper dans l'application de conteneur. Créez un thread, initialisez COM et appelez la méthode Main du programme. Selon l'application, cela peut fonctionner ou ne pas fonctionner et bloquer le programme principal, mais peut être votre dernier recours. (Avant de décompiler et de modifier l'application principale et cela peut être illégal.) Vous pouvez également essayer de contacter la société qui l'a développé. – devdimi

+0

Commencez un nouveau thread t, utilisez t.SetApartmentState (System.Threading.ApartmentState.STA), t.Start() - et rien ne peut mal tourner. Cela fonctionne, testé dans mon énorme application au travail. – Harry

1

J'ai récemment rencontré ce problème moi-même en essayant de lire des images d'une caméra Web. Ce que j'ai fini par faire était de créer une méthode qui a engendré un nouveau thread STA, sur lequel la méthode single-thread a été exécuté.

Le problème

private void TimerTick(object sender, EventArgs e) 
{ 
    // pause timer 
    this.timer.Stop(); 

     try 
     { 
      // get next frame 
      UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraGetFrame, 0, 0); 

      // copy frame to clipboard 
      UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraCopy, 0, 0); 

      // notify event subscribers 
      if (this.ImageChanged != null) 
      { 
       IDataObject imageData = Clipboard.GetDataObject(); 

       Image image = (Bitmap)imageData.GetData(System.Windows.Forms.DataFormats.Bitmap); 

       this.ImageChanged(this, new WebCamEventArgs(image.GetThumbnailImage(this.width, this.height, null, System.IntPtr.Zero))); 
      } 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show("Error capturing the video\r\n\n" + ex.Message); 
      this.Stop(); 
     } 
    } 
    // restart timer 
    Application.DoEvents(); 

    if (!this.isStopped) 
    { 
     this.timer.Start(); 
    } 
} 

La solution: Déplacer la logique thread unique à sa propre méthode, et appeler cette méthode à partir d'un nouveau thread STA.

private void TimerTick(object sender, EventArgs e) 
{ 
    // pause timer 
    this.timer.Stop(); 

    // start a new thread because GetVideoCapture needs to be run in single thread mode 
    Thread newThread = new Thread(new ThreadStart(this.GetVideoCapture)); 
    newThread.SetApartmentState(ApartmentState.STA); 
    newThread.Start(); 

    // restart timer 
    Application.DoEvents(); 

    if (!this.isStopped) 
    { 
     this.timer.Start(); 
    } 
} 

/// <summary> 
/// Captures the next frame from the video feed. 
/// This method needs to be run in single thread mode, because the use of the Clipboard (OLE) requires the STAThread attribute. 
/// </summary> 
private void GetVideoCapture() 
{ 
    try 
    { 
     // get next frame 
     UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraGetFrame, 0, 0); 

     // copy frame to clipboard 
     UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraCopy, 0, 0); 

     // notify subscribers 
     if (this.ImageChanged!= null) 
     { 
      IDataObject imageData = Clipboard.GetDataObject(); 

      Image image = (Bitmap)imageData.GetData(System.Windows.Forms.DataFormats.Bitmap); 

      // raise the event 
      this.ImageChanged(this, new WebCamEventArgs(image.GetThumbnailImage(this.width, this.height, null, System.IntPtr.Zero))); 
     } 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show("Error capturing video.\r\n\n" + ex.Message); 
     this.Stop(); 
    } 
}