Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
12 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "menusite.h"
  4. CMenuSite::CMenuSite() : _cRef(1)
  5. {
  6. }
  7. CMenuSite::~CMenuSite()
  8. {
  9. // Make sure that SetDeskBarSite(NULL) was called
  10. ASSERT(_punkSite == NULL);
  11. ASSERT(_punkSubActive == NULL);
  12. ASSERT(_pweh == NULL);
  13. ASSERT(_pdb == NULL);
  14. ASSERT(_hwnd == NULL);
  15. }
  16. STDAPI CMenuBandSite_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  17. {
  18. CMenuSite *pbs = new CMenuSite();
  19. if (pbs)
  20. {
  21. *ppunk = SAFECAST(pbs, IOleWindow*);
  22. return S_OK;
  23. }
  24. *ppunk = NULL;
  25. return E_OUTOFMEMORY;
  26. }
  27. /*----------------------------------------------------------
  28. Purpose: IUnknown::QueryInterface method
  29. */
  30. STDMETHODIMP CMenuSite::QueryInterface(REFIID riid, LPVOID * ppvObj)
  31. {
  32. static const QITAB qit[] = {
  33. QITABENT(CMenuSite, IBandSite),
  34. QITABENT(CMenuSite, IDeskBarClient),
  35. QITABENT(CMenuSite, IOleCommandTarget),
  36. QITABENT(CMenuSite, IInputObject),
  37. QITABENT(CMenuSite, IInputObjectSite),
  38. QITABENT(CMenuSite, IWinEventHandler),
  39. QITABENT(CMenuSite, IServiceProvider),
  40. QITABENT(CMenuSite, IOleWindow),
  41. { 0 },
  42. };
  43. return QISearch(this, qit, riid, ppvObj);
  44. }
  45. /*----------------------------------------------------------
  46. Purpose: IUnknown::AddRef method
  47. */
  48. STDMETHODIMP_(ULONG) CMenuSite::AddRef(void)
  49. {
  50. _cRef++;
  51. return _cRef;
  52. }
  53. /*----------------------------------------------------------
  54. Purpose: IUnknown::Release method
  55. */
  56. STDMETHODIMP_(ULONG) CMenuSite::Release()
  57. {
  58. ASSERT(_cRef > 0);
  59. _cRef--;
  60. if (_cRef > 0)
  61. return _cRef;
  62. delete this;
  63. return 0;
  64. }
  65. /*----------------------------------------------------------
  66. Purpose: IServiceProvider::QueryService method
  67. */
  68. STDMETHODIMP CMenuSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  69. {
  70. HRESULT hres = E_FAIL;
  71. *ppvObj = NULL; // assume error
  72. if (IsEqualIID(guidService, SID_SMenuBandBottom) ||
  73. IsEqualIID(guidService, SID_SMenuBandBottomSelected)||
  74. IsEqualIID(guidService, SID_SMenuBandChild))
  75. {
  76. if (_punkSubActive)
  77. hres = IUnknown_QueryService(_punkSubActive, guidService, riid, ppvObj);
  78. }
  79. else
  80. {
  81. ASSERT(_punkSite);
  82. hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
  83. }
  84. return hres;
  85. }
  86. /*----------------------------------------------------------
  87. Purpose: IOleCommandTarget::QueryStatus
  88. */
  89. STDMETHODIMP CMenuSite::QueryStatus(const GUID *pguidCmdGroup,
  90. ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  91. {
  92. ASSERT(_punkSite);
  93. return IUnknown_QueryStatus(_punkSite, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  94. }
  95. /*----------------------------------------------------------
  96. Purpose: IOleCommandTarget::Exec
  97. */
  98. STDMETHODIMP CMenuSite::Exec(const GUID *pguidCmdGroup,
  99. DWORD nCmdID, DWORD nCmdexecopt,
  100. VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  101. {
  102. ASSERT(_punkSite);
  103. return IUnknown_Exec(_punkSite, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  104. }
  105. /*----------------------------------------------------------
  106. Purpose: IInputObjectSite::OnFocusChangeIS
  107. This function is called by the client band to negotiate
  108. which band in this bandsite gets the focus. Typically
  109. this function will then change its focus to the given
  110. client band.
  111. CMenuSite only maintains one and only one band, which
  112. is set at AddBand time, so this function is a nop.
  113. */
  114. STDMETHODIMP CMenuSite::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
  115. {
  116. // Return S_OK since the menu site only ever has one band.
  117. // No need to negotiate which other band in this bandsite
  118. // might have the "activation".
  119. return S_OK;
  120. }
  121. /*----------------------------------------------------------
  122. Purpose: IInputObject::UIActivateIO method
  123. */
  124. STDMETHODIMP CMenuSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
  125. {
  126. ASSERT(NULL == lpMsg || IS_VALID_WRITE_PTR(lpMsg, MSG));
  127. // Forward onto the client band
  128. return IUnknown_UIActivateIO(_punkSubActive, fActivate, lpMsg);
  129. }
  130. /*----------------------------------------------------------
  131. Purpose: IInputObject::HasFocusIO
  132. Since the menuband can never have true activation (from
  133. the browser's perspective) this always returns S_FALSE.
  134. See comments in CMenuBand::UIActivateIO for more details
  135. about this.
  136. */
  137. STDMETHODIMP CMenuSite::HasFocusIO()
  138. {
  139. return S_FALSE;
  140. }
  141. /*----------------------------------------------------------
  142. Purpose: IInputObject::TranslateAcceleratorIO
  143. Menubands cannot ever have the activation, so this method
  144. should never be called.
  145. */
  146. STDMETHODIMP CMenuSite::TranslateAcceleratorIO(LPMSG lpMsg)
  147. {
  148. AssertMsg(0, TEXT("Menuband has the activation but it shouldn't!"));
  149. return S_FALSE;
  150. }
  151. // Utility Functions
  152. void CMenuSite::_CacheSubActiveBand(IUnknown * punk)
  153. {
  154. if (SHIsSameObject(punk, _punkSubActive))
  155. return;
  156. IUnknown_SetSite(_punkSubActive, NULL);
  157. ATOMICRELEASE(_punkSubActive);
  158. ATOMICRELEASE(_pdb);
  159. ATOMICRELEASE(_pweh);
  160. _hwndChild = NULL;
  161. if (punk != NULL)
  162. {
  163. EVAL(SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IDeskBand, &_pdb))));
  164. EVAL(SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IWinEventHandler, &_pweh))));
  165. IUnknown_SetSite(punk, SAFECAST(this, IOleWindow*));
  166. IUnknown_GetWindow(punk, &_hwndChild);
  167. _punkSubActive = punk;
  168. _punkSubActive->AddRef();
  169. }
  170. }
  171. /*----------------------------------------------------------
  172. Purpose: IBandSite::AddBand
  173. */
  174. STDMETHODIMP CMenuSite::AddBand(IUnknown* punk)
  175. {
  176. _CacheSubActiveBand(punk);
  177. return NOERROR;
  178. }
  179. /*----------------------------------------------------------
  180. Purpose: IBandSite::EnumBands
  181. */
  182. STDMETHODIMP CMenuSite::EnumBands(UINT uBand, DWORD* pdwBandID)
  183. {
  184. HRESULT hres = NOERROR;
  185. // The menusite only holds one band ever
  186. if (0 == uBand)
  187. *pdwBandID = 0;
  188. else
  189. hres = E_FAIL;
  190. return hres;
  191. }
  192. /*----------------------------------------------------------
  193. Purpose: IBandSite::QueryBand
  194. */
  195. HRESULT CMenuSite::QueryBand(DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
  196. {
  197. HRESULT hres = E_NOINTERFACE;
  198. ASSERT(dwBandID == 0);
  199. ASSERT(IS_VALID_WRITE_PTR(ppstb, IDeskBand *));
  200. if (_punkSubActive && 0 == dwBandID)
  201. {
  202. hres = _punkSubActive->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
  203. *pdwState = BSSF_VISIBLE; // Only band....
  204. if (cchName > 0)
  205. *pszName = L'\0';
  206. }
  207. else
  208. *ppstb = NULL;
  209. return hres;
  210. }
  211. /*----------------------------------------------------------
  212. Purpose: IBandSite::SetBandState
  213. */
  214. HRESULT CMenuSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
  215. {
  216. return E_NOTIMPL;
  217. }
  218. /*----------------------------------------------------------
  219. Purpose: IBandSite::RemoveBand
  220. */
  221. HRESULT CMenuSite::RemoveBand(DWORD dwBandID)
  222. {
  223. return E_NOTIMPL;
  224. }
  225. /*----------------------------------------------------------
  226. Purpose: IBandSite::GetBandObject
  227. */
  228. HRESULT CMenuSite::GetBandObject(DWORD dwBandID, REFIID riid, LPVOID *ppvObj)
  229. {
  230. HRESULT hres;
  231. ASSERT(dwBandID == 0);
  232. if (_punkSubActive && 0 == dwBandID)
  233. hres = _punkSubActive->QueryInterface(riid, ppvObj);
  234. else
  235. {
  236. *ppvObj = NULL;
  237. hres = E_NOINTERFACE;
  238. }
  239. return hres;
  240. }
  241. /*----------------------------------------------------------
  242. Purpose: IBandSite::SetBandSiteInfo
  243. */
  244. HRESULT CMenuSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
  245. {
  246. return E_NOTIMPL;
  247. }
  248. /*----------------------------------------------------------
  249. Purpose: IBandSite::GetBandSiteInfo
  250. */
  251. HRESULT CMenuSite::GetBandSiteInfo(BANDSITEINFO * pbsinfo)
  252. {
  253. return E_NOTIMPL;
  254. }
  255. /*----------------------------------------------------------
  256. Purpose: IOleWindow::GetWindow
  257. */
  258. HRESULT CMenuSite::GetWindow(HWND * lphwnd)
  259. {
  260. ASSERT(IS_VALID_HANDLE(_hwnd, WND));
  261. *lphwnd = _hwnd;
  262. return NOERROR;
  263. }
  264. /*----------------------------------------------------------
  265. Purpose: IOleWindow::ContextSensitiveHelp
  266. */
  267. HRESULT CMenuSite::ContextSensitiveHelp(BOOL fEnterMode)
  268. {
  269. return E_NOTIMPL;
  270. }
  271. /*----------------------------------------------------------
  272. Purpose: IDeskBarClient::SetDeskBarSite
  273. */
  274. HRESULT CMenuSite::SetDeskBarSite(IUnknown* punkSite)
  275. {
  276. if (punkSite)
  277. {
  278. ATOMICRELEASE(_punkSite);
  279. HWND hwnd;
  280. IUnknown_GetWindow(punkSite, &hwnd);
  281. if (hwnd)
  282. {
  283. _CreateSite(hwnd);
  284. _punkSite = punkSite;
  285. _punkSite->AddRef();
  286. }
  287. }
  288. else
  289. {
  290. if (_pdb)
  291. {
  292. _pdb->CloseDW(0);
  293. }
  294. _CacheSubActiveBand(NULL); // This is asymetric by design
  295. if (_hwnd)
  296. {
  297. DestroyWindow(_hwnd);
  298. _hwnd = NULL;
  299. }
  300. ATOMICRELEASE(_punkSite);
  301. }
  302. return _hwnd ? NOERROR : E_FAIL;
  303. }
  304. /*----------------------------------------------------------
  305. Purpose: IDeskBarClient::SetModeDBC
  306. */
  307. HRESULT CMenuSite::SetModeDBC(DWORD dwMode)
  308. {
  309. return E_NOTIMPL;
  310. }
  311. /*----------------------------------------------------------
  312. Purpose: IDeskBarClient::UIActivateDBC
  313. */
  314. HRESULT CMenuSite::UIActivateDBC(DWORD dwState)
  315. {
  316. HRESULT hr = S_OK;
  317. ASSERT(_pdb);
  318. if (_pdb)
  319. hr = _pdb->ShowDW(0 != dwState);
  320. return hr;
  321. }
  322. /*----------------------------------------------------------
  323. Purpose: IDeskBarClient::GetSize
  324. */
  325. HRESULT CMenuSite::GetSize(DWORD dwWhich, LPRECT prc)
  326. {
  327. if (dwWhich == DBC_GS_IDEAL)
  328. {
  329. if (_pdb)
  330. {
  331. DESKBANDINFO dbi = {0};
  332. _pdb->GetBandInfo(0, 0, &dbi);
  333. prc->right = dbi.ptMaxSize.x;
  334. prc->bottom = dbi.ptMaxSize.y;
  335. }
  336. }
  337. return NOERROR;
  338. }
  339. /*----------------------------------------------------------
  340. Purpose: IWinEventHandler::OnWinEvent
  341. */
  342. HRESULT CMenuSite::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  343. {
  344. if (_pweh)
  345. return _pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  346. return NOERROR;
  347. }
  348. /*----------------------------------------------------------
  349. Purpose: IWinEventHandler::IsWindowOwner
  350. */
  351. HRESULT CMenuSite::IsWindowOwner(HWND hwnd)
  352. {
  353. if (_hwnd == hwnd || (_pweh && _pweh->IsWindowOwner(hwnd) != S_FALSE))
  354. return S_OK;
  355. else
  356. return S_FALSE;
  357. }
  358. LRESULT CMenuSite::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  359. {
  360. LRESULT lres = 0;
  361. EnterModeless();
  362. switch(uMsg)
  363. {
  364. case WM_SIZE:
  365. {
  366. IMenuPopup* pmp;
  367. if (_punkSubActive && SUCCEEDED(_punkSubActive->QueryInterface(IID_PPV_ARG(IMenuPopup, &pmp))))
  368. {
  369. RECT rc = {0};
  370. GetClientRect(_hwnd, &rc);
  371. pmp->OnPosRectChangeDB(&rc);
  372. pmp->Release();
  373. }
  374. lres = 1;
  375. }
  376. break;
  377. case WM_NOTIFY:
  378. hwnd = ((LPNMHDR)lParam)->hwndFrom;
  379. break;
  380. case WM_COMMAND:
  381. hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
  382. break;
  383. default:
  384. ExitModeless();
  385. return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
  386. break;
  387. }
  388. if (hwnd && _pweh && _pweh->IsWindowOwner(hwnd) == S_OK)
  389. {
  390. _pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, &lres);
  391. }
  392. ExitModeless();
  393. return lres;
  394. }
  395. void CMenuSite::_CreateSite(HWND hwndParent)
  396. {
  397. if (_hwnd)
  398. {
  399. ASSERT(IS_VALID_HANDLE(_hwnd, WND)); // just to be safe...
  400. return;
  401. }
  402. WNDCLASS wc = {0};
  403. wc.style = 0;
  404. wc.lpfnWndProc = s_WndProc;
  405. //wc.cbClsExtra = 0;
  406. wc.cbWndExtra = SIZEOF(CMenuSite*);
  407. wc.hInstance = HINST_THISDLL;
  408. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  409. wc.hbrBackground = (HBRUSH) (COLOR_MENU+1);
  410. //wc.lpszMenuName = NULL;
  411. wc.lpszClassName = TEXT("MenuSite");
  412. //wc.hIcon = NULL;
  413. SHRegisterClass(&wc);
  414. _hwnd = CreateWindow(TEXT("MenuSite"), NULL, WS_VISIBLE | WS_CHILD, 0, 0, 0, 0,
  415. hwndParent, NULL, HINST_THISDLL, (LPVOID)SAFECAST(this, CImpWndProc*));
  416. ASSERT(_hwnd);
  417. }