6

古い VB6 アプリケーションで COM を使用しています。

を使用するよりもうまく機能するように見えるため、インターフェイスで DispID を使用するようにコードを変更しました[ClassInterface(ClassInterfaceType.AutoDual)]

しかし、クラスが 2 つのインターフェイスを使用している場合でも、DispID(1) から数えて各インターフェイスで開始することはできますか?

この方法で安定して動作しますか?それとも私は何かを誤解していますか?

[ComVisible(true)]
[Guid("9E1125A6-...")]
public interface IMyInterface1
{
    [DispId(1)]
    string Name1 { get; }
}

[ComVisible(true)]
[Guid("123425A6-...")]
public interface IMyInterface2
{
    [DispId(1)]
    string Name2 { get; }
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
class MyClass : IMyInterface1, IMyInterface2
{
    public string Name1 { get { return "Name1"; } }
    public string Name2 { get { return "Name2"; } }
}
4

3 に答える 3

6

クラスが 2 つのインターフェイスを使用する場合でも、DispID(1) から数えて各インターフェイスで開始することはできますか?

DISPID は、インターフェイス内でのみ一意である必要があります。両方のインターフェイスが同じ COM オブジェクトによって実装されている場合でも、それぞれが独自の (異なる) DISPID 1 プロパティを持つ 2 つのインターフェイスを使用することをお勧めします。

ただし、VB6 について言及されているため、VB6 は同じ COM オブジェクトに実装された 2 つ以上のディスパッチ インターフェイスを好まず、最初のメインのインターフェイスのみを「参照」する可能性があることに注意する必要があります。つまり、問題は DISPID の衝突ではなく (まったく問題ではありません)、2 つ以上のデュアル インターフェイスを公開しているオブジェクトを VB6 が正しく処理できないという事実です。これが発生する理由は、MSDN in Multiple Dual Interfacesで説明されています。

IDispatch インターフェイスが 1 つしか公開されていないため、IDispatch インターフェイスを介してのみオブジェクトにアクセスできるクライアントは、他のインターフェイスのメソッドまたはプロパティにアクセスできません。

そして悲しいことに、それはVB6の場合です。より高度な環境とは異なり、「他のインターフェイスのメソッドまたはプロパティ」にアクセスできない方法でインターフェイスをクエリしています。ただし、異なる DISPID を割り当てることは役に立ちません。

于 2013-04-25T15:12:02.257 に答える
3

COM オブジェクトごとに 1 つの IDispatch 実装しかないため、IDispatch::Invokeなどの呼び出しを成功させるには、COM オブジェクトごとに一意の DISPID が必要です。

編集:実際、ハンスがコメントで指摘しているように、実際、それについてもっと考えた後、質問はまったく無関係です. ClassInterfaceType を None として定義しているため、.NET は最初のインターフェイス IMyInterface1 dispids のみを使用可能にすることを意味します (既定では、ComDefaultInterfaceAttributeクラス属性を使用して既定のインターフェイスを構成できます)。

ClassInterfaceType を AutoDual または AutoDispatch として使用する場合、DISPID は自動生成され、手動で定義されたものは使用されません。

.NET はインターフェイスを組み合わせたりマージしたりしません。したがって、dispid が異なるという事実は、この ".NET が COM として公開された" ケースでは重要ではありません。これは、1 つの DISPID セットのみが (既定のインターフェイスに対して) 使用されるためです。同じクラスで同じ DISPID のセットを 2 回定義すると、正常にコンパイルされますが、regasm は文句を言い、重複したものを無視することに注意してください。

以下は、これらすべてを確認する小さな C++ プログラムです。

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    IDispatch *pDispatch;
    CoCreateInstance(__uuidof(MyClass), NULL, CLSCTX_ALL, IID_IDispatch, (void**)&pDispatch);
    DISPID dispid;
    LPOLESTR name1 = L"Name1";
    LPOLESTR name2 = L"Name2";
    HRESULT hr;
    hr = pDispatch->GetIDsOfNames(IID_NULL, &name1, 1, 0, &dispid);
    printf("Name1:%i hr=0x%08X\n", dispid, hr);
    hr = pDispatch->GetIDsOfNames(IID_NULL, &name2, 1, 0, &dispid);
    printf("Name2:%i hr=0x%08X\n", dispid, hr);
    pDispatch->Release();
    CoUninitialize();
    return 0;
}

これは次のように出力されます。

Name1:1 hr=0x00000000 (S_OK)
Name2:-1 hr=0x80020006 (DISP_E_UNKNOWNNAME)

AutoDispatch または AutoDual に変更すると、次のように出力されます (ID は何らかのアルゴリズムを使用して計算されます)。

Name1:1610743812 hr=0x00000000
Name2:1610743813 hr=0x00000000
于 2013-04-25T14:07:33.243 に答える