Невозможно привести объект COM типа исключения - PullRequest
20 голосов
/ 05 августа 2009

У меня есть следующий код:

public void Test(IMyInterface iInterface)
{
  iInterface.CallMethod ( );
}

Который работает нормально. Тем не менее, если я изменю код на многопоточность:

private IMyInterface myInterface;
public void Test(IMyInterface iInterface)
{
  myInterface = iInterface;
  new Thread ( new ThreadStart ( CallInterfaceMethod) ).Start ( );
}

public void CallInterfaceMethod ( )
{
  myInterface.CallMethod ( )
}

Когда я использую поток, я получаю исключение:

Невозможно привести COM-объект типа 'System .__ ComObject' к типу интерфейса 'IMyInterface'. Эта операция завершилась неудачно, потому что QueryInterface вызов COM-компонента для интерфейса с IID '{GUID}' не выполнен из-за следующей ошибки: такой интерфейс не поддерживается

Но интерфейс должен поддерживаться просто отлично? У кого-нибудь есть мысли о том, что здесь происходит?

Ответы [ 4 ]

21 голосов
/ 11 августа 2009

Это неприятное, неприятное исключение возникает из-за концепции, известной как COM-маршаллинг. Суть проблемы заключается в том, что для использования COM-объектов из любого потока поток должен иметь доступ к информации о типе, которая описывает COM-объект.

В описанном сценарии причина его сбоя во втором потоке заключается в том, что во втором потоке нет информации о типе интерфейса.

Вы можете попробовать добавить следующее в ваш код:

[ComImport]
[Guid("23EB4AF8-BE9C-4b49-B3A4-24F4FF657B27")]
public interface IMyInterface
{
    void CallMethod();
}

По сути, приведенное выше объявление указывает загрузчику COM .NET Framework загружать информацию о типах с использованием традиционных методов из реестра, находить связанную библиотеку типов и переходить оттуда.

Вы также должны ограничить создание COM-объекта одним потоком (чтобы предотвратить сортировку потоков), чтобы помочь решить эту проблему.

Подводя итог, эта ошибка вращается вокруг информации о типе и сортировке потока. Убедитесь, что каждый поток, который хочет получить доступ к COM-объекту, имеет соответствующую информацию, чтобы демонтировать объект из исходного потока.

PS: эта проблема решается в .NET 4.0 с помощью метода, называемого «эквивалентность типов»

4 голосов
/ 25 июня 2013

Я получил совет, и он мне помог!

Найдите в главном потоке (Program.cs) строку [STAThread] и измените ее на [MTAThread].

0 голосов
/ 13 мая 2017

Я разрабатывал приложение на C #, которое использует 7-zip через COM-интерфейсы. Я столкнулся с этой забавной вещью, когда мне удалось извлечь архивы из рабочего потока в одном экземпляре, но не в другом, получив то же исключение.

Я обнаружил, что до тех пор, пока вы инициализируете нарушающий COM-объект в потоке, в котором он используется, исключение не выдается. Моим решением было избавиться от объектов, использующих COM-интерфейсы, и повторно инициализировать их при передаче их между потоками.

0 голосов
/ 05 августа 2009

Ну, во-первых, вы делаете перекрестный вызов объекта, не блокируя его, это автоматически вызовет некоторые проблемы. Ваш код должен выглядеть примерно так:

private IMyInterface myInterface;
private static readonly object _myObjectLock = new object();

public void Test(IMyInterface iInterface)
{
     myInterface = iInterface;
     new Thread ( new ThreadStart ( CallInterfaceMethod) ).Start ( );
}

public void CallInterfaceMethod ( )
{
     lock(_myObjectLock)
     {
        myInterface.CallMethod ( );
     }
}

Из того, что я понимаю, ошибка, которую вы перечислили, может иногда происходить, когда к ресурсу невозможно получить доступ, что, скорее всего, при такой многопоточной операции могло бы произойти. Не цитируйте меня, хотя, я не эксперт COM.

По правде говоря, я не думаю, что подхожу к такому способу вызова этого метода, слишком много рисков при этом. Рассматривали ли вы использование ParameterizedThreadStart и передачу объекта таким образом? Вам все еще нужно было бы безопасно заблокировать ваши объекты для операций с несколькими потоками, но это было бы безопаснее.

Кроме того, убедитесь, что ваш класс "myInterface" все еще может вызывать метод "CallMethod ()". Интерфейсы не имеют реализации, вы можете столкнуться с проблемами при установке «myInterface = iInterface».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...