共有メニューインプレースアクティベーションされたオブジェクトは、コンテナに対してUIに関する通知を送りたいことがあります。ツールバーも表示しなければなりません。よって、このようなUIの要求に応えるために、コンテナはIOleInPlaceFrameを実装することになっています。今回は、IOleInPlaceFrameのメソッドの中で共有メニューに関するものを取り上げていきます。これはコンテナのメニュー内容自体が変更されたわけではありません。その空のメニューに対してコンテナとオブジェクトが項目を追加しているのです。1つのメニューをコンテナとオブジェクトが共有して使用していくのです。空の共有メニューは、IOleInPlaceFrame::InsertMenusを通じて渡されます。S_OK;}hmenuSharedには、コンテナのトップメニューに追加されている項目と同じ項目を追加します。それらをhmenuSharedに追加するようにします。GetSubMenuで既存のメニューからサブメニューを取得すればよいでしょう。InsertMenusにはlpMenuWidthsという引数がありますが、この引数の意味は少し分かりにくいと思われます。その項目がコンテナの項目よりも前に来るのか後に来るのかを判断できなければなりません。よって、その判断要素としてlpMenuWidthsが存在しているのですが、この初期化の仕方が複雑なのです。長い話になりますが、このlpMenuWidthsについて説明していきます。基本的に項目の並び方は、コンテナとオブジェクトで交互に行われるのが平等であるといえます。その次の項目はコンテナの項目、そして今度はオブジェクトの項目という具合です。次に、項目の順番を示します。5この順番から分かるように、コンテナの項目は0,2,4という偶数のインデックスに存在することになります。このため、コンテナはlpMenuWidthsの0,2,4を初期化してよいことになっています。1つの前提として、これらの値の合計はコンテナの項目の数を超えてはなりません。lpMenuWidths[0],lpMenuWidths[2],lpMenuWidths[4]の合計が2を超えてはなりません。例として、lpMenuWidths[0]に1を指定し、lpMenuWidths[2]に1を指定した際の共有メニューを見てみます。上図は、PaintbrushをUIアクティベーションしたものです。コンテナの「オブジェクトの挿入」というように、交互に項目が追加されていることが分かります。これはコンテナが項目を2つしか追加しなかったことに起因します。話はここから複雑になってきます。次の図は、WordPadをUIアクティベーションした結果です。項目の表示が交互に行われていないように思えます。実際には上記の表示には問題ありません。自分の順番の時にどれだけ項目を表示するかは自由になっているからです。この表示する数はlpMenuWidthsの要素に指定することになっています。lpMenuWidths[0]には1を指定していたため、コンテナの項目が1つ表示されます。lpMenuWidths[1]には4が指定されていると考えてよいでしょう。ここには1を指定していたためコンテナの項目が1つ表示されます。「オブジェクトの挿入」は「ファイル」の直後に表示されることになるでしょう。メニューグループ(1つ以上の項目)の表示ということになります。InsertMenusが制御を返せば、オブジェクトはlpMenuWidthsの中身を考慮しながら自身のメニュー項目を適切な位置に追加します。完成した共有メニューをコンテナに設定するためにSetMenuを呼び出します。APIのSetMenuを呼び出すことで共有メニューを設定します。holemenuがNULLである場合は、元のコンテナのメニューに戻す目的でSetMenuを呼び出します。これを可能にするのがOleSetMenuDescriptorです。この関数を呼び出せば、WM_COMMANDやWM_MENUSELECTをメッセージフックするための仕組みが内部で作成されることになります。項目の説明文を表示する際に利用します。コンテナに項目の説明文を表示する機会を与えます。コンテナはこのメソッド内で、スタータスバーに説明文を表示したりすることができます。オブジェクトはRemoveMenusを呼び出します。コンテナはこのメソッド内で、共有メニューに追加された項目を削除します。S_OK;}項目の数はGetMenuItemCountで取得できるため、この数だけRemoveMenuを呼び出せばよいことになります。