2013-04-19 2 views
6

C# 코드에서 호출 할 외부 구성 요소 (C++)가 있습니다.C# STAThread COMException

코드는이 같은 것입니다 : 그래서 문제가 처음에는 잘 작동하고 호출이다

using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace dgTEST 
{ 
    class Program 
    { 
     [STAThread] 
     static void Main(string[] args) 
     { 
      ExtComponentCaller extCompCaller = new ExtComponentCaller(); 
      result = extCompCaller.Call(input); 

      Thread t = new Thread(new ThreadStart(() => 
      { 
       try 
       { 
        result = extCompCaller.Call(input); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine(ex.ToString()); 
       } 
      })); 

      t.SetApartmentState(ApartmentState.STA); 
      t.Start(); 
      t.Join(); 
     } 
    } 
} 

라는 외부 구성 요소는, 나는 결과를 다시 얻었다.

그러나 다른 스레드에서 호출하려고하면 예외가 발생합니다. System.InvalidCastException : 'System .__ ComObject'형식의 COM 개체를 캐스팅 할 수 없습니다. STAThread 때문에이 예외가 throw 된 것이 확실합니다. Main 함수에서 [STAThread] 특성을 제거하면 정상적으로 작동 한 외부 구성 요소의 첫 번째 호출과 동일하게 발생합니다.

이 예외를 제거하기 위해 다른 스레드에서이 외부 구성 요소를 호출하려면 어떻게해야합니까?

UPDATE는 -------------

다른 미친 것은 이제 발생합니다. Visual Studio에서 F5 키를 눌러 프로그램을 시작하면 첫 번째 호출에서도 문제가 발생하지만 바이너리 .exe 파일을 직접 실행하면 다른 스레드에서 작동하지 않습니다.(). 놓고 F5와 비주얼 스튜디오에서 시작, 첫 번째 전화가 다시 작동하는 디버그에서 빌드를 전환 할 수 있습니다.

이 왜 발생합니까?

감사를 사전에 도움을!

안부, Zoli

+0

STA로 표시된 작성한 스레드에서 전체 작업 (COM 인스턴스 만들기 및 메서드 실행)을 수행하면 어떻게됩니까?이 COM 개체가 레지스트리에서 STA로 표시되고 다른 COM 아파트 (MTA에서 STA로 또는 STA에서 MTA로)에서 제대로 작동하지 않을 가능성이 있습니다 (코드화 된 방식의 버그로 인해). –

+0

동일한 예외가 있습니다 :. 하지만 Main 함수는 스레드가 생성되는 STA입니다 .STA로 설정된 스레드도 이해할 수 없으므로 –

+0

이것은 구성 요소의 버그로 인해 발생할 수 있습니다. 모든 단일 STA 스레드에서 수행됩니다 작동합니다. –

답변

2

스레딩은 결코 작은 세부 사항이 아닙니다. 코드가 명시 적으로 수행되지 않으면 99 %의 확률은 스레딩을 지원하지 않는다는 것입니다.

분명히이 구성 요소는 스레딩을 지원하지 않습니다. 다른 STA 스레드를 만드는 것은 마법의 해결책이 아니며 여전히 다른 스레드입니다. InvalidCastException은 생성하려고하는 것과 같은 작업자 스레드에서 호출을 마샬링하는 데 필요한 프록시/스텁 지원이 누락되었음을 나타냅니다. 스레드로부터 안전하지 않은 코드에 대한 스레드 안전성 호출을 수행하는 데 필요합니다. [STAThread]에 대한 계약을 위반 했음에도 불구하고 메시지 루프를 가동해야합니다. 작업자 스레드에서 스레드로부터 안전하지 않은 구성 요소로 호출하는 것을 허용하는 것은 메시지 루프입니다. Application.Run()에서 메시지 루프를 가져옵니다.

이것은 벅이 멈추는 곳입니다. thread로부터 안전한 기간은 아닙니다. 주 스레드를 수정하거나 공급 업체 또는 작성자에게 프록시/스텁을 제공하도록 요청한 경우에도 여전히 수행 한 작업을 수행하지 않았으므로 실제로 작성한 작업자 스레드에서 실행되지 않습니다. 그래서 다음과 같아야합니다 :

static void Main(string[] args) 
    { 
     Thread t = new Thread(new ThreadStart(() => 
     { 
      ExtComponentCaller extCompCaller = new ExtComponentCaller(); 
      result = extCompCaller.Call(input); 
     })); 

     t.SetApartmentState(ApartmentState.STA); 
     t.Start(); 
     t.Join(); 
    } 

다음과 같이 호출 한 동일한 스레드에 객체를 생성하므로 스레드로부터 안전합니다. 이 작업자 스레드가 메시지 루프를 보내지 않는 문제가 여전히 남아 있습니다. COM 구성 요소는이 문제에 의존하는 경향이 있습니다. 교착 상태 나 실행되지 않는 이벤트에서 문제가 발생했는지 여부를 알 수 있습니다. 테스트 프로그램에서 주 스레드에서 호출했을 때 이미 정상적으로 작동했다면 펌핑을하지 않아도됩니다.

+0

아주 좋음 설명, 도움 주셔서 감사합니다! :) 이제 테스트 프로그램에서 작동합니다. 나는 실제 환경에 놓을 것이고, 모든 것이 잘 될 것입니다. :). –