| デベロッパー | 2006年7月4日 10:00 |
|
COM相互運用機能の利用 - パート2 著者: Patrick Steele オリジナル版を読む ▼2006年7月4日 10:00 付の記事 ■海外internet.com発の記事 はじめにこの記事は、私が書いた記事『COM相互運用機能の利用』の続編です。今回は、.NETイベントをCOMクライアントに公開する方法について説明します。 パート1の記事と同様、今回もCOMのイベントについての簡単な復習から始めます。これによって.NETイベントをCOMに公開する方法が理解しやすくなります。残念ながら、.NETイベントを作成して後はCOM呼び出し可能ラッパー(CCW)に任せるというような単純なものではありません。COM/.NETのイベント統合を適切に行うには、いくつかの属性を適用する必要があります。 COMイベントの背景パート1の記事と同じように、COMイベントの背景についてもインターフェイスを中心に説明します。なぜなら、COMには.NETのような真のイベントのネイティブサポートがないからです。COMはインターフェイスを使ってイベントをシミュレートしています。 イベントメカニズムには、以下の主要機能が必要です。
COMでは、「コネクションポイントプロトコル」というプロセスでインターフェイスを介してこれらのメカニズムを実現しています。 ソースオブジェクトCOMのコネクションポイントプロトコルでは、あるオブジェクトをイベントのソースにするには、そのイベントを表現するメソッドを含んだインターフェイスをソースオブジェクト内に定義します。この点は重要なので、確実に覚えておいてください。 例えば VB6コードは次のようになります。 Public Event Click() Public Event MouseOver(ByVal x As Integer, ByVal y As Integer) これをコンパイルすると、COMタイプライブラリで示される
coclass CButton {
[default] interface _CButton;
[default, source] dispinterface __CButton;
};
1番目のインターフェイス
dispinterface __CButton {
properties:
methods:
[id(0x00000001)]
void Click();
[id(0x00000002)]
void MouseOver(
[in] short x,
[in] short y);
};
VB6で定義したイベントが、ソースインターフェイスのメソッドになっている点に注目してください。この点を理解しておくことが、COMに公開する.NETイベントを設定する上で重要です。 このソースオブジェクト( シンクオブジェクト イベント発生の通知を受ける、つまりイベントを「サブスクライブ」する側のオブジェクトは、ソースインターフェイスを実装することでこれが可能になります。上記の例の場合は、シンクオブジェクトに ソースオブジェクトがイベントを発生させるときには、サブスクライバリストを順に見ていき、個々のサブスクライバをインターフェイスにキャストして、各シンクオブジェクトの当該イベントを表すインターフェイスメソッドを呼び出します(先ほど述べたように、シンクオブジェクトにはイベントを表すインターフェイスが実装されています)。例えば このように、COMのコネクションポイントプロトコルは複雑なコールバックの仕組みになっています。コールバック(イベント)はインターフェイスで定義されます。COMに組み込まれているさまざまなインターフェイスが、サブスクライブ、サブスクライブ解除、シンクオブジェクトへのコールバックの機能を受け持ち、イベントメカニズム全体を構成しています。 .NETイベントをCOMに公開する.NETでは、イベントはデリゲート(委譲)によって実現されますが、ここではデリゲートの説明は省略します。デリゲートの詳細については、MSDNマガジン2003年2月号の記事『A Primer on Creating Type-Safe References to Methods in Visual Basic .NET』を参照してください。 まず、開発者が特に何もしなかった場合に、.NETイベントがどのようにCOMに公開されるかを見てみましょう。単純な 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のコネクションポイントプロトコルを使ってこれらのイベントをサブスクライブできるようにするには、 イベントを表すインターフェイスの定義まず、通常の.NETインターフェイスを定義することから始めましょう。それからそのインターフェイスをCOMソースインターフェイス(イベント用インターフェイス)として公開します。ここで以下の点が重要になります。
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に指定します。 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;
};
パーフェクトです。これで ![]() まとめCOMに公開するイベントの定義はとても簡単ですが、次のような手順が必要です。
著者紹介Patrick Steele(Patrick Steele)
ミシガン南東部で独立コンサルタントとして活動。ASP.NET、WinForms、COM+、COM相互運用機能など.NETの広範な経験を持つ。ミシガン五大湖地域の.NETユーザーグループ(GANG - http://www.migang.org)の主事でもあり、過去5年にわたりMicrosoft社の.NET MVPを受賞。連絡したい場合は、ブログhttp://weblogs.asp.net/psteeleから、またはpatrick@mvps.orgまで。
|