* Take "DbgPrint" function from explorer-new.
* CMenuBand: Show placeholder if the band gets an empty IShellFolder. Added what I guess is a hack, to allow CMenuDeskBar to get the submenu popup from the band.
* CMenuDeskBar: Use WM_ACTIVATE and WM_ACTIVATEAPP to detect when the menu should be closed. Uses the hack above for the exception of showing a submenu.
CORE-7886

svn path=/branches/shell-experiments/; revision=62295
This commit is contained in:
David Quintana 2014-02-22 22:59:28 +00:00
parent ddb3d908c9
commit 905ab8ebba
3 changed files with 261 additions and 126 deletions

View file

@ -332,6 +332,11 @@ private:
}
private:
CMenuBand * m_currentBand;
HWND m_currentFocus;
HHOOK m_hHook;
DWORD m_threadId;
// TODO: make dynamic
#define MAX_RECURSE 20
CMenuBand* m_bandStack[MAX_RECURSE];
@ -399,23 +404,16 @@ public:
BEGIN_COM_MAP(CMenuFocusManager)
END_COM_MAP()
private:
CMenuBand * m_currentBand;
HWND m_currentFocus;
HHOOK m_hHook;
DWORD m_threadId;
LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(m_hHook, nCode, wParam, lParam);
BOOL callNext = TRUE;
BOOL fRemoved = wParam;
MSG* msg = reinterpret_cast<MSG*>(lParam);
if (nCode == HC_ACTION)
{
BOOL callNext = TRUE;
MSG* msg = reinterpret_cast<MSG*>(lParam);
// Do whatever is necessary here
switch (msg->message)
@ -452,9 +450,6 @@ private:
// PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam);
//}
break;
case WM_ACTIVATE:
break;
}
if (!callNext)
@ -481,24 +476,26 @@ private:
HRESULT UpdateFocus(CMenuBand * newBand)
{
HRESULT hr;
HWND newFocus;
hr = RemoveHooks(m_currentFocus);
if (FAILED(hr) || !newBand)
if (newBand == NULL)
{
hr = RemoveHooks(m_currentFocus);
m_currentFocus = NULL;
m_currentBand = NULL;
return S_OK;
}
HWND newFocus;
hr = newBand->_GetTopLevelWindow(&newFocus);
if (FAILED(hr))
return hr;
hr = PlaceHooks(m_currentFocus);
if (FAILED(hr))
return hr;
if (!m_currentBand)
{
hr = PlaceHooks(newFocus);
if (FAILED(hr))
return hr;
}
m_currentFocus = newFocus;
m_currentBand = newBand;
@ -1147,6 +1144,22 @@ HRESULT CMenuSFToolbar::FillToolbar()
}
CoTaskMemFree(item);
// If no items were added, show the "empty" placeholder
if (i == 0)
{
TBBUTTON tbb = { 0 };
PWSTR MenuString = L"(Empty)";
tbb.fsState = 0/*TBSTATE_DISABLED*/;
tbb.fsStyle = 0;
tbb.iString = (INT_PTR) MenuString;
tbb.iBitmap = -1;
SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
return S_OK;
}
return hr;
}
@ -1829,7 +1842,15 @@ HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
{
UNIMPLEMENTED;
// HACK, so I can test for a submenu in the DeskBar
//UNIMPLEMENTED;
if (ppunkClient)
{
if (m_subMenuChild)
*ppunkClient = m_subMenuChild;
else
*ppunkClient = NULL;
}
return S_OK;
}
@ -2209,7 +2230,6 @@ HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
return S_OK;
}
HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude)
{
if (m_subMenuChild)

View file

@ -56,6 +56,8 @@ private:
INT m_Level;
BOOL m_Shown;
public:
CMenuDeskBar();
~CMenuDeskBar();
@ -68,8 +70,9 @@ public:
BEGIN_MSG_MAP(CMenuDeskBar)
MESSAGE_HANDLER(WM_SIZE, _OnSize)
MESSAGE_HANDLER(WM_NOTIFY, _OnNotify)
MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, _OnWindowPosChanged)
MESSAGE_HANDLER(WM_PAINT, _OnPaint)
MESSAGE_HANDLER(WM_ACTIVATE, _OnActivate)
MESSAGE_HANDLER(WM_ACTIVATEAPP, _OnAppActivate)
END_MSG_MAP()
BEGIN_COM_MAP(CMenuDeskBar)
@ -131,9 +134,11 @@ private:
// message handlers
LRESULT _OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT _OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT _OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT _OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT _OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT _OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
BOOL _IsSubMenuParent(HWND hwnd);
HRESULT _CloseBar();
};
@ -160,7 +165,8 @@ INT deskBarCount=0;
CMenuDeskBar::CMenuDeskBar() :
m_Client(NULL),
m_Banner(NULL),
m_Level(deskBarCount++)
m_Level(deskBarCount++),
m_Shown(FALSE)
{
}
@ -169,6 +175,11 @@ CMenuDeskBar::~CMenuDeskBar()
deskBarCount--;
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetWindow(HWND *lphwnd)
{
if (lphwnd == NULL)
@ -320,6 +331,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnPosRectChangeDB(LPRECT prc)
{
if (prc == NULL)
return E_POINTER;
return S_OK;
}
@ -327,6 +339,9 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSite(IUnknown *pUnkSite)
{
// Windows closes the bar if this is called when the bar is shown
if (m_Shown)
_CloseBar();
m_Site = pUnkSite;
IUnknown_QueryService(m_Site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_SubMenuParent));
@ -342,88 +357,6 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetSite(REFIID riid, void **ppvSite)
return m_Site->QueryInterface(riid, ppvSite);
}
LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
if (m_Client)
{
RECT rc;
GetClientRect(&rc);
if (m_Banner != NULL)
{
BITMAP bm;
::GetObject(m_Banner, sizeof(bm), &bm);
rc.left += bm.bmWidth;
}
::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0);
}
return 0;
}
LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
CComPtr<IWinEventHandler> winEventHandler;
LRESULT result;
HRESULT hr;
result = 0;
if (m_Client.p != NULL)
{
hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
if (SUCCEEDED(hr) && winEventHandler.p != NULL)
hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result);
}
return result;
}
LRESULT CMenuDeskBar::_OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
return 0;
}
LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bHandled = FALSE;
if (m_Banner && !m_IconSize)
{
BITMAP bm;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
HDC hdcMem = ::CreateCompatibleDC(hdc);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner);
::GetObject(m_Banner, sizeof(bm), &bm);
RECT rc;
if (!GetClientRect(&rc))
WARN("GetClientRect failed\n");
const int bx = bm.bmWidth;
const int by = bm.bmHeight;
const int cy = rc.bottom;
TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight);
if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY))
WARN("StretchBlt failed\n");
if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY))
WARN("BitBlt failed\n");
::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem);
EndPaint(&ps);
}
return TRUE;
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
{
HRESULT hr;
@ -502,6 +435,8 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP
this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, SWP_SHOWWINDOW);
m_Shown = true;
// HACK: The bar needs to be notified of the size AFTER it is shown.
// Quick & dirty way of getting it done.
BOOL bHandled;
@ -509,6 +444,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP
UIActivateIO(TRUE, NULL);
return S_OK;
}
@ -555,8 +491,28 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetBitmap(THIS_ HBITMAP* phBitmap)
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(
DWORD dwSelectType)
HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
{
// Called by the MenuBand to assign itself as the logical child of the DeskBar
if (fSet)
{
m_SubMenuChild = pmp;
}
else
{
if (m_SubMenuChild)
{
if (SHIsSameObject(pmp, m_SubMenuChild))
{
m_SubMenuChild = NULL;
}
}
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType)
{
/* As far as I can tell, the submenu hierarchy looks like this:
@ -604,6 +560,8 @@ HRESULT CMenuDeskBar::_CloseBar()
CComPtr<IDeskBarClient> dbc;
HRESULT hr;
m_Shown = false;
if (m_SubMenuChild)
{
hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL);
@ -624,29 +582,150 @@ HRESULT CMenuDeskBar::_CloseBar()
return UIActivateIO(FALSE, NULL);
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
BOOL CMenuDeskBar::_IsSubMenuParent(HWND hwnd)
{
// Called by the CHILD to notify the parent of the submenu object
CComPtr<IMenuPopup> popup = m_SubMenuParent;
if (fSet)
while (popup)
{
m_SubMenuChild = pmp;
HRESULT hr;
CComPtr<IOleWindow> window;
hr = popup->QueryInterface(IID_PPV_ARG(IOleWindow, &window));
if (FAILED(hr))
return FALSE;
HWND parent;
hr = window->GetWindow(&parent);
if (SUCCEEDED(hr) && hwnd == parent)
return TRUE;
popup = NULL;
hr = IUnknown_GetSite(window, IID_PPV_ARG(IMenuPopup, &popup));
if (FAILED(hr))
return FALSE;
}
else
return FALSE;
}
LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
if (m_Client)
{
if (m_SubMenuChild)
RECT rc;
GetClientRect(&rc);
if (m_Banner != NULL)
{
if (SHIsSameObject(pmp, m_SubMenuChild))
{
m_SubMenuChild = NULL;
}
BITMAP bm;
::GetObject(m_Banner, sizeof(bm), &bm);
rc.left += bm.bmWidth;
}
::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0);
}
return 0;
}
LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
if (!m_Client)
return 0;
CComPtr<IWinEventHandler> winEventHandler;
HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
if (FAILED(hr))
return 0;
if (winEventHandler)
{
LRESULT result;
hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result);
if (FAILED(hr))
return 0;
return result;
}
return 0;
}
LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bHandled = FALSE;
if (m_Banner && !m_IconSize)
{
BITMAP bm;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
HDC hdcMem = ::CreateCompatibleDC(hdc);
HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner);
::GetObject(m_Banner, sizeof(bm), &bm);
RECT rc;
if (!GetClientRect(&rc))
WARN("GetClientRect failed\n");
const int bx = bm.bmWidth;
const int by = bm.bmHeight;
const int cy = rc.bottom;
TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight);
if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY))
WARN("StretchBlt failed\n");
if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY))
WARN("BitBlt failed\n");
::SelectObject(hdcMem, hbmOld);
::DeleteDC(hdcMem);
EndPaint(&ps);
}
return TRUE;
}
LRESULT CMenuDeskBar::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
if (wParam != 0)
return 0;
// HACK! I just want it to work !!!
CComPtr<IDeskBar> db;
HRESULT hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db));
if (FAILED(hr))
return 0;
CComPtr<IUnknown> punk;
hr = db->GetClient(&punk);
if (FAILED(hr))
return 0;
if (!punk && m_Shown)
{
if (!_IsSubMenuParent(reinterpret_cast<HWND>(lParam)))
{
OnSelect(MPOS_FULLCANCEL);
}
}
return S_OK;
return 0;
}
HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS)
LRESULT CMenuDeskBar::_OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
return S_OK;
if (wParam == 0)
{
OnSelect(MPOS_FULLCANCEL);
}
return 0;
}

View file

@ -3,9 +3,9 @@
#define USE_SYSTEM_MENUSITE 0
#define USE_SYSTEM_MENUBAND 0
#define WRAP_MENUDESKBAR 1
#define WRAP_MENUSITE 1
#define WRAP_MENUBAND 1
#define WRAP_MENUDESKBAR 0
#define WRAP_MENUSITE 0
#define WRAP_MENUBAND 0
#include <stdio.h>
#include <tchar.h>
@ -44,3 +44,39 @@ extern "C" HRESULT CMenuBand_Constructor(REFIID riid, LPVOID *ppv);
extern "C" HRESULT CMenuDeskBar_Wrapper(IDeskBar * db, REFIID riid, LPVOID *ppv);
extern "C" HRESULT CMenuSite_Wrapper(IBandSite * bs, REFIID riid, LPVOID *ppv);
extern "C" HRESULT CMenuBand_Wrapper(IShellMenu * sm, REFIID riid, LPVOID *ppv);
static __inline ULONG
Win32DbgPrint(const char *filename, int line, const char *lpFormat, ...)
{
char szMsg[512];
char *szMsgStart;
const char *fname;
va_list vl;
ULONG uRet;
fname = strrchr(filename, '\\');
if (fname == NULL)
{
fname = strrchr(filename, '/');
if (fname != NULL)
fname++;
}
else
fname++;
if (fname == NULL)
fname = filename;
szMsgStart = szMsg + sprintf(szMsg, "%s:%d: ", fname, line);
va_start(vl, lpFormat);
uRet = (ULONG) vsprintf(szMsgStart, lpFormat, vl);
va_end(vl);
OutputDebugStringA(szMsg);
return uRet;
}
#define DbgPrint(fmt, ...) \
Win32DbgPrint(__FILE__, __LINE__, fmt, ##__VA_ARGS__)