2013-03-18 7 views
1

.NET의 열거 형은 AutoDispatch 값이고 AutoDual 값이지만 AutoUnknown 값은 없습니다. 왜 그렇게하지 않았고 누구나 이미 자동화 된 방법으로이를 완성 했으므로 바퀴를 다시 만들 필요가 없습니다. 여기에 좀 더 배경에 대한System.Runtime.InteropServices.ClassInterfaceType 열거 형에 AutoUnknown 값이없는 이유는 무엇입니까?

현재 열거에 세 개의 값이며, 그들이 무엇 :

  • ClassInterfaceType.None

    당신을위한 클래스 인터페이스를 만들지 않습니다. 이것은 Microsoft의 권장 값입니다. 클래스 인터페이스가 없으므로 의도하는 멤버와 함께 자신 만의 인터페이스를 만들어 클래스에 구현해야합니다. 그런 다음 인터페이스에 System.Runtime.InteropServices.ClassInterfaceAttribute 속성을 사용하여 인터페이스에 인터페이스 (런타임에 바인딩 된 클라이언트 지원), 알 수없는 인터페이스 (초기 바인딩 클라이언트 지원) 또는 이중 (초기 및 후기 바인딩 클라이언트 모두 지원)로 만들 수 있습니다.
  • ClassInterfaceType.AutoDispatch은 명시 적 구성원이없는 IDispatch에서 파생 된 클래스 인터페이스를 만듭니다. 명시 적 구성원이 없기 때문에 후기 바인딩 호출자 만 지원할 수 있습니다.
  • ClassInterfaceType.AutoDualIDispatch에서 파생 된 클래스 인터페이스를 만들고 에 해당 클래스의 public 비 정적 멤버 및 모든 구현 된 인터페이스의 명시적인 멤버를 명시합니다. Microsoft는 클래스의 멤버 중 하나라도 변경되면 클래스 인터페이스도 변경된다는 사실로 인해 "버전 제한으로 인해"이 값을 사용하지 않을 것을 강력하게 권장합니다. (재 바인드를하지 않는 클래스 후 발신자가 잘못된 메서드를 호출하거나 잘못된 매개 변수를 전달 끝낼 수 있었다 변경되었습니다 그래서.) 그래서

ClassInterfaceType.AutoUnknown라는 값이없는 이유입니다 궁금하네요 무엇 이 클래스는 명시 적으로 클래스의 멤버를 선언하는 IUnknown에서 파생 된 클래스 인터페이스를 만듭니다 (기본 클래스 또는 구현하는 다른 인터페이스는 제외).

기본 클래스의 모든 멤버와 모든 구현 된 인터페이스를 노출하는 대신 클래스의 직접 멤버 만 노출한다는 점을 제외하고는 AutoDual과 비슷한 ClassInterfaceType.AutoDualDirect과 같을 것으로 예상됩니다. 다른 COM 인터페이스를 통해 다른 멤버를 검색 할 수 있기 때문입니다.

여기에 무슨 이야기가 있습니다. 무엇이 빠졌습니까? 마이크로 소프트가 "버전 관리 문제"때문에 AutoDual을 사용하지 말 것을 권장하며, 이러한 우려는 AutoUnknown에도 어느 정도 적용될 것이라고 말했습니다. 하지만 그 권고에도 불구하고 그들은 여전히 ​​ AutoDual 있습니다. 왜 그들은 또한 AutoUnknown을 가지고 있지 않을까요?

"버전 관리 문제"에 대한 단어 : 이러한 우려의 가장 위험한 측면은 늦게 바인딩 된 발신자에만 적용됩니다. AutoUnknown은 IDispatch- 유도 된 인터페이스가 아닌 IUnknown- 유도 된 인터페이스를 생성하므로 사전 바인딩 된 클라이언트가 가질 수있는 버전 문제에 신경을 써야합니다. 그리고 자동 생성 클래스 인터페이스의 IID는 클래스의 public 비 정적 멤버가 변경 될 때마다 변경되므로 초기 바인딩 클라이언트는 기존 멤버에 "불량 호출"을 할 수 없으며 단순히 QueryInterface에 실패합니다 () 클래스 인터페이스. 여전히 실패이지만, 관리할만한 것이지 충돌이나 다른 것이 아닙니다. 이것은 인터페이스를 변경하지 못하게하는 COM 규칙을 깨지 않습니다. 변화하지 않고 새로운 인터페이스 (새로운 IID)가되었습니다. 실제로 AutoDual 메커니즘의 절반 인 (파생 된 멤버를 뺀) IUnknown과 실질적으로 다르지 않습니다.실제로, 보다 적습니다. AutoDual에는 모든 지연된 문제점이 있기 때문에 AutoDual보다 "버전 문제"가 있습니다.

