STA, MTA et cauchemar OLE
-
21-08-2019 - |
Question
Je dois inclure une application .NET dans une autre application .NET en tant que plug-in. L'interface du plugin me oblige à hériter d'un modèle de formulaire. La forme est ensuite fixé dans un MDI lorsque le module est chargé.
Tout fonctionne à ce jour, mais chaque fois que je me inscrire à glisser-déposer des événements, réglez le mode de saisie semi-automatique pour un combobox ou à d'autres situations que je reçois l'exception suivante:
... le thread courant doit être réglé sur simple appartement de fil en mode (STA) avant que les appels OLE peuvent être faites. Assurer, garantir 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 causent ces exceptions dans les discussions STA, mais cela ne résout pas le problème non plus.
Quelqu'un at-il été dans la même situation? Est-ce que je peux faire pour résoudre le problème?
La solution 3
Mise à jour: La société a publié une nouvelle version STA. La question n'est plus pertinent.
Autres conseils
Vous pouvez essayer de reproduire nouveau thread et appeler CoInitialize avec 0 sur elle (aparment filetée) et exécutez votre application dans ce fil. Cependant, vous ne serez 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 pour vous, mais vous pouvez l'essayer.
Je me suis récemment tombé sur ce problème tout en essayant de lire les images d'une caméra Web. Ce que je fini par faire a été la création d'une méthode qui a donné naissance à un nouveau thread STA, sur lequel la méthode unique 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 unique de fil à 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();
}
}