1 // in_place_menu.h : menu merging implementation
3 // This file is a modified version of the menu.h file, which is
4 // part of the ActiveDoc MSDN sample. The modifications are largely
5 // conversions to Google coding guidelines. Below is the original header
8 // This is a part of the Active Template Library.
9 // Copyright (c) Microsoft Corporation. All rights reserved.
11 // This source code is only intended as a supplement to the
12 // Active Template Library Reference and related
13 // electronic documentation provided with the library.
14 // See these sources for detailed information regarding the
15 // Active Template Library product.
17 #ifndef CHROME_FRAME_IN_PLACE_MENU_H_
18 #define CHROME_FRAME_IN_PLACE_MENU_H_
20 #include "base/logging.h"
21 #include "base/win/scoped_comptr.h"
26 InPlaceMenu() : shared_menu_(NULL
), ole_menu_(NULL
), our_menu_(NULL
) {
33 HRESULT
InPlaceMenuCreate(LPCWSTR menu_name
) {
34 // We might already have an in-place menu set, because we set menus
35 // IOleDocumentView::UIActivate as well as in
36 // IOleInPlaceActiveObject::OnDocWindowActivate. If we have already
37 // done our work, just return silently
38 if (ole_menu_
|| shared_menu_
)
41 base::win::ScopedComPtr
<IOleInPlaceFrame
> in_place_frame
;
42 GetInPlaceFrame(in_place_frame
.Receive());
43 // We have no IOleInPlaceFrame, no menu merging possible
44 if (!in_place_frame
) {
48 // Create a blank menu and ask the container to add
49 // its menus into the OLEMENUGROUPWIDTHS structure
50 shared_menu_
= ::CreateMenu();
51 OLEMENUGROUPWIDTHS mgw
= {0};
52 HRESULT hr
= in_place_frame
->InsertMenus(shared_menu_
, &mgw
);
54 ::DestroyMenu(shared_menu_
);
59 our_menu_
= LoadMenu(_AtlBaseModule
.GetResourceInstance(),menu_name
);
60 MergeMenus(shared_menu_
, our_menu_
, &mgw
.width
[0], 1);
61 // Send the menu to the client
62 ole_menu_
= (HMENU
)OleCreateMenuDescriptor(shared_menu_
, &mgw
);
63 T
* t
= static_cast<T
*>(this);
64 in_place_frame
->SetMenu(shared_menu_
, ole_menu_
, t
->m_hWnd
);
68 HRESULT
InPlaceMenuDestroy() {
69 base::win::ScopedComPtr
<IOleInPlaceFrame
> in_place_frame
;
70 GetInPlaceFrame(in_place_frame
.Receive());
72 in_place_frame
->RemoveMenus(shared_menu_
);
73 in_place_frame
->SetMenu(NULL
, NULL
, NULL
);
76 OleDestroyMenuDescriptor(ole_menu_
);
80 UnmergeMenus(shared_menu_
, our_menu_
);
81 DestroyMenu(shared_menu_
);
85 DestroyMenu(our_menu_
);
91 void MergeMenus(HMENU shared_menu
, HMENU source_menu
, LONG
* menu_widths
,
92 unsigned int width_index
) {
93 // Copy the popups from the source menu
94 // Insert at appropriate spot depending on width_index
95 DCHECK(width_index
== 0 || width_index
== 1);
98 position
= (int)menu_widths
[0];
100 int menu_items
= GetMenuItemCount(source_menu
);
101 for (int index
= 0; index
< menu_items
; index
++) {
102 // Get the HMENU of the popup
103 HMENU popup_menu
= ::GetSubMenu(source_menu
, index
);
104 // Separators move us to next group
105 UINT state
= GetMenuState(source_menu
, index
, MF_BYPOSITION
);
106 if (!popup_menu
&& (state
& MF_SEPARATOR
)) {
107 // Servers should not touch past 5
108 DCHECK(width_index
<= 5);
109 menu_widths
[width_index
] = group_width
;
112 position
+= static_cast<int>(menu_widths
[width_index
+1]);
115 // Get the menu item text
116 TCHAR item_text
[256] = {0};
117 int text_length
= GetMenuString(source_menu
, index
, item_text
,
118 ARRAYSIZE(item_text
), MF_BYPOSITION
);
119 // Popups are handled differently than normal menu items
121 if (::GetMenuItemCount(popup_menu
) != 0) {
122 // Strip the HIBYTE because it contains a count of items
123 state
= LOBYTE(state
) | MF_POPUP
; // Must be popup
124 // Non-empty popup -- add it to the shared menu bar
125 InsertMenu(shared_menu
, position
, state
|MF_BYPOSITION
,
126 reinterpret_cast<UINT_PTR
>(popup_menu
), item_text
);
130 } else if (text_length
> 0) {
131 // only non-empty items are added
132 DCHECK(item_text
[0] != 0);
133 // here the state does not contain a count in the HIBYTE
134 InsertMenu(shared_menu
, position
, state
|MF_BYPOSITION
,
135 GetMenuItemID(source_menu
, index
), item_text
);
143 void UnmergeMenus(HMENU shared_menu
, HMENU source_menu
) {
144 int our_item_count
= GetMenuItemCount(source_menu
);
145 int shared_item_count
= GetMenuItemCount(shared_menu
);
147 for (int index
= shared_item_count
- 1; index
>= 0; index
--) {
148 // Check the popup menus
149 HMENU popup_menu
= ::GetSubMenu(shared_menu
, index
);
151 // If it is one of ours, remove it from the shared menu
152 for (int sub_index
= 0; sub_index
< our_item_count
; sub_index
++) {
153 if (::GetSubMenu(source_menu
, sub_index
) == popup_menu
) {
154 // Remove the menu from hMenuShared
155 RemoveMenu(shared_menu
, index
, MF_BYPOSITION
);
164 HRESULT
GetInPlaceFrame(IOleInPlaceFrame
** in_place_frame
) {
165 if (!in_place_frame
) {
169 T
* t
= static_cast<T
*>(this);
171 if (S_OK
!= t
->GetInPlaceFrame(in_place_frame
)) {
172 // We weren't given an IOleInPlaceFrame pointer, so
173 // we'll have to get it ourselves.
174 if (t
->m_spInPlaceSite
) {
175 t
->frame_info_
.cb
= sizeof(OLEINPLACEFRAMEINFO
);
176 base::win::ScopedComPtr
<IOleInPlaceUIWindow
> in_place_ui_window
;
177 RECT position_rect
= {0};
178 RECT clip_rect
= {0};
179 hr
= t
->m_spInPlaceSite
->GetWindowContext(in_place_frame
,
180 in_place_ui_window
.Receive(),
181 &position_rect
, &clip_rect
,
189 // The OLE menu descriptor created by the OleCreateMenuDescriptor
191 // The shared menu that we pass to IOleInPlaceFrame::SetMenu
193 // Our menu resource that we want to insert
197 #endif // CHROME_FRAME_IN_PLACE_MENU_H_