From 2dc83755793eb5e6848658e698c9a6c9aa3f05f8 Mon Sep 17 00:00:00 2001 From: David Quintana Date: Wed, 12 Feb 2014 16:35:29 +0000 Subject: [PATCH] [RSHELL] * Implement CMenuSite CORE-7879 svn path=/branches/shell-experiments/; revision=62131 --- base/shell/rshell/CMakeLists.txt | 1 + base/shell/rshell/CMenuSite.cpp | 498 +++++++++++++++++++++++++++++++ base/shell/rshell/CStartMenu.cpp | 2 +- base/shell/rshell/precomp.h | 2 + 4 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 base/shell/rshell/CMenuSite.cpp diff --git a/base/shell/rshell/CMakeLists.txt b/base/shell/rshell/CMakeLists.txt index 5a9957708fe..bcc811bcb75 100644 --- a/base/shell/rshell/CMakeLists.txt +++ b/base/shell/rshell/CMakeLists.txt @@ -9,6 +9,7 @@ spec2def(rshell.dll rshell.spec ADD_IMPORTLIB) list(APPEND SOURCE CDesktopBrowser.cpp CStartMenu.cpp + CMenuSite.cpp misc.cpp ${CMAKE_CURRENT_BINARY_DIR}/rshell.def) diff --git a/base/shell/rshell/CMenuSite.cpp b/base/shell/rshell/CMenuSite.cpp new file mode 100644 index 00000000000..38a03bd84d1 --- /dev/null +++ b/base/shell/rshell/CMenuSite.cpp @@ -0,0 +1,498 @@ +/* + * Shell Menu Site + * + * Copyright 2014 David Quintana + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "precomp.h" +#include +#include + +WINE_DEFAULT_DEBUG_CHANNEL(menusite); + +bool _assert(bool cond, LPCSTR expr, LPCSTR file, DWORD line, LPCSTR func) +{ +#if DBG + if (!cond) + { + wine_dbg_printf("%s(%d): Assertion failed '%s', at %s", file, line, expr, func); + DebugBreak(); + } +#endif + return cond; +} +#define DBGASSERT(x) _assert(!!(x), #x, __FILE__, __LINE__, __FUNCSIG__) + +class CMenuSite : + public CComObjectRootEx, + public CWindowImpl, + public IBandSite, + public IDeskBarClient, + public IOleCommandTarget, + public IInputObject, + public IInputObjectSite, + public IWinEventHandler, + public IServiceProvider +{ + IUnknown * m_DeskBarSite; + IUnknown * m_BandObject; + IDeskBand * m_DeskBand; + IWinEventHandler * m_WinEventHandler; + HWND m_hWndBand; + +public: + CMenuSite(); + ~CMenuSite() {} + + DECLARE_WND_CLASS_EX(_T("MenuSite"), 0, COLOR_WINDOW) + + DECLARE_NOT_AGGREGATABLE(CMenuSite) + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(CMenuSite) + COM_INTERFACE_ENTRY_IID(IID_IBandSite, IBandSite) + COM_INTERFACE_ENTRY_IID(IID_IDeskBarClient, IDeskBarClient) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) + COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) + COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) + END_COM_MAP() + + virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); + virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); + virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus); + virtual HRESULT STDMETHODCALLTYPE AddBand(IUnknown * punk); + virtual HRESULT STDMETHODCALLTYPE EnumBands(UINT uBand, DWORD* pdwBandID); + virtual HRESULT STDMETHODCALLTYPE Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); + virtual HRESULT STDMETHODCALLTYPE GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv); + virtual HRESULT STDMETHODCALLTYPE GetSize(DWORD dwWhich, LPRECT prc); + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd); + virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT STDMETHODCALLTYPE QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName); + virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); + virtual HRESULT STDMETHODCALLTYPE SetDeskBarSite(IUnknown *punkSite); + virtual HRESULT STDMETHODCALLTYPE UIActivateDBC(DWORD dwState); + virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); + + // Using custom message map instead + virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId = 0); + + // UNIMPLEMENTED + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(BANDSITEINFO *pbsinfo); + virtual HRESULT STDMETHODCALLTYPE RemoveBand(DWORD dwBandID); + virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(const BANDSITEINFO *pbsinfo); + virtual HRESULT STDMETHODCALLTYPE SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState); + virtual HRESULT STDMETHODCALLTYPE SetModeDBC(DWORD dwMode); + +private: + BOOL CreateSiteWindow(HWND hWndParent); +}; + +extern "C" +HRESULT CMenuSite_Constructor(REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + + CMenuSite * site = new CComObject(); + + if (!site) + return E_OUTOFMEMORY; + + HRESULT hr = site->QueryInterface(riid, ppv); + + if (FAILED(hr)) + site->Release(); + + return hr; +} + +CMenuSite::CMenuSite() : + m_DeskBarSite(NULL), + m_BandObject(NULL), + m_DeskBand(NULL), + m_WinEventHandler(NULL), + m_hWndBand(NULL) +{ +} + +HRESULT STDMETHODCALLTYPE CMenuSite::ContextSensitiveHelp(BOOL fEnterMode) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::GetBandSiteInfo(BANDSITEINFO *pbsinfo) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::RemoveBand(DWORD dwBandID) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::SetBandSiteInfo(const BANDSITEINFO *pbsinfo) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::SetModeDBC(DWORD dwMode) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::TranslateAcceleratorIO(LPMSG lpMsg) +{ + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::HasFocusIO() +{ + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::AddBand(IUnknown * punk) +{ + if (SHIsSameObject(punk, m_BandObject)) + return S_OK + 0; + + IUnknown_SetSite(m_BandObject, NULL); + + if (m_BandObject) + { + m_BandObject->Release(); + m_BandObject = NULL; + } + + if (m_DeskBand) + { + m_DeskBand->Release(); + m_DeskBand = NULL; + } + + if (m_WinEventHandler) + { + m_WinEventHandler->Release(); + m_WinEventHandler = NULL; + } + + BOOL result = m_hWndBand != NULL; + + m_hWndBand = NULL; + + if (!punk) + return result ? S_OK + 0 : E_FAIL; + + DBGASSERT(SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IDeskBand, &m_DeskBand)))); + DBGASSERT(SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IWinEventHandler, &m_WinEventHandler)))); + + IUnknown_SetSite(punk, (IDeskBarClient*)this); + IUnknown_GetWindow(punk, &m_hWndBand); + + m_BandObject = punk; + + punk->AddRef(); + + return S_OK + 0; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::EnumBands(UINT uBand, DWORD* pdwBandID) +{ + if (uBand != 0) + return E_FAIL; + + *pdwBandID = 0; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + return IUnknown_Exec(m_DeskBarSite, *pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv) +{ + if (!DBGASSERT(dwBandID == 0) || m_BandObject == NULL) + { + *ppv = NULL; + return E_NOINTERFACE; + } + + return m_BandObject->QueryInterface(riid, ppv); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::GetSize(DWORD dwWhich, LPRECT prc) +{ + memset(prc, 0, sizeof(*prc)); + + if (dwWhich != 0) + return S_OK; + + if (m_DeskBand == NULL) + return S_OK; + + DESKBANDINFO info = { 0 }; + + m_DeskBand->GetBandInfo(0, 0, &info); + + prc->right = info.ptMaxSize.x; + prc->bottom = info.ptMaxSize.y; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::GetWindow(HWND *phwnd) +{ + DBGASSERT(IsWindow()); + + *phwnd = m_hWnd; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::IsWindowOwner(HWND hWnd) +{ + if (hWnd == m_hWnd) + return S_OK; + + if (!m_WinEventHandler) + return S_FALSE; + + return m_WinEventHandler->IsWindowOwner(hWnd); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ + if (!m_WinEventHandler) + return S_OK; + + return m_WinEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName) +{ + DBGASSERT(dwBandID == 0); + DBGASSERT(!IsBadWritePtr(ppstb, sizeof(*ppstb))); + + if (!m_BandObject) + { + *ppstb = NULL; + return E_NOINTERFACE; + } + + HRESULT hr = m_BandObject->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb)); + + *pdwState = 1; + + if (cchName > 0) + pszName[0] = 0; + + return hr; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) +{ + *ppvObject = NULL; + + if (IsEqualGUID(guidService, SID_SMenuBandBottom) || + IsEqualGUID(guidService, SID_SMenuBandBottomSelected) || + IsEqualGUID(guidService, SID_SMenuBandChild)) + { + if (m_BandObject == NULL) + return E_FAIL; + + return IUnknown_QueryService(m_BandObject, guidService, riid, ppvObject); + } + + DBGASSERT(m_DeskBarSite); + + return IUnknown_QueryService(m_DeskBarSite, guidService, riid, ppvObject); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText) +{ + if (!DBGASSERT(m_DeskBarSite)) + return E_FAIL; + return IUnknown_QueryStatus(m_DeskBarSite, *pguidCmdGroup, cCmds, prgCmds, pCmdText); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::SetDeskBarSite(IUnknown *punkSite) +{ + HWND hWndSite; + + ((IDeskBarClient*)this)->AddRef(); + + if (punkSite) + { + if (m_DeskBarSite) + { + m_DeskBarSite->Release(); + m_DeskBarSite = NULL; + } + + IUnknown_GetWindow(punkSite, &hWndSite); + + if (hWndSite) + { + CreateSiteWindow(hWndSite); + + m_DeskBarSite = punkSite; + + punkSite->AddRef(); + } + } + else + { + if (m_DeskBand) + { + m_DeskBand->CloseDW(0); + } + + IUnknown_SetSite(m_BandObject, NULL); + + if (m_BandObject) + { + m_BandObject->Release(); + m_BandObject = NULL; + } + + if (m_DeskBand) + { + m_DeskBand->Release(); + m_DeskBand = NULL; + } + + if (m_WinEventHandler) + { + m_WinEventHandler->Release(); + m_WinEventHandler = NULL; + } + + m_hWndBand = NULL; + + if (m_hWnd) + { + DestroyWindow(); + m_hWnd = NULL; + } + + if (m_DeskBarSite) + m_DeskBarSite->Release(); + + m_DeskBarSite = NULL; + } + + ((IDeskBarClient*)this)->Release(); + + if (!m_hWnd) + return E_FAIL; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CMenuSite::UIActivateDBC(DWORD dwState) +{ + if (!DBGASSERT(m_DeskBand)) + return S_OK; + + return m_DeskBand->ShowDW(dwState != 0); +} + +HRESULT STDMETHODCALLTYPE CMenuSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg) +{ + if (lpMsg && DBGASSERT(IsBadWritePtr(lpMsg, sizeof(*lpMsg)))) + return E_FAIL; + + return IUnknown_UIActivateIO(m_BandObject, fActivate, lpMsg); +} + +BOOL CMenuSite::CreateSiteWindow(HWND hWndParent) +{ + if (m_hWnd) + { + return DBGASSERT(IsWindow()); + } + + Create(hWndParent, NULL, L"MenuSite"); + + return m_hWnd != NULL; +} + +BOOL CMenuSite::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId) +{ + HWND hWndToCall; + IMenuPopup * pMenuPopup; + + ((IDeskBarClient*)this)->AddRef(); + + switch (uMsg) + { + case WM_SIZE: + if (m_BandObject) + { + if (SUCCEEDED(m_BandObject->QueryInterface(IID_PPV_ARG(IMenuPopup, &pMenuPopup)))) + { + RECT Rect = { 0 }; + GetClientRect(&Rect); + pMenuPopup->OnPosRectChangeDB(&Rect); + pMenuPopup->Release(); + } + } + hWndToCall = hWnd; + lResult = 1; + break; + case WM_NOTIFY: + hWndToCall = *(HWND *) lParam; + break; + case WM_COMMAND: + hWndToCall = (HWND) lParam; + break; + default: + ((IDeskBarClient*)this)->Release(); + return FALSE; + } + + if (hWndToCall) + { + if (m_WinEventHandler) + { + if (m_WinEventHandler->IsWindowOwner(hWndToCall) == S_OK) + { + HRESULT hr = m_WinEventHandler->OnWinEvent(hWndToCall, uMsg, wParam, lParam, &lResult); + ((IDeskBarClient*)this)->Release(); + return hr == S_OK; + } + } + } + + ((IDeskBarClient*)this)->Release(); + return FALSE; +} diff --git a/base/shell/rshell/CStartMenu.cpp b/base/shell/rshell/CStartMenu.cpp index 54a461889af..542c90a1a8a 100644 --- a/base/shell/rshell/CStartMenu.cpp +++ b/base/shell/rshell/CStartMenu.cpp @@ -266,7 +266,7 @@ CStartMenu_Constructor( if (FAILED(hr)) return NULL; -#if 1 +#if 0 hr = CoCreateInstance(CLSID_MenuBandSite, NULL, CLSCTX_INPROC_SERVER, diff --git a/base/shell/rshell/precomp.h b/base/shell/rshell/precomp.h index 56b466cc96f..0e54216d8a5 100644 --- a/base/shell/rshell/precomp.h +++ b/base/shell/rshell/precomp.h @@ -29,3 +29,5 @@ #define shell32_hInstance 0 #define SMC_EXEC 4 extern "C" INT WINAPI Shell_GetCachedImageIndex(LPCWSTR szPath, INT nIndex, UINT bSimulateDoc); + +extern "C" HRESULT CMenuSite_Constructor(REFIID riid, LPVOID *ppv); \ No newline at end of file