今回から、インプレースアクティベーションに対応したオブジェクトの作成について見ていきます。今回作成するサンプルでは次のようにウインドウを表示します。見て分かるように、オブジェクトのウインドウがコンテナ上に表示されています。オブジェクトのツールバーもコンテナ上に表示されています。オブジェクトの動作内容はOLE埋め込みの際と同様であり、クリックした位置に図形を描画します。オブジェクトもIOleInPlaceObjectという新しいインターフェースを実装することになります。このクラスがIOleInPlaceObjectを実装するようになればよいでしょう。インプレースアクティベーションの開始は、IOleObject::DoVerbによって伝えられます。OLEIVERB_INPLACEACTIVATEである場合はインプレースアクティベーションのみを行います。この区別については、InPlaceActivateの第3引数で行われます。第1引数はインプレース先のウインドウハンドル、第2引数はインプレースの位置を表すRECT構造体になります。そのような場合はbOpenをTRUEにして通常のウインドウを開くようにします。これは、iVerbにOLEIVERB_OPENが指定された場合も同様です。InPlaceActivateの実装は次のようになっています。それをコンテナのサイトがサポートするのかを確認しなければなりません。インプレースアクティベーションが可能であると判断します。オブジェクトのウインドウをコンテナ上に表示する作業に入ります。ウインドウスタイルにはWS_CHILDを指定します。第10引数には親ウインドウのハンドルを指定し、第11引数にはウインドウのIDを指定します。コンテナのウインドウにWM_PARENTNOTIFYが送られないようにできます。このメッセージはウインドウの作成や破棄を通知する意味を持ちますが、そうした通知は送る意味は特にありません。この時点でインプレースアクティベーションは完了したことになります。これについては次節で説明します。疑問に思う部分があるかもしれません。このウインドウをコンテナの子ウインドウに設定しては何か問題があるのでしょうか。確かにm_hwndはhwndParentの子ウインドウになるのです。それは子ウインドウとして正しく認識されることを無条件に意味するものではありません。子ウインドウとして不完全な形になるという問題があります。作成時にIDを指定することもできませんし、動的にIDを設定する手段も用意されていません。これを指定しても関数が成功することはありません。以上の事から、インプレースアクティベーション用のウインドウを別個作成するという方法を使用しています。元となるウインドウクラスが互いに異なります。ウインドウプロシージャを別々にしたほうがよいと考えたからです。m_hwndInplaceのウインドウクラスは、CObject::Runで次のように作成されています。m_szInplaceClassNameに保存するようにしています。次のような実装を持っています。lParam);}WindowProcと比べて、WM_CREATEやWM_CLOSEを処理していないことに注目してください。WindowProcよりも構造が簡素になります。ウインドウスタイルにWS_THICKFRAMEを指定していたためです。変更後のサイズをOnPosRectChangeでサイトに通知しています。折り返しSetObjectRectsを呼び出します。SendOnDataChangeを呼び出しているのは、コンテナのデフォルトハンドラがキャッシュしているイメージを更新するためです。ウインドウのサイズが変更された場合は、このキャッシュも変更されなければなりません。IOleInPlaceObjectを実装していなければなりません。以下、各メソッドの実装を示します。IOleWindowのメソッドも実装する必要があります。ない場合はm_hwndを返します。E_NOTIMPL;}ContextSensitiveHelpもIOleWindowのメソッドですが、基本的に呼ばれることはないのでE_NOTIMPLを返すだけで構いません。S_OK;}InPlaceDeactivateは、オブジェクトのインプレースアクティベーションを解除する目的で呼ばれます。UIDeactivateを呼び出してそれを行います。このメソッドの実装については次節で取り上げます。インプレースアクティベーション用のウインドウを破棄すれば問題ありません。OnShowWindowでそれを通知しておきます。この際にはInPlaceDeactivateを明示的に呼び出すようにしておきます。E_NOTIMPL;}ReactivateAndUndoは、基本的に呼ばれることがないためE_NOTIMPLを返すだけで構いません。どちらかというと、オブジェクトがIOleInPlaceSite::OnPosRectChangeを呼び出した際に折り返し呼ばれることが多いと思われます。WordやExcelでは、オブジェクトのデータの変更を検出した際にも呼び出すようになっています。WordやExcelの場合は一点注意すべきことがあります。それは、このサイズ変更によってウインドウのサイズが小さくなっていくという点です。変換結果に誤差が生じます。これにより、オブジェクトのサイズは小さくなってしまいます。Undo操作に関するメソッドが含まれています。実際にどのような使用例があるのかを理解するために、Excelを例に取り上げて説明します。コンテナがExcelをインプレースアクティベーションしたとします。どこかの位置に何らかの文字を入力したとします。これはExcelがUndo情報を維持しているから起こることです。このようなUndo情報を削除したい場合は、IOleObject::DoVerbにOLEIVERB_DISCARDUNDOSTATEを指定します。Undo操作を行いたい場合は、IOleInPlaceObject::ReactivateAndUndoを呼び出します。続いて、Excelがオブジェクトをインプレースアクティベーションした例を考えます。Zを押せば再びアクティベーションが行われるはずです。これを削除したい場合はIOleInPlaceSite::DiscardUndoStateを呼び出します。インプレースアクティベーションの解除だけでなく、オブジェクトの作成もなかったことにすることができます。