Chapter.4

アドバイザリーシンク


2004/6/17
 ・ソースのMarshal.BindToMonikerの呼び出し部分がコメントになっていたのを条件付コンパイルに変更。
2004/6/24
 ・サンプルソースで、構造体変数をNewで初期化しているものをNewしないように修正。

1.OLEサーバからの通知

前回のサンプルプログラムでは、IOleObjectのいくつかのメソッドをテストしていません。 一部のメソッドを呼び出した場合に、OLEサーバの状態を更新する可能性があることが挙げられます。 OLEサーバは状態が更新されると、それをクライアントに通知しようとします。 前回のサンプルプログラムでは、その通知を受け取る機構を実装していなかったので、OLEサーバを更新するメソッドをテストしていませんでした。

このOLEサーバからの通知を受け取る機構のことをアドバイザリーシンク(advisory sink)と呼びます。 通知のことをアドバイス通知と呼んでる書籍もあります。
ただ、私はadviseをどう聞いてもアドバイズ に聞こえるので、コレに釈然としないものを感じます。 検索サイトのgooでは、発音を聞けるので聞いてみてください。advise
とりあえず、このサイトでは通知を受け取る機構のことをアドバイザリーシンク、通知のことをアドバイ通知と呼ぶことにします。

ただ、これを言い出すとエクステントはイクステントになるな・・・。extent
忘れよう・・・。



2.アドバイザリーシンクの実装

とりあえず、サンプルを見て下さい。
VB.NETサンプルソース:chap4.vb.lzh(23KB未満 2004/06/24)

前回からの最も大きな違いは、MainFrameクラスがIAdviseSinkインターフェースを実装するようになったことです。 これをOLEサーバに通知先として登録することになります。 アドバイザリーシンクを登録するメソッドとしては、IDataObject.DAdviseIOleObject.Adviseが挙げられます。 また、まだ解説はしていないのですが、IViewObjectにもIViewObject.SetAdviseというアドバイザリーシンクを登録するメソッドがあります。

OLEサーバの状態を更新するメソッドとして、IOleObjectのテストメニューにSetExtentメソッドの呼び出しを追加しました。 現在は、単純にOLEサーバのエクステントを取得し、それを変更して設定するだけです。

最後に、オブジェクトのクリーンアップ処理(Closedハンドラ内)で、アドバイザリーシンクをOLEサーバから切断するメソッド、IDataObject.DUnadviseIOleObject.Unadviseを呼び出すように修正しています。


3.まとめと留意事項

OLEサーバ側からの通知を受け取る仕組みは理解して頂けたでしょうか?
現在のサンプルでは、通知を引き起こす可能性があるのは、IOleObject.SetExtentメソッドを呼び出した場合であり、 アドバイザリーシンクを利用しなくても、OLEサーバの状態が更新されたことを容易に判別可能です。 しかし、実際には、OLEサーバが自分自身を更新するシナリオが存在する可能性があるのです。 (ファイルが更新されたことを自動で認識して、ファイルを読み込みなおすOLEサーバ等)

IAdviseSinkには、5つの通知メソッドがあるのですが、OLEサーバのインターフェース毎に使用するメソッドが異なります。 それを簡単に表にまとめてみました。
インターフェース 通知に使用するメソッド
IDataObject ・OnDataChange
IOleObject ・OnRename
・OnSave
・OnClose
IViewObject ・OnViewChange
となります。通常、通知先として登録しなければ、それに対応するメソッドが呼び出されることはありません。 IDataObject.DAdviseIOleObject.Adviseのどちらかを呼び出さないようにして、テストしてみるのも面白いと思います。
ただし、仕様に準拠していないOLEサーバは、呼び出してくる可能性があります。今回、IViewObjectは使用していませんが、 OnViewChangeを呼び出してくるOLEサーバが存在するかもしれません。

このサンプルで最後に注目しておく点(これもOLEサーバの実装の揺らぎとなるが・・・)は、IOleObject.SetExtentメソッドを呼び出しても、 データが更新されたと判断しないOLEサーバが存在することです。これは、ビットマップイメージを扱うOLEサーバはそう動作するのですが、特に仕様に違反しているわけではありません。 ここが分かりにくいところなのですが、エクステントはOLEサーバ内部のオブジェクトサイズと一致している必要は無いのです。 また、IOleObject.SetExtentに対して、HRESULT.S_OK(=正常終了)を返却しているからといって、 OLEサーバが内部で保持しているエクステントを更新する保障は無いのです。(つまり、SetExtentした結果とGetExtentした結果が一致しない。Excelはそう動作する。これは内部に保持しているエクステントを使用するためだと推察されるが、詳細は不明。)
アドバイザリーシンクの話から脱線するので、ここではこれ以上説明しませんが、そういう動作をするものが存在するということを覚えておいてください。


前へ 次へ
OLE on .NET Frameworkへ
総合トップへ