2009-06-30 11 views
1

Ich muss eine .NET-Anwendung in eine andere .NET-Anwendung als ein Plugin einschließen. Die Plugin-Schnittstelle erfordert, dass ich von einem Template-Formular erbte. Das Formular wird dann in einem MDI angehängt, wenn das Plugin geladen wird.STA, MTA und OLE Alptraum

Alles funktioniert so weit, aber wenn ich für Drag registrieren und Ereignisse fallen, stellen Sie den Modus zur automatischen Vervollständigung für eine Combobox oder an verschiedenen anderen Situationen, die ich die folgende Ausnahme erhalten:

... den aktuellen Thread muss auf single thread apartment (STA) mode gesetzt werden, bevor OLE-Aufrufe vorgenommen werden können. Stellen Sie sicher, dass Ihre Hauptfunktion hat STAThreadAttribute auf sie markiert ...

Die Hauptanwendung ist von einem anderen Unternehmen in MTA und entwickelt laufen, so gibt es nichts, was ich dagegen tun kann.

Ich habe versucht, die Dinge zu tun, die diese Ausnahmen in STA-Threads verursachen, aber das hat das Problem auch nicht gelöst.

Hat sich jemand in der gleichen Situation befunden? Kann ich etwas tun, um das Problem zu lösen?

Antwort

0

Update: Das Unternehmen hat eine neue STA-Version veröffentlicht. Die Frage ist nicht mehr relevant.

2

Sie könnten versuchen, neue Thread zu spawnen und CoInitialize mit 0 darauf (aparment threaded) aufrufen und Ihre Anwendung in diesem Thread ausführen. Sie werden jedoch nicht die Steuerelemente direkt in diesem Thread aktualisieren, Sie sollten Control.Invoke für jede UI-Änderung verwenden.

Ich weiß nicht, ob dies sicher funktioniert, aber Sie könnten es versuchen.

+0

Vielen Dank für Ihren Vorschlag. Ich habe das versucht, aber ich habe denselben Fehler, wenn ich ein UI-Element aufruft, das von einem MTA-Thread erstellt wurde. – xsl

+1

Kann steuern, wie die Anwendung gestartet wird? Dann könnten Sie es in Container-App umbrechen. Erstellen Sie einen Thread, initialisieren Sie COM und rufen Sie dann die Main-Methode des Programms auf. Abhängig von der Anwendung kann dies funktionieren oder nicht funktionieren und das Hauptprogramm zum Absturz bringen, aber möglicherweise Ihr letzter Ausweg. (Vor dem Dekompilieren und Ändern der Hauptanwendung und das könnte illegal sein.) Sie könnten auch versuchen, das Unternehmen, das es entwickelt hat, zu kontaktieren. – devdimi

+0

Starten Sie einen neuen Thread t, verwenden Sie t.SetApartmentState (System.Threading.ApartmentState.STA), t.Start() - und nichts kann schief gehen. Es funktioniert einfach, getestet in meiner riesigen App bei der Arbeit. – Harry

1

Ich habe dieses Problem kürzlich selbst beim Versuch, Bilder von einer Web-Kamera zu lesen. Am Ende habe ich eine Methode erstellt, die einen neuen STA-Thread hervorgebracht hat, auf dem die Single-Thread-Methode ausgeführt wurde.

Das Problem

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(); 
    } 
} 

Die Lösung: Verschieben Sie den Single-Thread-Logik auf seine eigene Methode, und rufen Sie diese Methode von einem neuen STA-Thread.

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(); 
    } 
}