関数名の競合を解決する例
次の点について検討してください。
- IADs0はFunc0をサポートしていません。
- IADs1はFunc1とFunc0をサポートしています。
- IADs2はFunc2とFunc0をサポートしています。
3つのインターフェイスはすべてデュアルインターフェイスです。
IADs0 : IDispatch
{
OtherFunc();
}
IADs1 : IDispatch
{
Func0()
Func1();
}
IADs2 : IDispatch
{
Func0()
Func2();
}
Dim myInf1 as IADs1
myInf1.Func1 ' IADs1::Func1 is invoked using direct vtable access
myInf1.Func2 ' IADs2::Func2 is invoked using GetIDsOfNames/Invoke
IADs1がFunc2をサポートしていない場合でも、ADSIクライアントは、モデル内のすべてのデュアルインターフェイスとディスパッチインターフェイスをサポートする1つのIDispatchを認識することに注意してください。 したがって、ADSIクライアントは、Func2をサポートするインターフェイスを解決せずに、myInf1.Func2を使用してFunc2を直接呼び出すことができます。
myInf1.Func2
IADs1とIADs2の両方にFunc0という関数がありますが、次の両方がクライアントに適用されるため、IADs1 :: Func0はvtableアクセスを使用して直接呼び出されます。
- クライアントには、Func0という関数を持つデュアルインターフェイスIADs1オブジェクトへのポインターがあります。
- Visual Basicは、データの種類がタイプライブラリを介して使用できることを前提として、直接vtableアクセスをサポートしています。
次のコード例では、クライアントにIADs1ではなくIADs2へのデュアルインターフェイスポインターがあります。 そのため、IADs2 :: Func0は直接vtableアクセスを使用して呼び出されます。
Dim myInf2 as IADs2
Set myInf2 = myInf1 ' Query for pointer to IADs2
myInf2.Func0
ここでも、次のコード例では、IADs1とIADs2の両方にFunc0という関数がありますが、ここでは、クライアントにIADs0という名前の関数がないデュアルインターフェイスへのポインターがあります。 そのため、直接vtableアクセスを実行することはできません。 代わりに、IDispatch :: GetIDsOfNamesとInvokeを呼び出してFunc0を呼び出します。
Dim myInfNone as IADs0
Set myInfNone = myInf1 ' The aggregated object that
' supports IADs1 and IADs2.
myInfNone.Func0
次の2つのケースを考えてみます。
- IADs1とIADs2は、それぞれExt1とExt2の2つのCOMコンポーネントによって実装されます。 Ext1がレジストリのExt2の前にある場合は、IADs1 :: Func0が呼び出されます。 ただし、Ext2がレジストリの最初にある場合は、IADs2 :: Func0が呼び出されます。
- IADs1とADs2が同じ拡張機能オブジェクトによって実装されている場合、Func0は常に拡張機能のIADsExtension :: PrivateGetIDsOfNamesおよびPrivateInvokeメソッドによって呼び出されます。
拡張機能の開発者は、拡張機能で同じ名前を持つ異なるデュアルIDispatchインターフェイスの関数またはプロパティの競合を解決する方法を決定する必要があります。 IADsExtension :: PrivateGetIDsOfNamesおよびPrivateInvokeメソッドの実装では、この競合を解決する必要があります。 たとえば、IMyInterface1 :: Func1とIMyInterface2 :: Func1を使用する場合、IMyInterface1とIMyInterface2は、同じ拡張機能オブジェクトでサポートされているデュアルIDispatchインターフェイスです。 PrivateGetIDsOfNamesおよびPrivateInvokeメソッドは、Func1を常に呼び出す必要があるかどうかを判断する必要があります。
これは、異なるデュアルまたはIDispatchインターフェイスで競合するDISPIDにも適用されます。
たとえば、IMyInterface1 :: YのDISPIDは、ファイルimyinterface1.odlまたはimyinterface1.idlの2です。 IMyInterface2 :: XのDISPIDは、iMyInterface2.odlの2でもあります。 IADsExtension :: PrivateGetIDsOfNamesは、両方に対して同じDISPIDを返すのではなく、拡張機能自体内で一意のDISPIDを返す必要があります。
ADSIは、競合する関数またはプロパティ名を持つ複数のインターフェイスをサポートしないことで、最初の問題を解決します。 同じ拡張機能オブジェクト内にある一意のインターフェイス番号をDISPIDの未使用のビットに追加することで、2番目の問題を解決します。