Chapter.22

埋め込みコンテナ(2)

2007/6/10
 ・サンプルソースの名前を付けて保存した時にIOleObject.SetHostNamesが呼び出されていない問題を修正。
2007/6/12
 ・サンプルソースのサブストレージのプレフィックスを"EMBEDDED"から"OLEOBJECT"に変更。

1.オブジェクトの埋め込み

オブジェクトの埋め込みについては、今までのサンプルで実装方法は明らかですので、今回は最初にサンプルを提示します。

VB.NETサンプルソース:chap22.vb.lzh (40KB 2007/6/12)
C#サンプルソース:chap22.cs.lzh (39KB 2007/6/12)

前回のサンプルソースにオブジェクトの埋め込み処理を追加していますが、インプレースアクティベーションは実装していません。これは後の章で解説する予定であるリンクコンテナの解説では不要だと考えたためです。
埋め込んだオブジェクトをドラッグして移動できるようにするため、オブジェクトを操作する選択モードを追加しています。線を描く時には選択モードを解除する必要があります。サンプルソースの大半のコードはこれらマウス操作を実現するためのものです。


2.埋め込みコンテナで使用するAPI

埋め込みコンテナの実装に欠かせないOLEのAPIを解説していきます。

OleUIInsertObject
Office製品等のOLEをサポートするアプリケーションを使用していると下のようなダイアログを見たことがあるかもしれません。
オブジェクトの挿入ダイアログ - 新規作成オブジェクトの挿入ダイアログ - ファイルから作成
これらはOLEによって提供される標準のダイアログです。OleUIInsertObjectは、これらのダイアログの表示と埋め込むオブジェクトに対応するインプロセスハンドラの起動までを処理します。非常に強力ですが、インターフェースポインタへのポインタを使用しなければならないため、マネージコードから呼び出すのは多少手間が掛かります。まぁ、マネージコードからOLEのAPIを直接使用することは通常無いと思いますが・・・。

OleSave
前回解説していたサブストレージへのCLSIDの設定とオブジェクトの保存を処理します。OleSaveで保存したサブストレージはOleLoadで正確にロードすることができます。また、MSDNライブラリのOleSaveの解説には明記されていませんが、インプロセスハンドラによって埋め込んだオブジェクトの代替イメージが保存されるのも、このタイミングであると私は考えています。

OleLoad
OleSaveで保存したサブストレージを読み込み、対応するオブジェクトサーバのインプロセスハンドラを起動します。OleCreateOleCreateFromFileOleUIInsertObject等とは異なり、対象となるサーバが存在しない(インストールされていない)場合でも、インプロセスハンドラを起動することができます。これはOleSaveで保存した代替イメージを使用することにより実現されています。

OleSetContainedObject
オブジェクトサーバに対してオブジェクトが埋め込まれたことを通知します。この呼び出しはリンク可能なサーバとコンテナでなければ、まったく意味を成しません。今後のために呼び出しています。OleLoadで起動したサーバに対しては呼び出しを行っていませんが、これはOleLoadではインプロセスハンドラしか起動されないため、呼び出す必要がないからです。オブジェクトサーバが起動するまで、呼び出す必要はありません。

OleDraw
IViewObjectを使用してオブジェクトを描画します。インプロセスハンドラはオブジェクトサーバが実装するIDataObjectから取得できる描画用データを使用してIViewObjectを集成します。第5章で解説しようとしていたIViewObjectは、このインプロセスハンドラの解説を待っても良かったなと・・・。


3.まとめ

今までの章とは異なり、OLEのAPIを活用しているのでソースは全体的にすっきりしていると思います。
その他、解説しておかなければならないこととしては、オブジェクトの位置を管理するのはコンテナの役目です。この章ではOBJECTSストリームに埋め込んだオブジェクトの位置を記録しています。描画用データとオブジェクト管理用データを分けているため、本章で作成したファイルを前章のアプリケーションで読み書きすることができます。その際、CONTENTSストリーム以外を操作しないので、埋め込んだオブジェクトは本章で保存した状態が維持されます。

なお、この章でOleContainerクラスがSystem.ComponentModel.IComponentインターフェースを実装している理由は、IOleItemContainerの実装に.NET Frameworkの汎用コンテナ(System.ComponentModel.Container)を使用するための布石です。また、System.ComponentModel.Componentクラスを継承せずに、System.ComponentModel.IComponentインターフェースを直接実装しているのは、インプレースアクティベーションを実装する場合、別の基本クラスを使用した方が実装しやすかったためです。


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

サンプルで使用しているキーワード
IAdviseSink IOleClientSite IOleObject IPersistStorage IRootStorage IStorage IStream IViewObject2 OleDraw OleLoad OleSave OleSetContainedObject OLEUIINSERTOBJECT OleUIInsertObject StgCreateDocfile StgOpenStorage System.ComponentModel.IComponent