Проблемы с вызовом методов в потоке COM из потока графического интерфейса WinForms? - PullRequest
3 голосов
/ 19 февраля 2010

У меня проблемы с моим COM-компонентом, написанным на .NET, выдающим предупреждения, которые выглядят так:

Контекст 0x15eec0 отключен. нет прокси будет использоваться для обслуживания запрос на компонент COM. Это может вызвать повреждение или потерю данных. к избежать этой проблемы, пожалуйста, убедитесь, что все контексты / квартиры остаются в живых пока приложение полностью сделано с помощью RuntimeCallableWrappers которые представляют компоненты COM, которые жить внутри них.

Похоже, это вызвано тем, что мой поток GUI вызывает функции в потоке COM без необходимой синхронизации. Для справки я использую рекомендации, установленные в http://msdn.microsoft.com/en-us/library/ms229609%28VS.80%29.aspx для создания моего потока GUI в компоненте COM.

Мой код выглядит примерно так:

class COMClass {
  // this is called before SomeMethod
  public void Init() {
    ComObject comObject = new ComObject(); // this is imported from a TLB

    // I create my GUI thread and start it as in the MSDN sample
    Thread newThread = new Thread(new ThreadStart(delegate() {
      Application.Run(new GUIForm(comObject));
    }));
  }

  public void SomeMethod(){
    comObject.DoSomething();               // this is where the error occurs
  }
}

class GUIForm : Form {
  ComObject com;
  public GUIForm(ComObject com) {comObject = com;}

  public void SomeButtonHandler(object sender, EventArgs e) {
    comObject.SomeMethod();  // call on the GUI thread but the com object is bound to the COM thread...
  }
}

Существует ли установленный способ борьбы с этим? Вызовы в GUI не являются проблемой (Invoke / BeginInvoke), но вызов другого способа представляется более сложным ...

edit: Также нельзя изменять COM-объект каким-либо образом.

Ответы [ 3 ]

2 голосов
/ 19 февраля 2010

Из вашего фрагмента не очень понятно, как вызывается крайне важный метод Init () и как запускается поток. Ясно, что поток, в котором создается COM-объект, не совпадает с потоком, в котором выполняется вызов SomeMethod (). Кроме того, предполагая, что COM-сервер является многопоточным, COM должен перенаправить вызов SomeMethod () в поток, создавший объект. Тот, который называется Init (). Если этот поток больше не работает, возникает веселье.

Есть одна вопиющая проблема, вы забыли вызвать Thread.SetApartmentState ().

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

1 голос
/ 19 февраля 2010

Я обнаружил проблему, это не была операция с несколькими потоками. В моей GUIForm я создал подокно и использовал SetParent (), чтобы привязать его к окну приложения COM-сервера. Кажется, это вызвало проблемы с отключением прокси-сервера COM (хотя опытный эксперт COM мог бы объяснить мне, почему он так себя ведет).

Вместо того, чтобы привязать мой элемент управления к окну, я собираюсь полностью отключить его и просто подключить WM_WINDOWPOSCHANGING для перемещения моего элемента управления в главном окне приложения.

0 голосов
/ 19 февраля 2010

Поскольку COM-объект был создан в другом потоке, все вызовы COM-объекта должны выполняться из этого потока. После запуска потока с графическим интерфейсом вам необходимо настроить какой-либо механизм организации очередей для ожидания вызовов для выполнения методов (возможно, очереди делегатов). Ваш код GUI может поместить делегата в очередь, и он будет выполнен (в исходном потоке), когда исходный поток обрабатывает очередь. См .: http://www.yoda.arachsys.com/csharp/threads/deadlocks.shtml (пример производителя / потребителя о середине страницы).

...