다시 질문 드리겠습니다 : AutoUnknown이없는 경우 왜 AutoDual이 존재합니까?

using System.Runtime.InteropServices; 

[ComVisible(true)] 
[ClassInterface(ClassInterfaceType.AutoDual)] 
public class F 
{ 
    public int foo() 
    { 
     return 5; 
    } 
} 

다음 IDL 생성 :

고려, 다음 C# 코드 몇 가지 실제 예제를 부여하려면

[ 
    uuid(1F3A7DE1-99A1-37D4-943E-1BF5CFDF7DFA), 
    version(1.0), 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "F") 
] 
coclass F { 
    [default] interface _F; 
    interface _Object; 
}; 

[ 
    odl, 
    uuid(3D0A1144-1C0B-3877-BE45-AD8318898790), 
    hidden, 
    dual, 
    nonextensible, 
    oleautomation, 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "F")  

] 
interface _F : IDispatch { 
    [id(00000000), propget, 
     custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)] 
    HRESULT ToString([out, retval] BSTR* pRetVal); 
    [id(0x60020001)] 
    HRESULT Equals(
        [in] VARIANT obj, 
        [out, retval] VARIANT_BOOL* pRetVal); 
    [id(0x60020002)] 
    HRESULT GetHashCode([out, retval] long* pRetVal); 
    [id(0x60020003)] 
    HRESULT GetType([out, retval] _Type** pRetVal); 
    [id(0x60020004)] 
    HRESULT foo([out, retval] long* pRetVal); 
}; 

괜찮습니다,하지만 난 AutoUnknown가 유용하게이 IDL을 대신 생성하는 것을 제안 할 것 :

[ 
    uuid(1F3A7DE1-99A1-37D4-943E-1BF5CFDF7DFA), 
    version(1.0), 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "F") 
] 
coclass F { 
    [default] interface _F; 
    interface _Object; 
}; 

[ 
    odl, 
    uuid(BC84F393-DACC-353F-8DBE-F27CB2FB4757), 
    version(1.0), 
    oleautomation, 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "_F")  

] 
interface _F : IUnknown { 
    HRESULT _stdcall foo([out, retval] long* pRetVal); 
}; 

자동으로 수행 할 방법이 없다면 n 오, 내가 그것을 할 리플렉션을 사용하는 무언가를 쓰게 될 것이므로, 나는 또한 사물의 그 측면에 대한 어떤 권고도 감사 할 것입니다. 예를 들어, 메소드에서 확인해야하는 속성이 있습니까? 매개 변수에? 나는 그것을 어떻게하는지 알기 위해 System.Runtime.InteropServices.TypeLibConverter의 IL을 파 냈다. 그러나 불행히도 모든 좋은 것들은 내가 얻을 수없는 개인 internalcall nConvertAssemblyToTypeLib() 함수에있다.

감사합니다.

+1

[ClassInterfaceType]의 의미부터 시작하여 COM의 작동 방식을 근본적으로 오해 할 수 있습니다. 그것을 설명하면 책이 필요하며, 많은 책들이 있습니다. –

+0

저는 COM이 어떻게 작동하는지 아주 잘 압니다. 물론 더 많은 것을 배우기 위해서, 많은 책들이 있다는 관찰에 감사드립니다. 어쨌든, 내 질문을 되풀이하다 : 나는 클래스의 공개 비 정적 멤버를 기반으로'IUnknown' 파생 인터페이스를 전적으로 필요로 할 것이므로 커뮤니티에서 자동 생성을위한 아이디어를 얻고 각각의 변화가 일어날 때마다 그것들을 써야합니다. 인터페이스를 직접 작성하지 않고 후기 바인딩 클라이언트를 허용하지 않는 대체 방법을 포함하여 모든 건설적인 아이디어에 대해 개방적입니다. 고맙습니다. – bob

+0

