1

.NETのSystem.Runtime.InteropServices.ClassInterfaceType列挙にはAutoDispatch値と値AutoDualがありますが、値はありませんAutoUnknownなぜそうしないのですか? また、車輪を再発明する必要がないように、それを達成するためのかなり自動化された方法を誰かがすでに考え出していますか?

もう少し背景として、現在の列挙型の 3 つの値とその機能を次に示します。

  • ClassInterfaceType.Noneはクラス インターフェイスを作成しません。これは Microsoft の推奨値です。クラス インターフェイスがない場合は、意図するメンバーを使用して独自のインターフェイスを作成し、クラスにそれを実装させる必要があります。次に、インターフェイスでSystem.Runtime.InteropServices.ClassInterfaceAttribute属性を使用して、インターフェイスをディスパッチ インターフェイス (レイト バインド クライアントをサポート)、不明なインターフェイス (アーリー バインド クライアントをサポート)、またはデュアル (アーリー バインド クライアントとレイト バインド クライアントの両方をサポート) にすることができます。
  • ClassInterfaceType.AutoDispatchIDispatch明示的なメンバーなしでから派生したクラス インターフェイスを作成します。明示的なメンバーがない場合、遅延バインディングの呼び出し元のみをサポートできます。
  • ClassInterfaceType.AutoDualから派生したクラス インターフェイスを作成します。このインターフェイスは、IDispatchそのクラスのすべてのパブリック非静的メンバーの明示的なメンバーと、その基本クラスおよび実装されたインターフェイスのすべてのメンバーを持ちます。クラスのメンバーのいずれかが変更されると、クラス インターフェイスも変更されるという事実から生じる「バージョン管理の制限のため」、Microsoft はこの値の使用を強くお勧めしません。(そのため、クラスが変更された後に再バインドしない呼び出し元は、間違ったメソッドを呼び出したり、間違ったパラメーターを渡したりする可能性があります。)

だから私が疑問に思っているのは、クラスのメンバーを明示的に宣言するClassInterfaceType.AutoUnknown派生クラスインターフェイスを作成する値が呼び出されない理由ですIUnknown(基本クラスまたはそれが実装する他のインターフェイスではありません)。

私たちがClassInterfaceType.AutoDualDirectそれに取り組んでいる間、基本クラスのすべてのメンバーと実装されたすべてのインターフェイスを公開する代わりに、他のメンバーができるため、クラスの直接のメンバーのみを公開することを除いて、AutoDual に似たようなものがあることも期待できます。他の COM インターフェイスを介して取得できます。

それで、ここでの話は何ですか、何が欠けていますか?Microsoft が AutoDual を使用しないことを推奨していると言っているのは知っています。「バージョン管理の問題」があるからです。これらの懸念は AutoUnknown にもある程度当てはまります。しかし、その推奨にもかかわらず、彼らはまだAutoDualを持っています。彼らはなぜ AutoUnknown も持っていないのでしょうか?

これらの「バージョン管理の課題」について一言: これらの懸念事項の最も危険な側面は、遅延バインディングの呼び出し元にのみ適用されます。AutoUnknown は、派生IUnknownインターフェイスではなく、派生インターフェイスを生成するため、事前IDispatchにバインドされたクライアントが持つ可能性のあるバージョン管理の問題だけを気にする必要があります。また、自動生成されたクラス インターフェイスの IID は、クラスの public 非 static メンバーが変更されるたびに変更されるため、事前にバインドされたクライアントは既存のメンバーに対して「不適切な呼び出し」を行うことができず、単純に QueryInterface( ) クラス インターフェイスの場合。まだ失敗ですが、クラッシュなどではなく、管理可能なものです。これは、インターフェイスの変更を決して許可しないという COM の規則を破るものではありません。変わるのではなく、新しいインターフェース (新しい IID) になりつつあります。それはそう、IUnknownAutoDual メカニズムの半分 (派生メンバーを除く)。実際、AutoDual にはレイト バウンドの課題もすべて含まれているため、AutoDual よりも「バージョン管理の課題」が少なくなります。

繰り返しますが、AutoUnknown が存在しないのに、なぜ AutoDual が存在するのでしょうか。

実際の例をいくつか示すために、次の C# コードを検討してください。

using System.Runtime.InteropServices;

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

次の 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(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);
};

これを自動的に行う方法がない場合は、リフレクションを使用してそれを行うものを作成する予定です。そのため、その面での推奨事項もいただければ幸いです。たとえば、メソッドで確認する必要がある属性はありますか? パラメータについて?私はそれがどのように機能するかを確認するために IL を掘り下げましたSystem.Runtime.InteropServices.TypeLibConverterが、残念ながらすべての機能は、私が取得できないプライベート internalcall nConvertAssemblyToTypeLib() 関数にあります。

ありがとう!

4

1 に答える 1

0

本当の問題は、何を達成しようとしているのかということです。

ClassInterfaceドキュメントから: 「インターフェイスが生成される場合、COM に公開されるクラスに対して生成されるクラス インターフェイスのタイプを示します。」

背後にある考え方ClassInterfaceは、クラスのプログラム インターフェイスを COM クライアントで利用できるようにすることです。これが、基本クラス メソッドを含む完全なインターフェイスが表示される理由です。目標は、クラス機能のサブセットにビューを提供することではありません。それがインターフェースの目的です(およびClassInterfaceType.None

適切に機能するためにクラスのレイアウトに直接依存するため、遅延バインディング機能 (つまりIDispatch) を持たないクラス インターフェイスを提供することは、実際には行うべきではありません (幸いなことに有効にしません)。ClassInterfaceこれは、クラスもその基本クラスも変更されないことを意味します。これは保証するのが難しいことであり、COM の哲学全体に反するという事実に加えて、これが一般的に悪い考えである理由です。事前にバインドされたクライアントは、インターフェイスの vtable レイアウトに密接に結合されています。レイアウトを変更すると、レイアウトが壊れます。メソッドは名前で解決され、不足しているメソッドを適切に処理できるため、レイト バインド クライアントではこの問題は発生しません。

を使用AutoDualすると、本当に必要な場合にメソッドへの早期バインド アクセスが既に提供されているため、車輪を再発明する理由がわかりません。

于 2013-03-18T17:14:10.810 に答える