STA, MTA und OLE-Alptraum
-
21-08-2019 - |
Frage
muß ich eine .NET-Anwendung in einer anderen .NET-Anwendung als Plugin enthalten. Die Plugin-Schnittstelle erfordert mich aus einer Vorlage Form zu erben. Die Form wird dann in einem MDI angebracht, wenn das Plugin geladen wird.
Alles funktioniert so weit, aber wenn ich für Drag-and-Drop registrieren Ereignisse, stellen Sie den Modus zur automatischen Vervollständigung für eine Combobox oder an verschiedenen anderen Situationen, die ich die folgende Ausnahme erhalten:
... der aktuelle Thread muss eingestellt werden einzelner Thread Apartment (STA) -Modus bevor OLE Anrufe getätigt werden. Dafür sorgen dass Ihre Hauptfunktion 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 nicht lösen.
Hat in der gleichen Situation jemand gewesen? Gibt es etwas, was ich tun kann, das Problem zu lösen?
Lösung 3
Update: Das Unternehmen hat eine neue STA-Version veröffentlicht. Die Frage ist nicht mehr relevant.
Andere Tipps
Sie könnten versuchen, neuen Thread zu erzeugen und rufen CoInitialize mit 0 drauf (aparment Gewinden) und Ihre Anwendung in diesem Thread ausgeführt. Allerdings werden Sie nicht in Kontrollen werden direkt innerhalb dieses Threads zu aktualisieren, sollten Sie Control.Invoke für jede UI Modifikation verwendet werden.
Ich weiß nicht, ob dies sicher funktionieren wird, aber man könnte es versuchen.
ich vor kurzem lief in dieses Problem selbst bei dem Versuch, Bilder von einer Web-Kamera zu lesen. Was ich am Ende dabei eine Methode wurde zu schaffen, einen neuen STA Thread erzeugt, auf das 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:. Bewegen 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();
}
}