"필자는'AutoDual'이 제공하는 것과 정확히 똑같은 클래스의 public non-static 멤버를 기반으로하는'IUnknown' 파생 인터페이스를 필요로 할 것입니다. –

답변

0

진짜 질문은 무엇을 달성하려고합니까?

ClassInterface docs : "인터페이스가 생성되는 경우 COM에 노출되는 클래스에 대해 생성 될 클래스 인터페이스의 유형을 나타냅니다."

뒤에 오는 아이디어 ClassInterface은 COM 클라이언트에 클래스의 프로그래밍 방식 인터페이스를 제공하는 것입니다. 이것이 기본 클래스 메서드를 포함한 전체 인터페이스를 보는 이유입니다. 목표는 클래스 기능의 하위 집합에 대한보기를 제공하지 않는 것입니다. 그것은 직접에 따라대로

가 런타임에 바인딩 기능 (예 : IDispatch)없이 클래스 인터페이스를 제공하기 위해 (그리고 ClassInterfaceType.None) 즉 인터페이스가 무엇인지 정말하지 말아야 할 것이있다 (그리고 ClassInterface 운이 좋게 그것을 사용하지 않음) 귀하의 클래스의 레이아웃이 제대로 작동합니다. 즉, 클래스도 기본 클래스도 변경되지 않아야합니다. 이것이 COM의 전체 철학에 반하는 사실 외에도 일반적으로 나쁜 생각이 들지 않는 이유는 무엇인지 보장하기 어렵고 왜 그렇게 나쁜지입니다. 조기에 바인딩 된 클라이언트는 인터페이스의 vtable 레이아웃과 밀접하게 결합됩니다. 레이아웃을 변경할 때마다 인터페이스가 손상됩니다. 후기 바인딩 된 클라이언트는 메서드가 이름으로 확인되고 누락 된 메서드를 제대로 처리 할 수 ​​있으므로이 문제가 발생하지 않습니다.

AutoDual을 사용하면 실제로 필요한 경우 메소드에 대한 초기 액세스를 제공하므로 사용자가 휠을 재발견하려는 이유가 표시되지 않습니다.

+0

늦은 바운드 클라이언트가 버전 비 호환성 (예 : 충돌로 이어지는 이진 불일치)의 심각한 위험에 노출되기 때문에 조기 바운드 클라이언트 만 지원하기를 원합니다. 초기 클라이언트는 필요한 인터페이스를 얻기 위해 QueryInterface()를 사용해야합니다. IID가 변경되면 (인터페이스가 변경 되었기 때문에) 정상적으로 처리 할 수있는 E_NOINTERFACE를 얻을 수 있습니다. 인터페이스가 변경 될 때 IID가 변경되는 한 후기 바인딩 기능이없는 클래스 인터페이스는 제공되어서는 안됩니다. – bob

+0

당신은 그것을 거꾸로 가지고 있습니다. 초기 바인딩 된 클라이언트는 런타임에 바인딩되지 않는 vtable 레이아웃과 결합되어 이진 불일치를 겪습니다. 불일치가 발생하면'DISP_E_MEMBERNOTFOUND' (또는'DISP_E_BADPARAMCOUNT' /'DISP_E_BADVARTYPE') 만 반환합니다. 그러나'AutoDual'은 초기에 바인딩 된 클라이언트에게는 좋으므로 이것을 사용하면 바로 사용할 수 있습니다. 기능을 사용하여 의도하지 않은 작업을하려고합니다. –

+0

적절히 작성된 후기 바인딩 클라이언트는 이진 불일치로도 안전하다는 것을 양보 할 것입니다. 왜냐하면 캐시 된 인터페이스 세부 정보 (예 : dispids 및 매개 변수 개수)가 없기 때문입니다. 여전히 AutoUnknown이 존재하지 않는 이유는 아직 없습니다. 단순히 늦은 바운드 클라이언트를 지원하고 싶지 않습니다. 내 인터페이스가'IDispatch'에서 파생되기를 원하지 않습니다. 제 타입 라이브러리에 부 풀림을 원하지 않습니다. 여기에 대한 답변이 없으면 나는 지금 내 자신의 자동 생성을 진행하고 있지만 더 많은 아이디어를 듣고 싶다. 지금까지 통찰력을 얻은 것에 대해 (여러분 모두에게) 감사드립니다! – bob