STA, MTA e l'incubo OLE
-
21-08-2019 - |
Domanda
Devo includere un'applicazione .NET in un'altra applicazione .NET come un plugin. L'interfaccia plug-in mi impone di ereditare da una forma di modello. Il modulo viene poi attaccato in un MDI quando il plugin è caricato.
Tutto sta funzionando finora, ma ogni volta che mi iscrivo per trascinare e rilasciare gli eventi, impostare la modalità di completamento automatico per una casella combinata o in varie altre situazioni ottengo la seguente eccezione:
... il thread corrente deve essere impostato su appartamento singolo filo modalità (STA) prima di chiamate OLE possono essere fatte. Garantire che la funzione principale ha STAThreadAttribute segnato su di esso ...
L'applicazione principale è in esecuzione in MTA e sviluppato da un'altra società, quindi non c'è nulla che io possa fare al riguardo.
Ho cercato di fare le cose che causano queste eccezioni in thread STA, ma che non ha risolto il problema.
Qualcuno è stato nella stessa situazione? C'è qualcosa che posso fare per risolvere il problema?
Soluzione 3
Update: La società ha rilasciato una nuova versione STA. La domanda non è più rilevante.
Altri suggerimenti
Si potrebbe provare a deporre le uova nuovo thread e chiamare CoInitialize con 0 su di esso (appartamento nello stesso filettato) ed eseguire l'applicazione in questo thread. Tuttavia non sarà aggiornare i controlli direttamente all'interno di questa discussione si dovrebbe usare Control.Invoke per ogni modifica dell'interfaccia utente.
Non so se questo sta andando a lavorare per certo, ma si potrebbe provare.
Recentemente ho incontrato questo problema io stesso durante il tentativo di leggere le immagini da una webcam. Quello che ho finito per fare è stato la creazione di un metodo che ha generato un nuovo thread STA, su cui è stato eseguito il metodo single-thread.
Il problema
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 soluzione:. Spostare la logica single-thread al proprio metodo e chiamare questo metodo da un nuovo 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();
}
}