Невозможно привести объект COM типа исключения

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

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 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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".

Другие вопросы по тегам