SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

COM相互運用機能の利用 - パート2

.NETイベントをCOMクライアントに公開する

.NETイベントをCOMに公開する

 .NETでは、イベントはデリゲート(委譲)によって実現されますが、ここではデリゲートの説明は省略します。デリゲートの詳細については、MSDNマガジン2003年2月号の記事『A Primer on Creating Type-Safe References to Methods in Visual Basic .NET』を参照してください。

 まず、開発者が特に何もしなかった場合に、.NETイベントがどのようにCOMに公開されるかを見てみましょう。単純なBug(虫)クラスがあり、このクラスがHungryイベント(虫が空腹になると発生するイベント)とFoundイベント(虫が餌、木などを見つけたときに発生するイベント)を公開するとします。

VB.NETの場合
Option Strict On
Option Explicit On

Namespace BugVB

    Public Class Bug
        Public Delegate Sub HungryEventHandler()
        Public Delegate Sub FoundEventHandler(ByVal item As String)

        Public Event Hungry As HungryEventHandler
        Public Event Found As FoundEventHandler

    End Class

End Namespace
C#の場合
using System;

namespace BugCS
{
    public class Bug
    {
        public delegate void HungryEventHandler();
        public delegate void FoundEventHandler(string item);

        public event HungryEventHandler Hungry;
        public event FoundEventHandler Found;

    }
}

 VB.NETのコード例で、イベントのデリゲートを明示的に定義している点に注目してください。この定義はVB.NETで自動的に行われるものなので必須ではありませんが、同じ処理のコードをC#とVB.NETの両方で表す場合、私はコードができる限り同じになるようにし、便利なコンパイラ機能に依存しないようにしています。

 TLBEXP.EXEを使用してこのオブジェクトのCOMタイプライブラリを生成すると、タイプライブラリには各デリゲートのコクラスができますが、イベントを検出するメカニズムは含まれていません。前述のVB6の例のようなソースインターフェイスがないのです。ソースインターフェイスがないと、VB6でこのタイプライブラリへの参照を追加してオブジェクトブラウザで確認しても、イベントは表示されません。

 COMオブジェクトがCOMのコネクションポイントプロトコルを使ってこれらのイベントをサブスクライブできるようにするには、HungryメソッドとFoundメソッドを定義するインターフェイスが必要です。このインターフェイスによって、シンクオブジェクトへのコールバックが行えるようになります。スムーズな.NET/COM統合を行うために、この手順に進みましょう。

イベントを表すインターフェイスの定義

 まず、通常の.NETインターフェイスを定義することから始めましょう。それからそのインターフェイスをCOMソースインターフェイス(イベント用インターフェイス)として公開します。ここで以下の点が重要になります。

  • 他のクラスやインターフェイスをCOMに公開する場合と同様、固有のGUIDが必要です(COM相互運用機能とGUIDの詳細についてはパート1の記事を参照)。
  • これらのイベントがVB6で動作するようにするには、イベントをCOMのDispInterface型にします。これを行うにはインターフェイスにInterfaceType属性を適用します。
  • ソースインターフェイスの各メソッドのメソッド名およびシグネチャを、各イベント(デリゲートではない)の名前およびシグネチャと完全に同一にします。
  • ソースインターフェイスの各メソッドには、0より大きい一意の値のSystem.Runtime.InteropServices.DispId属性を適用します。一意のDispIdを指定すると、COMは遅延バインディングを行わずに直接メソッドを呼び出せます。

 Bugオブジェクトのソースインターフェイスとして使用する.NETインターフェイスを以下に示します。

VB.NETの場合
Imports System.Runtime.InteropServices

<Guid("A66356CF-7408-4bf5-B02E-17158FE30DA3"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface IBugEvents
    <DispId(1)> _
    Sub Hungry()

    <DispId(2)> _
    Sub Found(ByVal item As String)
End Interface
C#の場合
using System.Runtime.InteropServices;

[Guid("A66356CF-7408-4bf5-B02E-17158FE30DA3")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IBugEvents
{
    [DispId(1)]
    void Hungry();

    [DispId(2)]
    void Found(string item);
}

 インターフェイスを定義したので、これをイベントのソースインターフェイスにすることをTLBEXP.EXEに指定します。Bugクラスでこのインターフェイスを実装する必要はありません。このインターフェイスはCOM相互運用機能がプレースホルダとして使うだけです。インターフェイスメソッドのシグネチャを.NETイベントのシグネチャと同じにすることが重要なのはそのためです。TLBEXP.EXEにとってはプレースホルダにすぎないので、これらが同じでなくても.NETではその不一致が検出されないからです。BugクラスではComSourceInterfaces属性を使用して、どのインターフェイスをイベントシンクが受信できるソースインターフェイスとするかをCOMに通知します。Bugクラスの例では、IBugEventsインターフェイスを指定します。

VB.NETの場合
<ComSourceInterfaces(GetType(IBugEvents))> _
Public Class Bug
    Public Delegate Sub HungryEventHandler()
    Public Delegate Sub FoundEventHandler(ByVal item As String)

    Public Event Hungry As HungryEventHandler
    Public Event Found As FoundEventHandler

End Class
C#
[ComSourceInterfaces(typeof(IBugEvents))]
public class Bug
{
    public delegate void HungryEventHandler();
    public delegate void FoundEventHandler(string item);

    public event HungryEventHandler Hungry;
    public event FoundEventHandler Found;

}

 この.NETクラスをCOMにエクスポートすると次のようになります。

coclass Bug {
    [default] interface _Bug;
    interface _Object;
    [default, source] dispinterface IBugEvents;
};

 パーフェクトです。これでIBugEventsインターフェイスがソースインターフェイスとして指定されました。「COM相互運用機能の利用」パート1の記事と同様、ここでも周辺の具体的な処理は省略しました。このサンプルでは、COMのイベントメカニズムを示す部分だけを記載してます。VB6のオブジェクトブラウザでこのタイプライブラリを確認すると、意図したとおりにイベントが表示されます。

まとめ

 COMに公開するイベントの定義はとても簡単ですが、次のような手順が必要です。

  1. 必要なイベントを.NETコンポーネント内で定義する。
  2. .NETコンポーネントのイベントと同じメソッド名とシグネチャを含むインターフェイスを作成する。
  3. InterfaceType属性を使用してこのインターフェイスをIDispatchインターフェイスにする。
  4. .NETオブジェクトでComSourceInterfaces属性を使用して、このインターフェイスをCOMイベントのソースインターフェイスにする。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Patrick Steele(Patrick Steele)

ミシガン南東部で独立コンサルタントとして活動。ASP.NET、WinForms、COM+、COM相互運用機能など.NETの広範な経験を持つ。ミシガン五大湖地域の.NETユーザーグループ(GANG - http://www.migang.org)の主事でもあり、過去5年にわたりMicrosoft社の.NET ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/438 2006/08/22 15:50

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー