.NETのSystem.Runtime.InteropServices.ClassInterfaceType列挙にはAutoDispatch
値と値AutoDual
がありますが、値はありませんAutoUnknown
。なぜそうしないのですか? また、車輪を再発明する必要がないように、それを達成するためのかなり自動化された方法を誰かがすでに考え出していますか?
もう少し背景として、現在の列挙型の 3 つの値とその機能を次に示します。
ClassInterfaceType.None
はクラス インターフェイスを作成しません。これは Microsoft の推奨値です。クラス インターフェイスがない場合は、意図するメンバーを使用して独自のインターフェイスを作成し、クラスにそれを実装させる必要があります。次に、インターフェイスでSystem.Runtime.InteropServices.ClassInterfaceAttribute属性を使用して、インターフェイスをディスパッチ インターフェイス (レイト バインド クライアントをサポート)、不明なインターフェイス (アーリー バインド クライアントをサポート)、またはデュアル (アーリー バインド クライアントとレイト バインド クライアントの両方をサポート) にすることができます。ClassInterfaceType.AutoDispatch
IDispatch
明示的なメンバーなしでから派生したクラス インターフェイスを作成します。明示的なメンバーがない場合、遅延バインディングの呼び出し元のみをサポートできます。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) になりつつあります。それはそう、IUnknown
AutoDual メカニズムの半分 (派生メンバーを除く)。実際、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() 関数にあります。
ありがとう!