From 4da0e180ee496ab0a22178b48d530280dd51bd6a Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Tue, 23 Oct 2007 02:00:30 +0000 Subject: [PATCH] - add a member to shlview to able to track the current context menu - make the background menu use owner drawn items to show icon (icon not yet shown) - let the shell item menu also accept owner drawn images - this makes winrar shellextension appear however the language is _not_ correct in most cases and executing a command is at your own risk :) svn path=/trunk/; revision=29808 --- reactos/dll/win32/shell32/shlview.c | 50 +++++++++--- reactos/dll/win32/shell32/shv_bg_cmenu.c | 94 ++++++++++++++++++++-- reactos/dll/win32/shell32/shv_item_cmenu.c | 73 ++++++++++++++--- 3 files changed, 192 insertions(+), 25 deletions(-) diff --git a/reactos/dll/win32/shell32/shlview.c b/reactos/dll/win32/shell32/shlview.c index a22e33e93c5..5eabe90c3a5 100644 --- a/reactos/dll/win32/shell32/shlview.c +++ b/reactos/dll/win32/shell32/shlview.c @@ -109,6 +109,7 @@ typedef struct LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */ UINT cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */ POINT ptLastMousePos; /* Mouse position at last DragOver call */ + IContextMenu2 *pCM; } IShellViewImpl; static const IShellViewVtbl svvt; @@ -948,7 +949,6 @@ static void ShellView_DoContextMenu(IShellViewImpl * This, WORD x, WORD y, BOOL BOOL fExplore = FALSE; HWND hwndTree = 0; LPCONTEXTMENU pContextMenu = NULL; - IContextMenu2 *pCM = NULL; CMINVOKECOMMANDINFO cmi; TRACE("(%p)->(0x%08x 0x%08x 0x%08x) stub\n",This, x, y, bDefault); @@ -957,9 +957,9 @@ static void ShellView_DoContextMenu(IShellViewImpl * This, WORD x, WORD y, BOOL if( ShellView_GetSelections(This) ) { IShellFolder_GetUIObjectOf( This->pSFParent, This->hWndParent, This->cidl, (LPCITEMIDLIST*)This->apidl, - (REFIID)&IID_IContextMenu, NULL, (LPVOID *)&pContextMenu); + (REFIID)&IID_IContextMenu, NULL, (LPVOID *)&This->pCM); - if(pContextMenu) + if(This->pCM) { TRACE("-- pContextMenu\n"); hMenu = CreatePopupMenu(); @@ -977,7 +977,7 @@ static void ShellView_DoContextMenu(IShellViewImpl * This, WORD x, WORD y, BOOL wFlags = CMF_NORMAL | (This->cidl != 1 ? 0 : CMF_CANRENAME) | (fExplore ? CMF_EXPLORE : 0); /* let the ContextMenu merge its items in */ - if (SUCCEEDED(IContextMenu_QueryContextMenu( pContextMenu, hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, wFlags ))) + if (SUCCEEDED(IContextMenu_QueryContextMenu( This->pCM, hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, wFlags ))) { if (This->FolderSettings.fFlags & FWF_DESKTOP) SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND); @@ -1017,16 +1017,19 @@ static void ShellView_DoContextMenu(IShellViewImpl * This, WORD x, WORD y, BOOL DestroyMenu(hMenu); } } - if (pContextMenu) - IContextMenu_Release(pContextMenu); + if (This->pCM) + { + IContextMenu_Release(This->pCM); + This->pCM = NULL; + } } } else /* background context menu */ { hMenu = CreatePopupMenu(); - pCM = ISvBgCm_Constructor(This->pSFParent, FALSE); - IContextMenu2_QueryContextMenu(pCM, hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0); + This->pCM = ISvBgCm_Constructor(This->pSFParent, FALSE); + IContextMenu2_QueryContextMenu(This->pCM, hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0); uCommand = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,This->hWnd,NULL); DestroyMenu(hMenu); @@ -1037,9 +1040,10 @@ static void ShellView_DoContextMenu(IShellViewImpl * This, WORD x, WORD y, BOOL cmi.cbSize = sizeof(cmi); cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand); cmi.hwnd = This->hWndParent; - IContextMenu2_InvokeCommand(pCM, &cmi); + IContextMenu2_InvokeCommand(This->pCM, &cmi); - IContextMenu2_Release(pCM); + IContextMenu2_Release(This->pCM); + This->pCM = NULL; } } @@ -1582,6 +1586,26 @@ static LRESULT ShellView_OnChange(IShellViewImpl * This, LPITEMIDLIST * Pidls, L } return TRUE; } + +/********************************************************** +* ShellView_DoMeasureItem +*/ + +static LRESULT ShellView_DoCustomItem(IShellViewImpl * pThis, HWND hWnd, UINT uMsg, LPARAM lParam) +{ + if (!pThis->pCM) + { + /* no menu */ + ERR("no menu!!!\n"); + return FALSE; + } + + if (pThis->pCM->lpVtbl->HandleMenuMsg(pThis->pCM, uMsg, (WPARAM)hWnd, lParam) == S_OK) + return TRUE; + else + return FALSE; +} + /********************************************************** * ShellView_WndProc */ @@ -1616,6 +1640,9 @@ static LRESULT CALLBACK ShellView_WndProc(HWND hWnd, UINT uMessage, WPARAM wPara case WM_CONTEXTMENU: ShellView_DoContextMenu(pThis, LOWORD(lParam), HIWORD(lParam), FALSE); return 0; + case WM_DRAWITEM: + case WM_MEASUREITEM: + return ShellView_DoCustomItem(pThis, hWnd, uMessage, lParam); case WM_SHOWWINDOW: UpdateWindow(pThis->hWndList); break; @@ -1727,6 +1754,9 @@ static ULONG WINAPI IShellView_fnRelease(IShellView * iface) if(This->pAdvSink) IAdviseSink_Release(This->pAdvSink); + if (This->pCM) + IContextMenu_Release(This->pCM); + HeapFree(GetProcessHeap(),0,This); } return refCount; diff --git a/reactos/dll/win32/shell32/shv_bg_cmenu.c b/reactos/dll/win32/shell32/shv_bg_cmenu.c index e0202ef0000..4877b7946d7 100644 --- a/reactos/dll/win32/shell32/shv_bg_cmenu.c +++ b/reactos/dll/win32/shell32/shv_bg_cmenu.c @@ -23,7 +23,7 @@ #define COBJMACROS #define NONAMELESSUNION #define NONAMELESSSTRUCT -//#define YDEBUG +#define YDEBUG #include "wine/debug.h" #include "windef.h" @@ -36,6 +36,7 @@ #include "undocshell.h" #include "shlwapi.h" #include "stdio.h" +#include "winuser.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); @@ -277,7 +278,6 @@ InsertShellNewItems(HMENU hMenu, UINT idFirst, UINT idMenu, BgCmImpl * This) } - ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); @@ -298,8 +298,8 @@ InsertShellNewItems(HMENU hMenu, UINT idFirst, UINT idMenu, BgCmImpl * This) InsertMenuItemW(hMenu, -1, TRUE, &mii); - mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; //MIIM_BITMAP; - mii.fType = MFT_STRING; + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + mii.fType = MFT_OWNERDRAW; mii.fState = MFS_ENABLED; pCurItem = s_SnHead; @@ -468,6 +468,74 @@ DoShellNewCmd(BgCmImpl * This, LPCMINVOKECOMMANDINFO lpcmi) } } } +HRESULT +DoMeasureItem(BgCmImpl *This, HWND hWnd, MEASUREITEMSTRUCT * lpmis) +{ + PSHELLNEW_ITEM pCurItem; + PSHELLNEW_ITEM pItem; + UINT i; + HDC hDC; + SIZE size; + + TRACE("DoMeasureItem entered with id %x\n", lpmis->itemID); + + pCurItem = s_SnHead; + + i = This->iIdShellNewFirst; + pItem = NULL; + while(pCurItem) + { + if (i == lpmis->itemID) + { + pItem = pCurItem; + break; + } + pCurItem = pCurItem->Next; + i++; + } + + if (!pItem) + return E_FAIL; + + hDC = GetDC(hWnd); + GetTextExtentPoint32W(hDC, pCurItem->szDesc, strlenW(pCurItem->szDesc), &size); + lpmis->itemWidth = size.cx + 32; + lpmis->itemHeight = max(size.cy, 20); + ReleaseDC (hWnd, hDC); + return S_OK; +} + +HRESULT +DoDrawItem(BgCmImpl *This, HWND hWnd, DRAWITEMSTRUCT * drawItem) +{ + PSHELLNEW_ITEM pCurItem; + PSHELLNEW_ITEM pItem; + UINT i; + pCurItem = s_SnHead; + + TRACE("DoDrawItem entered with id %x\n", drawItem->itemID); + + i = This->iIdShellNewFirst; + pItem = NULL; + while(pCurItem) + { + if (i == drawItem->itemID) + { + pItem = pCurItem; + break; + } + pCurItem = pCurItem->Next; + i++; + } + + if (!pItem) + return E_FAIL; + + drawItem->rcItem.left += 20; + + DrawTextW(drawItem->hDC, pCurItem->szDesc, wcslen(pCurItem->szDesc), &drawItem->rcItem, 0); + return S_OK; +} /************************************************************************** @@ -870,9 +938,23 @@ static HRESULT WINAPI ISVBgCm_fnHandleMenuMsg( WPARAM wParam, LPARAM lParam) { - BgCmImpl *This = (BgCmImpl *)iface; + BgCmImpl *This = (BgCmImpl *)iface; + DRAWITEMSTRUCT * lpids = (DRAWITEMSTRUCT*) lParam; + MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*) lParam; - FIXME("(%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam); + TRACE("ISVBgCm_fnHandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam); + + switch(uMsg) + { + case WM_MEASUREITEM: + if (lpmis->itemID >= This->iIdShellNewFirst && lpmis->itemID <= This->iIdShellNewLast) + return DoMeasureItem(This, (HWND)wParam, lpmis); + break; + case WM_DRAWITEM: + if (lpmis->itemID >= This->iIdShellNewFirst && lpmis->itemID <= This->iIdShellNewLast) + return DoDrawItem(This, (HWND)wParam, lpids); + break; + } return E_NOTIMPL; } diff --git a/reactos/dll/win32/shell32/shv_item_cmenu.c b/reactos/dll/win32/shell32/shv_item_cmenu.c index 381261de94f..87ee6978a46 100644 --- a/reactos/dll/win32/shell32/shv_item_cmenu.c +++ b/reactos/dll/win32/shell32/shv_item_cmenu.c @@ -56,6 +56,8 @@ typedef struct IContextMenu ** ecmenu; UINT esize; UINT ecount; + UINT iIdSHEFirst; + UINT iIdSHELast; } ItemCmImpl; UINT @@ -215,6 +217,50 @@ void WINAPI _InsertMenuItem ( InsertMenuItemA( hmenu, indexMenu, fByPosition, &mii); } +HRESULT +DoCustomItemAction(ItemCmImpl *This, LPARAM lParam, UINT uMsg) +{ + IContextMenu2 * cmenu; + IContextMenu * menu; + MEASUREITEMSTRUCT * lpmis = (MEASUREITEMSTRUCT *)lParam; + DRAWITEMSTRUCT * drawItem = (DRAWITEMSTRUCT *)lParam; + HRESULT hResult; + + + TRACE("DoCustomItemAction entered with uMsg %x lParam %p\n", uMsg, lParam); + + if (uMsg == WM_MEASUREITEM) + { + menu = This->ecmenu[lpmis->itemID - This->iIdSHEFirst]; + } + else if (uMsg == WM_DRAWITEM) + { + menu = This->ecmenu[drawItem->itemID - This->iIdSHEFirst]; + } + else + { + ERR("unexpected message\n"); + return E_FAIL; + } + + if (!menu) + { + ERR("item is not valid\n"); + return E_FAIL; + } + + hResult = menu->lpVtbl->QueryInterface(menu, &IID_IContextMenu2, (void**)&cmenu); + if (hResult != S_OK) + { + ERR("failed to get IID_IContextMenu2 interface\n"); + return hResult; + } + + hResult = cmenu->lpVtbl->HandleMenuMsg(cmenu, uMsg, (WPARAM)0, lParam); + TRACE("returning hResult %x\n", hResult); + return hResult; +} + BOOL SH_EnlargeContextMenuArray(ItemCmImpl *This, UINT newsize) { @@ -253,7 +299,7 @@ SH_LoadContextMenuHandlers(ItemCmImpl *This, IDataObject * pDataObj, HMENU hMenu HRESULT hResult; UINT idCmdFirst = 0x5000; UINT idCmdLast = 0xFFF0; - static const WCHAR szAny[] = { '*',0}; + static WCHAR szAny[] = { '*',0}; SH_EnumerateDynamicContextHandlerForKey(szAny, This, pDataObj); @@ -283,17 +329,16 @@ SH_LoadContextMenuHandlers(ItemCmImpl *This, IDataObject * pDataObj, HMENU hMenu } TRACE("SH_LoadContextMenuHandlers num extensions %u\n", This->ecount); - + This->iIdSHEFirst = idCmdFirst; for (i = 0; i < This->ecount; i++) { cmenu = This->ecmenu[i]; - TRACE("Invoking menu %p\n", cmenu); - hResult = cmenu->lpVtbl->QueryContextMenu(hMenu, indexMenu, idCmdFirst, idCmdLast, idCmdLast, CMF_NORMAL); - TRACE("result %x\n",hResult); + hResult = cmenu->lpVtbl->QueryContextMenu(cmenu, hMenu, indexMenu, idCmdFirst, idCmdLast, CMF_NORMAL); + idCmdFirst += (hResult & 0xFFFF); } + This->iIdSHELast = idCmdFirst; - - + TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This->iIdSHEFirst, This->iIdSHELast); } /************************************************************************** @@ -681,10 +726,20 @@ static HRESULT WINAPI ISvItemCm_fnHandleMenuMsg( LPARAM lParam) { ItemCmImpl *This = (ItemCmImpl *)iface; - + LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam; TRACE("(%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam); - return E_NOTIMPL; + switch(uMsg) + { + case WM_MEASUREITEM: + case WM_DRAWITEM: + if (lpmis->itemID >= This->iIdSHEFirst && lpmis->itemID <= This->iIdSHELast) + return DoCustomItemAction(This, lParam, uMsg); + break; + + } + + return E_NOTIMPL; } static const IContextMenu2Vtbl cmvt =