2009-10-06 2 views
3

저는 VStudio, Google 및 다양한 도구와 웹 사이트와 하루 종일 대결하여 해결책을 찾지 못했습니다!Absolute COM Confusion - C# interop at early-binding

나는 두 개의 COM 인터페이스 (순수 COM, 아니 ATL)이 : 해당 구현 내가 C#을에서하지만에 regsvr32로 COM 서버를 등록하지 않고 그들을 사용할

IMyClassFactory와 IMyClass를. CoRegisterClassObject를 사용하여 클래스 팩토리를 노출하고 관리되지 않는 코드에서 CoCreateInstance를 사용하여 IMyClass의 객체를 성공적으로 만들 수 있습니다.

그래서는 C#의 상호 운용성은 ...

나는 tlbimp myComServer.tlb와 .NET 래퍼를 만들고 내 C# 클라이언트에 대한 참조로로드. 내가 IMyClass의 인스턴스를 만들려고 할 때 다음

, 내가 얻을 다음 QueryInterface를 내가 E_NOINTERFACE를 반환하는 유일한 경우에

An unhandled exception of type 'System.InvalidCastException' occurred in COMTestClient.exe 

Additional information: Unable to cast COM object of type 'MyComServerLib.MyClass' to interface type 'MyComServerLib.IMyClass'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{9F8CBFDC-8117-4B9F-9BDC-12D2E6A92A06}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)). 

이제, 내가 추가 한 흔적이 중 어떤 요청하면된다 정렬 화 관련 인터페이스 또는 IManagedObject 용

어떻게 수정합니까 ??

편집 : 내 IDL 파일 : 당신은 당신의 인터페이스 즉, .idl 파일에 같은 "로컬"하지를 표시하여가에서 끝나도록 (정렬 화 할 수 있도록하거나 필요

import "unknwn.idl"; 

[ 
    object, 
    uuid(...), 
    nonextensible, 
    pointer_default(unique) 
] 
interface IMyClass : IUnknown 
{ 
    HRESULT(SetFirstNumber)(long nX1); 

    HRESULT(SetSecondNumber)(long nX2); 

    HRESULT(DoTheAddition)([out,retval] long *pBuffer); 
}; 

[ 
    uuid(...) 
] 
library MyLib 
{ 
    importlib("stdole2.tlb"); 

    [ 
     uuid(...) 
    ] 
    coclass IMyClassImpl 
    { 
     [default] interface IMyClass; 
    }; 
} 

답변

4

타입 라이브러리, 프록시/스텁에서), 또는 그렇게한다면 자유 스레드 마샬 러를 집계하십시오.

#define DECLARE_FTM() \ 
protected: CComPtr<IUnknown> _m_Marshal; \ 
DECLARE_GET_CONTROLLING_UNKNOWN() \ 
public: HRESULT FinalConstruct() \ 
{ return CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&_m_Marshal); } 

#define COM_INTERFACE_ENTRY_FTM() COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal,_m_Marshal.p) 

그런 다음, COM 맵 :

는 FTM을 집계하기 위해,이 같은 짓 난 당신이 ATL 등을 사용하지 않는 점에 유의

BEGIN_COM_MAP(Blah) 
    COM_INTERFACE_ENTRY(IBlah) 
    COM_INTERFACE_ENTRY_FTM() 
END_COM_MAP() 
DECLARE_FTM() 

을 - 당신은 IMarshal이 쿼리 될 때 QueryInterface 구현에서 FTM 포인터를 반환하도록이 값을 수정해야합니다.

FTM을 집계하는 것은 실제로 가볍게 수행 할 수있는 것이 아니며, 항상 유효하지 않은 여러 가지 안전하지 않은 가정을 만듭니다. 예를 들어, 클래스는 스스로 자유 스레드가 아닌 인터페이스를 사용할 수 없습니다.

다른 대안은 기본적으로 @ [Franci Penov]가 말했듯이, 인터페이스를 정렬 할 수 있어야합니다. 내가 이해하는 방식으로, 형식 라이브러리의 모든 인터페이스를 마샬링 할 수있는 표준 marshaller가 있습니다. (즉, midl 컴파일러가 자동 또는 다소 자동으로 수행합니다.) 프록시/스텁 DLL을 만들거나 코드를 병합 할 수 있습니다. 프록시/자신의 dll에 스텁)에 대한 마샬링 할 수 있습니다.

이 기사 here describes the process of building and registering the proxy/stub에 대해 자세히 설명합니다.

+0

두 가지 방법 중 하나를 수행하는 방법에 대한 정보를 추가 할 수 있습니까? 내 원래 게시물을 내 IDL 파일로 편집합니다. 감사합니다 – georgiosd

+0

좀 더 자세한 내용을 추가했습니다 –

+0

COM 개체의 참조 계산 구현도 연동 작업을 사용하여 스레드로부터 안전해야합니까? CLR이 COM 스레드를 프리 스레드로 처리하면 Finalizer 스레드에서 COM 개체를 Release로 호출합니다. –

1
  1. 인터페이스를 라이브러리 섹션으로 이동하십시오. 이것은 타입 라이브러리에서 그 정의를 얻을 것이다.
  2. 인터페이스를 oleautomation으로 표시하십시오.이것은 midl 컴파일러에 의해 생성 된 프록시/스텁과는 대조적으로 표준 마샬 러와 typelib 정보를 사용하여 마샬링 될 수있는 인터페이스로 표시합니다. (참고 : oleautomation은 오래된 OLE 세상에서 왔지만 IDispatch에서 파생하려면 인터페이스가 필요하지 않습니다.)
관련 문제