2016-12-09 3 views
2

Пока я рефакторинг некоторые старые C# код для создания документов с Office.Interop библиотекой я нашел это и из-за этого использует контекст пользовательского интерфейса, когда функция была вызваны из него блокировали егоTask.Run из UI нити бросает ошибку STA

Пример

private void btnFooClick(object sender, EventArgs e) 
{ 
     bool documentGenerated = chckBox.Checked ? updateDoc() : newDoc(); 

     if(documentGenerated){ 
     //do something 
     } 
} 

решил изменить его так, чтобы уменьшить от блокировки UI

private async void btnFooClick(object sender, EventArgs e) 
{ 
     bool documentGenerated; = chckBox.Checked ? updateDoc() : newDoc(); 

     if(chckBox.Checked) 
     { 
       documentGenerated = await Task.Run(() => updateDoc()).ConfigureAwait(false); 
     } 
     else 
     { 
       documentGenerated = await Task.Run(() => newDoc()).ConfigureAwait(false); 
     } 

     if(documentGenerated){ 
     //do something 
     } 
} 

И это было бросать такую ​​ошибку

Текущий поток должен быть установлен в режим одного потока квартиры (STA) перед тем OLE вызовы могут быть сделаны

Почему это происходит и что можно решить эту проблему?

+1

Вы делаете что-то в updateDoc(), что вы никогда не должны делать из рабочего потока. Мы не можем этого видеть. Ничего общего с интернетом Office, судя из сообщения об исключении, вы используете буфер обмена или диалог оболочки, такой как OpenFileDialog. Не делай этого. И имейте в виду, что код взаимодействия работает в потоке пользовательского интерфейса в любом случае, COM сохраняет его поточно-безопасным автоматически, поэтому вы, вероятно, не впереди. –

+0

@ HansPassant хорошо, да, видел, что 'MessageBox' вызывает не менее – DanilGholtsman

+0

@ HansPassant haha, и там тоже используется буфер обмена. Получил 3,5 года опыта разработки, понятия не имел о таких проблемах и немного испугался. – DanilGholtsman

ответ

0

Компоненты COM, доступные через Interop, требуют, чтобы вызывающий поток был потоком STA, но в вашем случае это не STA. Используя STA, к компоненту можно получить доступ через несколько потоков. Вы можете узнать больше о том, почему требуется STA в Understanding and Using COM Threading Models. Вы можете сделать способ расширения для класса Task, как предлагается в этом answer, чтобы вызвать COM-компонент через Interop с помощью задачи.

public static Task<T> StartSTATask<T>(Func<T> func) 
{ 
    var tcs = new TaskCompletionSource<T>(); 
    Thread thread = new Thread(() => 
    { 
     try 
     { 
      tcs.SetResult(func()); 
     } 
     catch (Exception e) 
     { 
      tcs.SetException(e); 
     } 
    }); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
    return tcs.Task; 
} 

Вы также можете использовать тему вместо задачи, вы должны установить ApartmentState в ГНА как thread.SetApartmentState(ApartmentState.STA)

+0

Спасибо за ответ. Кажется, это сложный процесс, но я стараюсь, спасибо за ссылки – DanilGholtsman

+1

Это так. Вы не можете просто преобразовать код из каменного века (Office interop), чтобы использовать Задачи.Он не был построен для этого, поэтому вам нужно немного больше, чтобы заставить его работать. –

+0

Кто-то голосует за ваш ответ. Кто бы вы ни были, не могли бы вы объяснить, почему и что не так, если вы читаете это? – DanilGholtsman

1

Поскольку в этом случае Task предположительно запускает новую нить, которая не является потоком STA. Ваши звонки в updateDoc и newDoc - это те, которые называют слой Interop, который не любит потоки MTA.

Вы можете реорганизовать это, чтобы использовать Thread вместо Task и установить квартиру в STA самостоятельно. Я был бы осторожен, потому что я не уверен, что Interop любит многопоточность.

+0

Спасибо за ответ. Я новичок в асинхронном и параллельном программировании (ну, когда я был студентом, сделал некоторые интегральные исполнения CUDA, но это была просто задача cs math), но, как это имеет смысл? Я имею в виду логически 'ui thread' и' interop thread' не привязаны так. – DanilGholtsman

+0

. Лист UI должен быть потоком STA, поэтому он всегда работает над этим потоком. –

 Смежные вопросы

  • Нет связанных вопросов^_^