STA, MTA и СТАРЫЙ кошмар
-
21-08-2019 - |
Вопрос
Я должен включить .NET-приложение в другое .NET-приложение в качестве плагина.Интерфейс плагина требует, чтобы я наследовал форму шаблона.Затем форма прикрепляется в MDI при загрузке плагина.
Пока все работает, но всякий раз, когда я регистрируюсь для событий перетаскивания, устанавливаю режим автозаполнения для списка со списком или в различных других ситуациях, я получаю следующее исключение:
... текущий поток должен быть настроен на режим однопоточного управления (STA) прежде чем можно будет выполнять OLE-вызовы.Убедитесь, что в вашей основной функции отмечен атрибут STAThreadAttribute...
Основное приложение запущено в MTA и разработано другой компанией, так что я ничего не могу с этим поделать.
Я попытался сделать то, что вызывает эти исключения в потоках STA, но это также не решило проблему.
Кто-нибудь был в такой же ситуации?Могу ли я что-нибудь сделать, чтобы решить эту проблему?
Решение 3
Обновить:Компания выпустила новую версию STA.Этот вопрос больше не актуален.
Другие советы
Вы могли бы попытаться создать новый поток и вызвать CoInitialize с 0 в нем (aparment threaded) и запустить ваше приложение в этом потоке.Однако вы не сможете обновлять элементы управления непосредственно в этом потоке, вам следует использовать Control.Вызывайте для каждого изменения пользовательского интерфейса.
Я не знаю, сработает ли это наверняка, но вы могли бы попробовать.
Недавно я сам столкнулся с этой проблемой, пытаясь прочитать изображения с веб-камеры.В итоге я создал метод, который породил новый поток STA, в котором был запущен однопоточный метод.
В чем проблема
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();
}
}
Решение:Переместите однопоточную логику в ее собственный метод и вызовите этот метод из нового потока 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();
}
}