[SHELL32] - CDefaultContextMenu::QueryContextMenu : Implement CMF_VERBSONLY flag...
[reactos.git] / reactos / dll / win32 / shell32 / CDefaultContextMenu.cpp
index 233dbd5..59f4cfc 100644 (file)
@@ -6,14 +6,15 @@
  * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
  */
 
-/*
-TODO:
-    The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
-    example of the wrong way to do it.
-*/
-
 #include "precomp.h"
 
+extern "C"
+{
+    //fixme: this isn't in wine's shlwapi header, and the definition doesnt match the
+    // windows headers. When wine's header and lib are fixed this can be removed.
+    DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen);
+};
+
 WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
 
 typedef struct _DynamicShellEntry_
@@ -28,19 +29,45 @@ typedef struct _DynamicShellEntry_
 typedef struct _StaticShellEntry_
 {
     LPWSTR szVerb;
-    LPWSTR szClass;
+    HKEY hkClass;
     struct _StaticShellEntry_ *pNext;
 } StaticShellEntry, *PStaticShellEntry;
 
+
+//
+// verbs for InvokeCommandInfo
+//
+struct _StaticInvokeCommandMap_
+{
+    LPCSTR szStringVerb;
+    UINT IntVerb;
+} g_StaticInvokeCmdMap[] = 
+{
+    { "RunAs", 0 },  // Unimplemented
+    { "Print", 0 },  // Unimplemented
+    { "Preview", 0 }, // Unimplemented
+    { "Open", FCIDM_SHVIEW_OPEN },
+    { CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER },
+    { CMDSTR_VIEWLISTA, FCIDM_SHVIEW_LISTVIEW },
+    { CMDSTR_VIEWDETAILSA, FCIDM_SHVIEW_REPORTVIEW }
+};
+
+
 class CDefaultContextMenu :
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IContextMenu2
+    public IContextMenu3,
+    public IObjectWithSite
 {
     private:
+        CComPtr<IUnknown> m_site;
         CComPtr<IShellFolder> m_psf;
+        CComPtr<IContextMenuCB> m_pmcb;
+        LPFNDFMCALLBACK m_pfnmcb;
         UINT m_cidl;
         PCUITEMID_CHILD_ARRAY m_apidl;
         CComPtr<IDataObject> m_pDataObj;
+        HKEY* m_aKeys;
+        UINT m_cKeys;
         PIDLIST_ABSOLUTE m_pidlFolder;
         DWORD m_bGroupPolicyActive;
         PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */
@@ -50,35 +77,35 @@ class CDefaultContextMenu :
         UINT m_iIdSCMFirst; /* first static used id */
         UINT m_iIdSCMLast; /* last static used id */
 
-        void AddStaticEntry(LPCWSTR pwszVerb, LPCWSTR pwszClass);
-        void AddStaticEntryForKey(HKEY hKey, LPCWSTR pwszClass);
-        void AddStaticEntryForFileClass(LPCWSTR pwszExt);
+        HRESULT _DoCallback(UINT uMsg, WPARAM wParam, LPVOID lParam);
+        void AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb);
+        void AddStaticEntriesForKey(HKEY hKey);
         BOOL IsShellExtensionAlreadyLoaded(const CLSID *pclsid);
         HRESULT LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid);
         BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey);
         UINT InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast);
-        UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
         UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
         UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
         HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink);
         HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
         HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
-        HRESULT DoRefresh(LPCMINVOKECOMMANDINFO lpcmi);
         HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
         HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy);
         HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
         HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
-        HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
+        HRESULT DoCreateNewFolder(LPCMINVOKECOMMANDINFO lpici);
         HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
         HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
         DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry);
         HRESULT TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags);
         HRESULT InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry);
+        PDynamicShellEntry GetDynamicEntry(UINT idCmd);
+        BOOL MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode);
 
     public:
         CDefaultContextMenu();
         ~CDefaultContextMenu();
-        HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm);
+        HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm, LPFNDFMCALLBACK lpfn);
 
         // IContextMenu
         virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
@@ -88,17 +115,30 @@ class CDefaultContextMenu :
         // IContextMenu2
         virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
 
+        // IContextMenu3
+        virtual HRESULT WINAPI HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult);
+
+        // IObjectWithSite
+        virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite);
+        virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void **ppvSite);
+
         BEGIN_COM_MAP(CDefaultContextMenu)
         COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
         COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
+        COM_INTERFACE_ENTRY_IID(IID_IContextMenu3, IContextMenu3)
+        COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
         END_COM_MAP()
 };
 
 CDefaultContextMenu::CDefaultContextMenu() :
     m_psf(NULL),
+    m_pmcb(NULL),
+    m_pfnmcb(NULL),
     m_cidl(0),
     m_apidl(NULL),
     m_pDataObj(NULL),
+    m_aKeys(NULL),
+    m_cKeys(NULL),
     m_pidlFolder(NULL),
     m_bGroupPolicyActive(0),
     m_pDynamicEntries(NULL),
@@ -127,31 +167,48 @@ CDefaultContextMenu::~CDefaultContextMenu()
     while (pStaticEntry)
     {
         pNextStatic = pStaticEntry->pNext;
-        HeapFree(GetProcessHeap(), 0, pStaticEntry->szClass);
         HeapFree(GetProcessHeap(), 0, pStaticEntry->szVerb);
         HeapFree(GetProcessHeap(), 0, pStaticEntry);
         pStaticEntry = pNextStatic;
     }
 
+    for (UINT i = 0; i < m_cKeys; i++)
+        RegCloseKey(m_aKeys[i]);
+    HeapFree(GetProcessHeap(), 0, m_aKeys);
+
     if (m_pidlFolder)
         CoTaskMemFree(m_pidlFolder);
     _ILFreeaPidl(const_cast<PITEMID_CHILD *>(m_apidl), m_cidl);
 }
 
-HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
+HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm, LPFNDFMCALLBACK lpfn)
 {
-    CComPtr<IDataObject> pDataObj;
-
     TRACE("cidl %u\n", pdcm->cidl);
 
+    if (!pdcm->pcmcb && !lpfn)
+    {
+        ERR("CDefaultContextMenu needs a callback!\n");
+        return E_INVALIDARG;
+    }
+
     m_cidl = pdcm->cidl;
     m_apidl = const_cast<PCUITEMID_CHILD_ARRAY>(_ILCopyaPidl(pdcm->apidl, m_cidl));
     if (m_cidl && !m_apidl)
         return E_OUTOFMEMORY;
     m_psf = pdcm->psf;
+    m_pmcb = pdcm->pcmcb;
+    m_pfnmcb = lpfn;
+
+    m_cKeys = pdcm->cKeys;
+    if (pdcm->cKeys)
+    {
+        m_aKeys = (HKEY*)HeapAlloc(GetProcessHeap(), 0, sizeof(HKEY) * pdcm->cKeys);
+        if (!m_aKeys)
+            return E_OUTOFMEMORY;
+        memcpy(m_aKeys, pdcm->aKeys, sizeof(HKEY) * pdcm->cKeys);
+    }
 
-    if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
-        m_pDataObj = pDataObj;
+    m_psf->GetUIObjectOf(pdcm->hwnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &m_pDataObj));
 
     if (pdcm->pidlFolder)
     {
@@ -171,8 +228,21 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
     return S_OK;
 }
 
-void
-CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
+HRESULT CDefaultContextMenu::_DoCallback(UINT uMsg, WPARAM wParam, LPVOID lParam)
+{
+    if (m_pmcb)
+    {
+        return m_pmcb->CallBack(m_psf, NULL, m_pDataObj, uMsg, wParam, (LPARAM)lParam);
+    }
+    else if(m_pfnmcb)
+    {
+        return m_pfnmcb(m_psf, NULL, m_pDataObj, uMsg, wParam, (LPARAM)lParam);
+    }
+
+    return E_FAIL;
+}
+
+void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb)
 {
     PStaticShellEntry pEntry = m_pStaticEntries, pLastEntry = NULL;
     while(pEntry)
@@ -186,7 +256,7 @@ CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
         pEntry = pEntry->pNext;
     }
 
-    TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
+    TRACE("adding verb %s\n", debugstr_w(szVerb));
 
     pEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
     if (pEntry)
@@ -195,9 +265,7 @@ CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
         pEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb) + 1) * sizeof(WCHAR));
         if (pEntry->szVerb)
             wcscpy(pEntry->szVerb, szVerb);
-        pEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass) + 1) * sizeof(WCHAR));
-        if (pEntry->szClass)
-            wcscpy(pEntry->szClass, szClass);
+        pEntry->hkClass = hkeyClass;
     }
 
     if (!wcsicmp(szVerb, L"open"))
@@ -212,88 +280,26 @@ CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
         m_pStaticEntries = pEntry;
 }
 
-void
-CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey, const WCHAR *pwszClass)
+void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey)
 {
     WCHAR wszName[40];
     DWORD cchName, dwIndex = 0;
+    HKEY hShellKey;
 
-    TRACE("AddStaticEntryForKey %x %ls\n", hKey, pwszClass);
+    LRESULT lres = RegOpenKeyExW(hKey, L"shell", 0, KEY_READ, &hShellKey);
+    if (lres != STATUS_SUCCESS)
+        return;
 
     while(TRUE)
     {
         cchName = _countof(wszName);
-        if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+        if (RegEnumKeyExW(hShellKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
             break;
 
-        AddStaticEntry(wszName, pwszClass);
-    }
-}
-
-void
-CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR * szExt)
-{
-    WCHAR szBuffer[100];
-    HKEY hKey;
-    LONG result;
-    DWORD dwBuffer;
-    UINT Length;
-    static WCHAR szShell[] = L"\\shell";
-    static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
-
-    TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt));
-
-    Length = wcslen(szExt);
-    if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
-    {
-        wcscpy(szBuffer, szExt);
-        wcscpy(&szBuffer[Length], szShell);
-        result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
-        if (result == ERROR_SUCCESS)
-        {
-            szBuffer[Length] = 0;
-            AddStaticEntryForKey(hKey, szExt);
-            RegCloseKey(hKey);
-        }
+        AddStaticEntry(hKey, wszName);
     }
 
-    dwBuffer = sizeof(szBuffer);
-    result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer);
-    if (result == ERROR_SUCCESS)
-    {
-        Length = wcslen(szBuffer);
-        if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
-        {
-            wcscpy(&szBuffer[Length], szShell);
-            TRACE("szBuffer %s\n", debugstr_w(szBuffer));
-
-            result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
-            if (result == ERROR_SUCCESS)
-            {
-                szBuffer[Length] = 0;
-                AddStaticEntryForKey(hKey, szBuffer);
-                RegCloseKey(hKey);
-            }
-        }
-    }
-
-    wcscpy(szBuffer, szShellAssoc);
-    dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR);
-    result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer);
-    if (result == ERROR_SUCCESS)
-    {
-        Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc);
-        wcscat(szBuffer, L"\\shell");
-        TRACE("szBuffer %s\n", debugstr_w(szBuffer));
-
-        result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
-        if (result == ERROR_SUCCESS)
-        {
-            szBuffer[Length] = 0;
-            AddStaticEntryForKey(hKey, szBuffer);
-            RegCloseKey(hKey);
-        }
-    }
+    RegCloseKey(hShellKey);
 }
 
 static
@@ -303,7 +309,7 @@ HasClipboardData()
     BOOL bRet = FALSE;
     CComPtr<IDataObject> pDataObj;
 
-    if(SUCCEEDED(OleGetClipboard(&pDataObj)))
+    if (SUCCEEDED(OleGetClipboard(&pDataObj)))
     {
         STGMEDIUM medium;
         FORMATETC formatetc;
@@ -312,7 +318,7 @@ HasClipboardData()
 
         /* Set the FORMATETC structure*/
         InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
-        if(SUCCEEDED(pDataObj->GetData(&formatetc, &medium)))
+        if (SUCCEEDED(pDataObj->GetData(&formatetc, &medium)))
         {
             bRet = TRUE;
             ReleaseStgMedium(&medium);
@@ -322,20 +328,6 @@ HasClipboardData()
     return bRet;
 }
 
-static
-VOID
-DisablePasteOptions(HMENU hMenu)
-{
-    MENUITEMINFOW mii;
-
-    mii.cbSize = sizeof(mii);
-    mii.fMask = MIIM_STATE;
-    mii.fState = MFS_DISABLED;
-
-    TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii));
-    TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii));
-}
-
 BOOL
 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID *pclsid)
 {
@@ -363,32 +355,24 @@ CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsi
 
     CComPtr<IContextMenu> pcm;
     hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IContextMenu, &pcm));
-    if (hr != S_OK)
-    {
-        ERR("SHCoCreateInstance failed %x\n", GetLastError());
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-    }
 
     CComPtr<IShellExtInit> pExtInit;
     hr = pcm->QueryInterface(IID_PPV_ARG(IShellExtInit, &pExtInit));
-    if (hr != S_OK)
-    {
-        ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-    }
 
     hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey);
-    if (hr != S_OK)
+    if (FAILED(hr))
     {
-        TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
+        WARN("IShellExtInit::Initialize failed.clsid %s hr 0x%x\n", wine_dbgstr_guid(pclsid), hr);
         return hr;
     }
 
     PDynamicShellEntry pEntry = (DynamicShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
     if (!pEntry)
-    {
         return E_OUTOFMEMORY;
-    }
 
     pEntry->iIdCmdFirst = 0;
     pEntry->pNext = NULL;
@@ -414,7 +398,6 @@ CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsi
 BOOL
 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
 {
-
     WCHAR wszName[MAX_PATH], wszBuf[MAX_PATH], *pwszClsid;
     DWORD cchName;
     HRESULT hr;
@@ -445,24 +428,31 @@ CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
                 hr = CLSIDFromString(wszBuf, &clsid);
             pwszClsid = wszBuf;
         }
-        if (SUCCEEDED(hr))
+
+        if (FAILED(hr))
+        {
+            ERR("CLSIDFromString failed for clsid %S hr 0x%x\n", pwszClsid, hr);
+            continue;
+        }
+
+        if (m_bGroupPolicyActive)
         {
-            if (m_bGroupPolicyActive)
+            if (RegGetValueW(HKEY_LOCAL_MACHINE,
+                             L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
+                             pwszClsid,
+                             RRF_RT_REG_SZ,
+                             NULL,
+                             NULL,
+                             NULL) != ERROR_SUCCESS)
             {
-                if (RegGetValueW(HKEY_LOCAL_MACHINE,
-                                 L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
-                                 pwszClsid,
-                                 RRF_RT_REG_SZ,
-                                 NULL,
-                                 NULL,
-                                 NULL) == ERROR_SUCCESS)
-                {
-                    LoadDynamicContextMenuHandler(hKey, &clsid);
-                }
+                ERR("Shell extension %s not approved!\n", pwszClsid);
+                continue;
             }
-            else
-                LoadDynamicContextMenuHandler(hKey, &clsid);
         }
+
+        hr = LoadDynamicContextMenuHandler(hKey, &clsid);
+        if (FAILED(hr))
+            WARN("Failed to get context menu entires from shell extension! clsid: %S\n", pwszClsid);
     }
 
     RegCloseKey(hKey);
@@ -502,87 +492,6 @@ CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, U
     return IndexMenu;
 }
 
-UINT
-CDefaultContextMenu::BuildBackgroundContextMenu(
-    HMENU hMenu,
-    UINT iIdCmdFirst,
-    UINT iIdCmdLast,
-    UINT uFlags)
-{
-    UINT IndexMenu = 0;
-    HMENU hSubMenu;
-
-    TRACE("BuildBackgroundContextMenu entered\n");
-
-    SFGAOF rfg = SFGAO_FILESYSTEM | SFGAO_FOLDER;
-    HRESULT hr = m_psf->GetAttributesOf(0, NULL, &rfg);
-    if (FAILED(hr))
-    {
-        ERR("GetAttributesOf failed: %x\n", hr);
-        rfg = 0;
-    }
-
-    if (!_ILIsDesktop(m_pidlFolder))
-    {
-        WCHAR wszBuf[MAX_PATH];
-
-        /* view option is only available in browsing mode */
-        hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
-        if (hSubMenu && LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, wszBuf, _countof(wszBuf)))
-        {
-            TRACE("wszBuf %s\n", debugstr_w(wszBuf));
-
-            MENUITEMINFOW mii;
-            ZeroMemory(&mii, sizeof(mii));
-            mii.cbSize = sizeof(mii);
-            mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
-            mii.fType = MFT_STRING;
-            mii.wID = iIdCmdFirst++;
-            mii.dwTypeData = wszBuf;
-            mii.cch = wcslen(mii.dwTypeData);
-            mii.fState = MFS_ENABLED;
-            mii.hSubMenu = hSubMenu;
-            InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
-            DestroyMenu(hSubMenu);
-        }
-    }
-
-    hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002");
-    if (hSubMenu)
-    {
-        /* merge general background context menu in */
-        iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), IndexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1;
-        DestroyMenu(hSubMenu);
-    }
-
-    if (!HasClipboardData())
-    {
-        TRACE("disabling paste options\n");
-        DisablePasteOptions(hMenu);
-    }
-
-    /* Directory is progid of filesystem folders only */
-    if (rfg == (SFGAO_FILESYSTEM|SFGAO_FOLDER))
-    {
-        /* Load context menu handlers */
-        TRACE("Add background handlers: %p\n", m_pidlFolder);
-        HKEY hKey;
-        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory\\Background", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-        {
-            EnumerateDynamicContextHandlerForKey(hKey);
-            RegCloseKey(hKey);
-        }
-
-        if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu, GetMenuItemCount(hMenu) - 1, iIdCmdFirst, iIdCmdLast))
-        {
-            /* seperate dynamic context menu items */
-            _InsertMenuItemW(hMenu, GetMenuItemCount(hMenu) - 1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
-        }
-    }
-
-    return iIdCmdLast;
-}
-
 UINT
 CDefaultContextMenu::AddStaticContextMenusToMenu(
     HMENU hMenu,
@@ -648,14 +557,30 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
         else
         {
             WCHAR wszKey[256];
-            HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
+            HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", pEntry->szVerb);
 
             if (SUCCEEDED(hr))
             {
+                HKEY hkVerb;
                 DWORD cbVerb = sizeof(wszVerb);
+                LONG res = RegOpenKeyW(pEntry->hkClass, wszKey, &hkVerb);
+                if (res == ERROR_SUCCESS)
+                {
+                    res = RegLoadMUIStringW(hkVerb, 
+                                            NULL,
+                                            wszVerb,
+                                            cbVerb,
+                                            NULL,
+                                            0,
+                                            NULL);
+                    if (res == ERROR_SUCCESS)
+                    {
+                        /* use description for the menu entry */
+                        mii.dwTypeData = wszVerb; 
+                    }
 
-                if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, NULL, RRF_RT_REG_SZ, NULL, wszVerb, &cbVerb) == ERROR_SUCCESS)
-                    mii.dwTypeData = wszVerb; /* use description for the menu entry */
+                    RegCloseKey(hkVerb);
+                }
             }
         }
 
@@ -710,160 +635,58 @@ void WINAPI _InsertMenuItemW(
     InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
 }
 
-UINT
-CDefaultContextMenu::BuildShellItemContextMenu(
+HRESULT
+WINAPI
+CDefaultContextMenu::QueryContextMenu(
     HMENU hMenu,
-    UINT iIdCmdFirst,
-    UINT iIdCmdLast,
+    UINT IndexMenu,
+    UINT idCmdFirst,
+    UINT idCmdLast,
     UINT uFlags)
 {
-    HKEY hKey;
     HRESULT hr;
 
     TRACE("BuildShellItemContextMenu entered\n");
-    ASSERT(m_cidl >= 1);
 
-    STRRET strFile;
-    hr = m_psf->GetDisplayNameOf(m_apidl[0], SHGDN_FORPARSING, &strFile);
-    if (hr == S_OK)
+    /* Load static verbs and shell extensions from registry */
+    for (UINT i = 0; i < m_cKeys; i++)
     {
-        WCHAR wszPath[MAX_PATH];
-        hr = StrRetToBufW(&strFile, m_apidl[0], wszPath, _countof(wszPath));
-        if (hr == S_OK)
-        {
-            LPCWSTR pwszExt = PathFindExtensionW(wszPath);
-            if (pwszExt[0])
-            {
-                /* enumerate dynamic/static for a given file class */
-                if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-                {
-                    /* add static verbs */
-                    AddStaticEntryForFileClass(pwszExt);
-
-                    /* load dynamic extensions from file extension key */
-                    EnumerateDynamicContextHandlerForKey(hKey);
-                    RegCloseKey(hKey);
-                }
-
-                WCHAR wszTemp[40];
-                DWORD dwSize = sizeof(wszTemp);
-                if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
-                {
-                    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-                    {
-                        /* add static verbs from progid key */
-                        AddStaticEntryForFileClass(wszTemp);
-
-                        /* load dynamic extensions from progid key */
-                        EnumerateDynamicContextHandlerForKey(hKey);
-                        RegCloseKey(hKey);
-                    }
-                }
-            }
-
-            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-            {
-                /* load default extensions */
-                EnumerateDynamicContextHandlerForKey(hKey);
-                RegCloseKey(hKey);
-            }
-        }
+        AddStaticEntriesForKey(m_aKeys[i]);
+        EnumerateDynamicContextHandlerForKey(m_aKeys[i]);
     }
-    else
-        ERR("GetDisplayNameOf failed: %x\n", hr);
 
-    GUID *pGuid = _ILGetGUIDPointer(m_apidl[0]);
-    if (pGuid)
-    {
-        LPOLESTR pwszCLSID;
-        WCHAR buffer[60];
+    /* Add static context menu handlers */
+    IndexMenu = AddStaticContextMenusToMenu(hMenu, IndexMenu);
 
-        wcscpy(buffer, L"CLSID\\");
-        hr = StringFromCLSID(*pGuid, &pwszCLSID);
-        if (hr == S_OK)
-        {
-            wcscpy(&buffer[6], pwszCLSID);
-            TRACE("buffer %s\n", debugstr_w(buffer));
-            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-            {
-                EnumerateDynamicContextHandlerForKey(hKey);
-                AddStaticEntryForFileClass(buffer);
-                RegCloseKey(hKey);
-            }
-            CoTaskMemFree(pwszCLSID);
-        }
-    }
+    /* Add dynamic context menu handlers */
+    BOOL bAddSep = FALSE;
+    IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, idCmdFirst, idCmdLast);
+    TRACE("IndexMenu %d\n", IndexMenu);
 
-    if (_ILIsDrive(m_apidl[0]))
-    {
-        AddStaticEntryForFileClass(L"Drive");
-        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-        {
-            EnumerateDynamicContextHandlerForKey(hKey);
-            RegCloseKey(hKey);
-        }
+    /* Now let the callback add its own items */
+    QCMINFO qcminfo;
+    qcminfo.hmenu = hMenu;
+    qcminfo.indexMenu = IndexMenu;
+    qcminfo.idCmdFirst = idCmdFirst;
+    qcminfo.idCmdLast = idCmdLast;
+    qcminfo.pIdMap = NULL;
+    _DoCallback(DFM_MERGECONTEXTMENU, uFlags, &qcminfo);
+    IndexMenu = GetMenuItemCount(hMenu);
+
+    if (uFlags & CMF_VERBSONLY)
+        return S_OK;
 
-    }
+    /* If this is a background context menu we are done */
+    if (!m_cidl)
+        return S_OK;
 
-    /* add static actions */
+    /* Get the attributes of the items */
     SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
     hr = m_psf->GetAttributesOf(m_cidl, m_apidl, &rfg);
-    if (FAILED(hr))
-    {
-        ERR("GetAttributesOf failed: %x\n", hr);
-        rfg = 0;
-    }
-
-    if (rfg & SFGAO_FOLDER)
-    {
-        /* add the default verbs open / explore */
-        AddStaticEntryForFileClass(L"Folder");
-        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-        {
-            EnumerateDynamicContextHandlerForKey(hKey);
-            RegCloseKey(hKey);
-        }
-
-        /* Directory is only loaded for real filesystem directories */
-        if (rfg & SFGAO_FILESYSTEM)
-        {
-            AddStaticEntryForFileClass(L"Directory");
-            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-            {
-                EnumerateDynamicContextHandlerForKey(hKey);
-                RegCloseKey(hKey);
-            }
-        }
-    }
-
-    /* AllFilesystemObjects class is loaded only for files and directories */
-    if (rfg & SFGAO_FILESYSTEM)
-    {
-        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-        {
-            /* sendto service is registered here */
-            EnumerateDynamicContextHandlerForKey(hKey);
-            RegCloseKey(hKey);
-        }
-    }
-
-    /* add static context menu handlers */
-    UINT IndexMenu = AddStaticContextMenusToMenu(hMenu, 0);
-
-    /* now process dynamic context menu handlers */
-    BOOL bAddSep = FALSE;
-    IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, iIdCmdFirst, iIdCmdLast);
-    TRACE("IndexMenu %d\n", IndexMenu);
-
-    if (_ILIsDrive(m_apidl[0]))
-    {
-        /* The 'Format' option must be always available,
-         * thus it is not registered as a static shell extension */
-        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
-        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
-        bAddSep = TRUE;
-    }
+    if (FAILED_UNEXPECTEDLY(hr))
+        return S_OK;
 
+    /* Add the standard menu entries based on the attributes of the items */
     BOOL bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM));
     if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData)
     {
@@ -911,120 +734,17 @@ CDefaultContextMenu::BuildShellItemContextMenu(
         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
     }
 
-    return iIdCmdLast;
-}
-
-HRESULT
-WINAPI
-CDefaultContextMenu::QueryContextMenu(
-    HMENU hMenu,
-    UINT IndexMenu,
-    UINT idCmdFirst,
-    UINT idCmdLast,
-    UINT uFlags)
-{
-    if (m_cidl)
-        idCmdFirst = BuildShellItemContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
-    else
-        idCmdFirst = BuildBackgroundContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
-
     return S_OK;
 }
 
-static
-HRESULT
-NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
-{
-    /* Note: CWM_GETISHELLBROWSER returns not referenced object */
-    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
-    if (!lpSB)
-        return E_FAIL;
-
-    CComPtr<IShellView> lpSV;
-    if (FAILED(lpSB->QueryActiveShellView(&lpSV)))
-        return E_FAIL;
-
-    HWND hwndSV = NULL;
-    if (SUCCEEDED(lpSV->GetWindow(&hwndSV)))
-        SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
-    return S_OK;
-}
-
-HRESULT
-CDefaultContextMenu::DoRefresh(
-    LPCMINVOKECOMMANDINFO lpcmi)
-{
-    CComPtr<IPersistFolder2> ppf2 = NULL;
-    LPITEMIDLIST pidl;
-    HRESULT hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
-    if (SUCCEEDED(hr))
-    {
-        hr = ppf2->GetCurFolder(&pidl);
-        if (SUCCEEDED(hr))
-        {
-            SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
-            ILFree(pidl);
-        }
-    }
-    return hr;
-}
-
-HRESULT
-CDefaultContextMenu::DoPaste(
-    LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink)
+HRESULT CDefaultContextMenu::DoPaste(LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink)
 {
     HRESULT hr;
 
     CComPtr<IDataObject> pda;
     hr = OleGetClipboard(&pda);
-    if (FAILED(hr))
-        return hr;
-
-    CComPtr<IShellFolder> psfDesktop;
-    CComPtr<IShellFolder> psfTarget = NULL;
-
-    hr = SHGetDesktopFolder(&psfDesktop);
-    if (FAILED(hr))
-        return hr;
-
-    /* Find target folder */
-    if (m_cidl)
-    {
-        hr = m_psf->BindToObject(m_apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
-    }
-    else
-    {
-        CComPtr<IPersistFolder2> ppf2 = NULL;
-        LPITEMIDLIST pidl;
-
-        /* cidl is zero due to explorer view */
-        hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
-        if (SUCCEEDED(hr))
-        {
-            hr = ppf2->GetCurFolder(&pidl);
-            if (SUCCEEDED(hr))
-            {
-                if (_ILIsDesktop(pidl))
-                {
-                    /* use desktop shellfolder */
-                    psfTarget = psfDesktop;
-                }
-                else
-                {
-                    /* retrieve target desktop folder */
-                    hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
-                }
-                TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
-                ILFree(pidl);
-            }
-        }
-    }
-
-    if (FAILED(hr))
-    {
-        ERR("no IShellFolder\n");
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-    }
 
     FORMATETC formatetc2;
     STGMEDIUM medium2;
@@ -1054,12 +774,13 @@ CDefaultContextMenu::DoPaste(
     }
 
     CComPtr<IDropTarget> pdrop;
-    hr = psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pdrop));
-    if (FAILED(hr))
-    {
-        ERR("Error getting IDropTarget interface\n");
+    if (m_cidl)
+        hr = m_psf->GetUIObjectOf(NULL, 1, &m_apidl[0], IID_NULL_PPV_ARG(IDropTarget, &pdrop));
+    else
+        hr = m_psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pdrop));
+
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-    }
 
     SHSimulateDrop(pdrop, pda, dwKey, NULL, NULL);
 
@@ -1068,312 +789,227 @@ CDefaultContextMenu::DoPaste(
 }
 
 HRESULT
-CDefaultContextMenu::DoOpenOrExplore(
-    LPCMINVOKECOMMANDINFO lpcmi)
+CDefaultContextMenu::DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi)
 {
     UNIMPLEMENTED;
     return E_FAIL;
 }
 
-HRESULT
-CDefaultContextMenu::DoCreateLink(
-    LPCMINVOKECOMMANDINFO lpcmi)
+HRESULT CDefaultContextMenu::DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi)
 {
-    CComPtr<IDataObject> pDataObj;
-    CComPtr<IDropTarget> pDT;
-    HRESULT hr;
-    CComPtr<IPersistFolder2> ppf2 = NULL;
-    LPITEMIDLIST pidl;
-    CComPtr<IShellFolder> psfDesktop;
-    CComPtr<IShellFolder> psfTarget = NULL;
+    if (!m_cidl || !m_pDataObj)
+        return E_FAIL;
 
-    hr = SHGetDesktopFolder(&psfDesktop);
-    if (FAILED(hr))
+    CComPtr<IDropTarget> pDT;
+    HRESULT hr = m_psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT));
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
-    if (SUCCEEDED(hr = SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
-    {
-        hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
-        if (SUCCEEDED(hr))
-        {
-            hr = ppf2->GetCurFolder(&pidl);
-            if (SUCCEEDED(hr))
-            {
-                if (_ILIsDesktop(pidl))
-                {
-                    /* use desktop shellfolder */
-                    psfTarget = psfDesktop;
-                }
-                else
-                {
-                    /* retrieve target desktop folder */
-                    hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
-                }
-                TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
-                ILFree(pidl);
-            }
-        }
-
-    }
+    SHSimulateDrop(pDT, m_pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
 
-    if (FAILED(hr))
-    {
-        ERR("no IShellFolder\n");
-        return hr;
-    }
+    return S_OK;
+}
 
-    hr = psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pDT));
-    if (FAILED(hr))
-    {
-        ERR("no IDropTarget Interface\n");
-        return hr;
-    }
-    SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
+HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi)
+{
+    if (!m_cidl || !m_pDataObj)
+        return E_FAIL;
 
+    DoDeleteAsync(m_pDataObj, lpcmi->fMask);
     return S_OK;
 }
 
-HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi) {
-    TRACE("(%p) Deleting\n", this);
-
-    CComPtr<IDataObject> pDataObject;
+HRESULT CDefaultContextMenu::DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy)
+{
+    if (!m_cidl || !m_pDataObj)
+        return E_FAIL;
 
-    if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObject))))
+    if (!bCopy)
     {
-        IStream *s;
-        CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &s);
-        SHCreateThread(DoDeleteThreadProc, s, NULL, NULL);
+        FORMATETC formatetc;
+        STGMEDIUM medium;
+        InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
+        m_pDataObj->GetData(&formatetc, &medium);
+        DWORD * pdwFlag = (DWORD*)GlobalLock(medium.hGlobal);
+        if (pdwFlag)
+            *pdwFlag = DROPEFFECT_MOVE;
+        GlobalUnlock(medium.hGlobal);
+        m_pDataObj->SetData(&formatetc, &medium, TRUE);
     }
-    else
-        return E_FAIL;
+
+    HRESULT hr = OleSetClipboard(m_pDataObj);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
     return S_OK;
 }
 
-HRESULT
-CDefaultContextMenu::DoCopyOrCut(
-    LPCMINVOKECOMMANDINFO lpcmi,
-    BOOL bCopy)
+HRESULT CDefaultContextMenu::DoRename(LPCMINVOKECOMMANDINFO lpcmi)
 {
-    CComPtr<IDataObject> pDataObj;
+    CComPtr<IShellBrowser> psb;
     HRESULT hr;
 
-    if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
-    {
-        if (!bCopy)
-        {
-            FORMATETC formatetc;
-            STGMEDIUM medium;
-            InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
-            pDataObj->GetData(&formatetc, &medium);
-            DWORD * pdwFlag = (DWORD*)GlobalLock(medium.hGlobal);
-            if (pdwFlag)
-                *pdwFlag = DROPEFFECT_MOVE;
-            GlobalUnlock(medium.hGlobal);
-            pDataObj->SetData(&formatetc, &medium, TRUE);
-        }
+    if (!m_site || !m_cidl)
+        return E_FAIL;
 
-        hr = OleSetClipboard(pDataObj);
+    /* Get a pointer to the shell browser */
+    hr = IUnknown_QueryService(m_site, SID_IShellBrowser, IID_PPV_ARG(IShellBrowser, &psb));
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-    }
-
-    /* Note: CWM_GETISHELLBROWSER returns not referenced object */
-    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
-    if (!lpSB)
-    {
-        ERR("failed to get shellbrowser\n");
-        return E_FAIL;
-    }
 
     CComPtr<IShellView> lpSV;
-    hr = lpSB->QueryActiveShellView(&lpSV);
-    if (FAILED(hr))
-    {
-        ERR("failed to query the active shellview\n");
+    hr = psb->QueryActiveShellView(&lpSV);
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-    }
 
-    hr = lpSV->GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IDataObject, &pDataObj));
-    if (SUCCEEDED(hr))
-    {
-        hr = OleSetClipboard(pDataObj);
-        if (FAILED(hr))
-            ERR("OleSetClipboard failed");
-        pDataObj->Release();
-    } else
-        ERR("failed to get item object\n");
+    SVSIF selFlags = SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT;
+    hr = lpSV->SelectItem(m_apidl[0], selFlags);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-    return hr;
+    return S_OK;
 }
 
 HRESULT
-CDefaultContextMenu::DoRename(
+CDefaultContextMenu::DoProperties(
     LPCMINVOKECOMMANDINFO lpcmi)
 {
-    /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
-    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
-    if (!lpSB)
-    {
-        ERR("CWM_GETISHELLBROWSER failed\n");
-        return E_FAIL;
-    }
-
-    /* is the treeview focused */
-    HWND hwnd;
-    if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
-    {
-        HTREEITEM hItem = TreeView_GetSelection(hwnd);
-        if (hItem)
-            (void)TreeView_EditLabel(hwnd, hItem);
-    }
+    _DoCallback(DFM_INVOKECOMMAND, DFM_CMD_PROPERTIES, NULL);
 
-    CComPtr<IShellView> lpSV;
-    HRESULT hr = lpSB->QueryActiveShellView(&lpSV);
-    if (FAILED(hr))
-    {
-        ERR("CWM_GETISHELLBROWSER failed\n");
-        return hr;
-    }
-
-    SVSIF selFlags = SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT;
-    lpSV->SelectItem(m_apidl[0], selFlags);
     return S_OK;
 }
 
+// This code is taken from CNewMenu and should be shared between the 2 classes
 HRESULT
-CDefaultContextMenu::DoProperties(
-    LPCMINVOKECOMMANDINFO lpcmi)
+CDefaultContextMenu::DoCreateNewFolder(
+    LPCMINVOKECOMMANDINFO lpici)
 {
-    HRESULT hr = S_OK;
-    const ITEMIDLIST *pidlParent = m_pidlFolder, *pidlChild;
+    WCHAR wszPath[MAX_PATH];
+    WCHAR wszName[MAX_PATH];
+    WCHAR wszNewFolder[25];
+    HRESULT hr;
 
-    if (!pidlParent)
-    {
-        CComPtr<IPersistFolder2> pf;
+    /* Get folder path */
+    hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-        /* pidlFolder is optional */
-        if (SUCCEEDED(m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
-        {
-            pf->GetCurFolder((_ITEMIDLIST**)&pidlParent);
-        }
-    }
+    if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder)))
+        return E_FAIL;
 
-    if (m_cidl > 0)
-        pidlChild = m_apidl[0];
-    else
-    {
-        /* Set pidlChild to last pidl of current folder */
-        if (pidlParent == m_pidlFolder)
-            pidlParent = (ITEMIDLIST*)ILClone(pidlParent);
+    /* Create the name of the new directory */
+    if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFolder))
+        return E_FAIL;
 
-        pidlChild = (ITEMIDLIST*)ILClone(ILFindLastID(pidlParent));
-        ILRemoveLastID((ITEMIDLIST*)pidlParent);
-    }
+    /* Create the new directory and show the appropriate dialog in case of error */
+    if (SHCreateDirectory(lpici->hwnd, wszName) != ERROR_SUCCESS)
+        return E_FAIL;
 
-    if (_ILIsMyComputer(pidlChild))
-    {
-        if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL))
-            hr = E_FAIL;
-    }
-    else if (_ILIsDesktop(pidlChild))
-    {
-        if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
-            hr = E_FAIL;
-    }
-    else if (_ILIsDrive(pidlChild))
-    {
-        WCHAR wszBuf[MAX_PATH];
-        ILGetDisplayName(pidlChild, wszBuf);
-        if (!SH_ShowDriveProperties(wszBuf, pidlParent, &pidlChild))
-            hr = E_FAIL;
-    }
-    else if (_ILIsNetHood(pidlChild))
-    {
-        // FIXME path!
-        if (32 >= (UINT)ShellExecuteW(NULL, L"open", L"explorer.exe",
-                                      L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
-                                      NULL, SW_SHOWDEFAULT))
-            hr = E_FAIL;
-    }
-    else if (_ILIsBitBucket(pidlChild))
-    {
-        /* FIXME: detect the drive path of bitbucket if appropiate */
-        if(!SH_ShowRecycleBinProperties(L'C'))
-            hr = E_FAIL;
-    }
-    else
-    {
-        if (m_cidl > 1)
-            WARN("SHMultiFileProperties is not yet implemented\n");
+    /* Show and select the new item in the def view */
+    LPITEMIDLIST pidl;
+    PITEMID_CHILD pidlNewItem;
+    CComPtr<IShellView> psv;
 
-        STRRET strFile;
-        hr = m_psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
-        if (SUCCEEDED(hr))
-        {
-            WCHAR wszBuf[MAX_PATH];
-            hr = StrRetToBufW(&strFile, pidlChild, wszBuf, _countof(wszBuf));
-            if (SUCCEEDED(hr))
-                hr = SH_ShowPropertiesDialog(wszBuf, pidlParent, &pidlChild);
-            else
-                ERR("StrRetToBufW failed\n");
-        }
-        else
-            ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
-    }
+    /* Notify the view object about the new item */
+    SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, (LPCVOID)wszName, NULL);
 
-    /* Free allocated PIDLs */
-    if (pidlParent != m_pidlFolder)
-        ILFree((ITEMIDLIST*)pidlParent);
-    if (m_cidl < 1 || pidlChild != m_apidl[0])
-        ILFree((ITEMIDLIST*)pidlChild);
+    if (!m_site)
+        return S_OK;
 
-    return hr;
-}
+    /* Get a pointer to the shell view */
+    hr = IUnknown_QueryService(m_site, SID_IFolderView, IID_PPV_ARG(IShellView, &psv));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return S_OK;
 
-HRESULT
-CDefaultContextMenu::DoFormat(
-    LPCMINVOKECOMMANDINFO lpcmi)
-{
-    char szDrive[8] = {0};
+    /* Attempt to get the pidl of the new item */
+    hr = SHILCreateFromPathW(wszName, &pidl, NULL);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-    if (!_ILGetDrive(m_apidl[0], szDrive, sizeof(szDrive)))
-    {
-        ERR("pidl is not a drive\n");
-        return E_FAIL;
-    }
+    pidlNewItem = ILFindLastID(pidl);
+
+    hr = psv->SelectItem(pidlNewItem, SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE |
+                          SVSI_FOCUSED | SVSI_SELECT);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    SHFree(pidl);
 
-    SHFormatDrive(lpcmi->hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
     return S_OK;
 }
 
-HRESULT
-CDefaultContextMenu::DoDynamicShellExtensions(
-    LPCMINVOKECOMMANDINFO lpcmi)
+PDynamicShellEntry CDefaultContextMenu::GetDynamicEntry(UINT idCmd)
 {
-    UINT idCmd = LOWORD(lpcmi->lpVerb);
     PDynamicShellEntry pEntry = m_pDynamicEntries;
 
-    TRACE("verb %p first %x last %x", lpcmi->lpVerb, m_iIdSHEFirst, m_iIdSHELast);
-
     while(pEntry && idCmd > pEntry->iIdCmdFirst + pEntry->NumIds)
         pEntry = pEntry->pNext;
 
     if (!pEntry)
-        return E_FAIL;
+        return NULL;
+
+    if (idCmd < pEntry->iIdCmdFirst || idCmd > pEntry->iIdCmdFirst + pEntry->NumIds)
+        return NULL;
+
+    return pEntry;
+}
+
+//FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
+#define MAX_VERB 260
+
+BOOL
+CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
+{
+    WCHAR UnicodeStr[MAX_VERB];
 
-    if (idCmd >= pEntry->iIdCmdFirst && idCmd <= pEntry->iIdCmdFirst + pEntry->NumIds)
+    /* Loop through all the static verbs looking for a match */
+    for (UINT i = 0; i < _countof(g_StaticInvokeCmdMap); i++)
     {
-        /* invoke the dynamic context menu */
-        lpcmi->lpVerb = MAKEINTRESOURCEA(idCmd - pEntry->iIdCmdFirst);
-        return pEntry->pCM->InvokeCommand(lpcmi);
+        /* We can match both ANSI and unicode strings */
+        if (IsUnicode)
+        {
+            /* The static verbs are ANSI, get a unicode version before doing the compare */
+            SHAnsiToUnicode(g_StaticInvokeCmdMap[i].szStringVerb, UnicodeStr, MAX_VERB);
+            if (!wcscmp(UnicodeStr, (LPWSTR)Verb))
+            {
+                /* Return the Corresponding Id */
+                *idCmd = g_StaticInvokeCmdMap[i].IntVerb;
+                return TRUE;
+            }
+        }
+        else
+        {
+            if (!strcmp(g_StaticInvokeCmdMap[i].szStringVerb, (LPSTR)Verb))
+            {
+                *idCmd = g_StaticInvokeCmdMap[i].IntVerb;
+                return TRUE;
+            }
+        }
     }
 
-    return E_FAIL;
+    return FALSE;
+}
+
+HRESULT
+CDefaultContextMenu::DoDynamicShellExtensions(
+    LPCMINVOKECOMMANDINFO lpcmi)
+{    
+    TRACE("verb %p first %x last %x", lpcmi->lpVerb, m_iIdSHEFirst, m_iIdSHELast);
+
+    UINT idCmd = LOWORD(lpcmi->lpVerb);
+    PDynamicShellEntry pEntry = GetDynamicEntry(idCmd);
+    if (!pEntry)
+        return E_FAIL;
+
+    /* invoke the dynamic context menu */
+    lpcmi->lpVerb = MAKEINTRESOURCEA(idCmd - pEntry->iIdCmdFirst);
+    return pEntry->pCM->InvokeCommand(lpcmi);
 }
 
 DWORD
 CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry)
 {
-    LPSHELLBROWSER lpSB;
+    CComPtr<IShellBrowser> psb;
     HWND hwndTree;
     LPCWSTR FlagsName;
     WCHAR wszKey[256];
@@ -1381,24 +1017,27 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticSh
     DWORD wFlags;
     DWORD cbVerb;
 
+    if (!m_site)
+        return 0;
+
     /* Get a pointer to the shell browser */
-    lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
-    if (lpSB == NULL)
+    hr = IUnknown_QueryService(m_site, SID_IShellBrowser, IID_PPV_ARG(IShellBrowser, &psb));
+    if (FAILED_UNEXPECTEDLY(hr))
         return 0;
 
     /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
-    if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
+    if (SUCCEEDED(psb->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
         FlagsName = L"ExplorerFlags";
     else
         FlagsName = L"BrowserFlags";
 
     /* Try to get the flag from the verb */
-    hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
-    if (!SUCCEEDED(hr))
+    hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", pEntry->szVerb);
+    if (FAILED_UNEXPECTEDLY(hr))
         return 0;
 
     cbVerb = sizeof(wFlags);
-    if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS)
+    if (RegGetValueW(pEntry->hkClass, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS)
     {
         return wFlags;
     }
@@ -1410,15 +1049,18 @@ HRESULT
 CDefaultContextMenu::TryToBrowse(
     LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags)
 {
-    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+    CComPtr<IShellBrowser> psb;
     HRESULT hr;
 
-    if (lpSB == NULL)
+    if (!m_site)
         return E_FAIL;
 
-    hr = lpSB->BrowseObject(ILCombine(m_pidlFolder, pidl), wFlags);
+    /* Get a pointer to the shell browser */
+    hr = IUnknown_QueryService(m_site, SID_IShellBrowser, IID_PPV_ARG(IShellBrowser, &psb));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return 0;
 
-    return hr;
+    return psb->BrowseObject(ILCombine(m_pidlFolder, pidl), wFlags);
 }
 
 HRESULT
@@ -1434,7 +1076,7 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl,
     BOOL bHasPath = SHGetPathFromIDListW(pidlFull, wszPath);
 
     WCHAR wszDir[MAX_PATH];
-    if(bHasPath)
+    if (bHasPath)
     {
         wcscpy(wszDir, wszPath);
         PathRemoveFileSpec(wszDir);
@@ -1444,9 +1086,6 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl,
         SHGetPathFromIDListW(m_pidlFolder, wszDir);
     }
 
-    HKEY hkeyClass;
-    RegOpenKeyExW(HKEY_CLASSES_ROOT, pEntry->szClass, 0, KEY_READ, &hkeyClass);
-
     SHELLEXECUTEINFOW sei;
     ZeroMemory(&sei, sizeof(sei));
     sei.cbSize = sizeof(sei);
@@ -1455,7 +1094,7 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl,
     sei.lpVerb = pEntry->szVerb;
     sei.lpDirectory = wszDir;
     sei.lpIDList = pidlFull;
-    sei.hkeyClass = hkeyClass;
+    sei.hkeyClass = pEntry->hkClass;
     sei.fMask = SEE_MASK_CLASSKEY | SEE_MASK_IDLIST;
     if (bHasPath)
     {
@@ -1464,8 +1103,6 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl,
 
     ShellExecuteExW(&sei);
 
-    RegCloseKey(hkeyClass);
-
     ILFree(pidlFull);
 
     return S_OK;
@@ -1520,57 +1157,82 @@ WINAPI
 CDefaultContextMenu::InvokeCommand(
     LPCMINVOKECOMMANDINFO lpcmi)
 {
-    switch(LOWORD(lpcmi->lpVerb))
-    {
-        case FCIDM_SHVIEW_BIGICON:
-        case FCIDM_SHVIEW_SMALLICON:
-        case FCIDM_SHVIEW_LISTVIEW:
-        case FCIDM_SHVIEW_REPORTVIEW:
-        case 0x30: /* FIX IDS in resource files */
-        case 0x31:
-        case 0x32:
-        case 0x33:
-        case FCIDM_SHVIEW_AUTOARRANGE:
-        case FCIDM_SHVIEW_SNAPTOGRID:
-            return NotifyShellViewWindow(lpcmi, FALSE);
-        case FCIDM_SHVIEW_REFRESH:
-            return DoRefresh(lpcmi);
-        case FCIDM_SHVIEW_INSERT:
-            return DoPaste(lpcmi, FALSE);
-        case FCIDM_SHVIEW_INSERTLINK:
-            return DoPaste(lpcmi, TRUE);
-        case FCIDM_SHVIEW_OPEN:
-        case FCIDM_SHVIEW_EXPLORE:
-            return DoOpenOrExplore(lpcmi);
-        case FCIDM_SHVIEW_COPY:
-        case FCIDM_SHVIEW_CUT:
-            return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
-        case FCIDM_SHVIEW_CREATELINK:
-            return DoCreateLink(lpcmi);
-        case FCIDM_SHVIEW_DELETE:
-            return DoDelete(lpcmi);
-        case FCIDM_SHVIEW_RENAME:
-            return DoRename(lpcmi);
-        case FCIDM_SHVIEW_PROPERTIES:
-            return DoProperties(lpcmi);
-        case 0x7ABC:
-            return DoFormat(lpcmi);
-    }
+    CMINVOKECOMMANDINFO LocalInvokeInfo;
+    HRESULT Result;
+    UINT CmdId;
+
+    /* Take a local copy of the fixed members of the
+       struct as we might need to modify the verb */
+    LocalInvokeInfo = *lpcmi;
+
+    /* Check if this is a string verb */
+    if (HIWORD(LocalInvokeInfo.lpVerb))
+    {
+        /* Get the ID which corresponds to this verb, and update our local copy */
+        if (MapVerbToCmdId((LPVOID)LocalInvokeInfo.lpVerb, &CmdId, FALSE))
+            LocalInvokeInfo.lpVerb = MAKEINTRESOURCEA(CmdId);
+    }
+
+    /* Check if this is a Id */
+    switch (LOWORD(LocalInvokeInfo.lpVerb))
+    {
+    case FCIDM_SHVIEW_INSERT:
+        Result = DoPaste(&LocalInvokeInfo, FALSE);
+        break;
+    case FCIDM_SHVIEW_INSERTLINK:
+        Result = DoPaste(&LocalInvokeInfo, TRUE);
+        break;
+    case FCIDM_SHVIEW_OPEN:
+    case FCIDM_SHVIEW_EXPLORE:
+        Result = DoOpenOrExplore(&LocalInvokeInfo);
+        break;
+    case FCIDM_SHVIEW_COPY:
+    case FCIDM_SHVIEW_CUT:
+        Result = DoCopyOrCut(&LocalInvokeInfo, LOWORD(LocalInvokeInfo.lpVerb) == FCIDM_SHVIEW_COPY);
+        break;
+    case FCIDM_SHVIEW_CREATELINK:
+        Result = DoCreateLink(&LocalInvokeInfo);
+        break;
+    case FCIDM_SHVIEW_DELETE:
+        Result = DoDelete(&LocalInvokeInfo);
+        break;
+    case FCIDM_SHVIEW_RENAME:
+        Result = DoRename(&LocalInvokeInfo);
+        break;
+    case FCIDM_SHVIEW_PROPERTIES:
+        Result = DoProperties(&LocalInvokeInfo);
+        break;
+    case FCIDM_SHVIEW_NEWFOLDER:
+        Result = DoCreateNewFolder(&LocalInvokeInfo);
+        break;
+    default:
+
+        _DoCallback(DFM_INVOKECOMMAND, LOWORD(LocalInvokeInfo.lpVerb), NULL);
+
+        Result = E_UNEXPECTED;
+        break;
+    }
+
+    /* Check for ID's we didn't find a handler for */
+    if (Result == E_UNEXPECTED)
+    {
+        if (m_iIdSHEFirst && m_iIdSHELast)
+        {
+            if (LOWORD(LocalInvokeInfo.lpVerb) >= m_iIdSHEFirst && LOWORD(LocalInvokeInfo.lpVerb) <= m_iIdSHELast)
+                Result = DoDynamicShellExtensions(&LocalInvokeInfo);
+        }
 
-    if (m_iIdSHEFirst && m_iIdSHELast)
-    {
-        if (LOWORD(lpcmi->lpVerb) >= m_iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSHELast)
-            return DoDynamicShellExtensions(lpcmi);
+        if (m_iIdSCMFirst && m_iIdSCMLast)
+        {
+            if (LOWORD(LocalInvokeInfo.lpVerb) >= m_iIdSCMFirst && LOWORD(LocalInvokeInfo.lpVerb) <= m_iIdSCMLast)
+                Result = DoStaticShellExtensions(&LocalInvokeInfo);
+        }
     }
 
-    if (m_iIdSCMFirst && m_iIdSCMLast)
-    {
-        if (LOWORD(lpcmi->lpVerb) >= m_iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSCMLast)
-            return DoStaticShellExtensions(lpcmi);
-    }
+    if (Result == E_UNEXPECTED)
+        FIXME("Unhandled Verb %xl\n", LOWORD(LocalInvokeInfo.lpVerb));
 
-    FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi->lpVerb));
-    return E_UNEXPECTED;
+    return Result;
 }
 
 HRESULT
@@ -1582,7 +1244,36 @@ CDefaultContextMenu::GetCommandString(
     LPSTR lpszName,
     UINT uMaxNameLen)
 {
-    return S_OK;
+    /* We don't handle the help text yet */
+    if (uFlags == GCS_HELPTEXTA ||
+        uFlags == GCS_HELPTEXTW)
+    {
+        return E_NOTIMPL;
+    }
+
+    /* Loop looking for a matching Id */
+    for (UINT i = 0; i < _countof(g_StaticInvokeCmdMap); i++)
+    {
+        if (g_StaticInvokeCmdMap[i].IntVerb == idCommand)
+        {
+            /* Validation just returns S_OK on a match */
+            if (uFlags == GCS_VALIDATEA || uFlags == GCS_VALIDATEW)
+                return S_OK;
+
+            /* Return a copy of the ANSI verb */
+            if (uFlags == GCS_VERBA)
+                return StringCchCopyA(lpszName, uMaxNameLen, g_StaticInvokeCmdMap[i].szStringVerb);
+
+            /* Convert the ANSI verb to unicode and return that */
+            if (uFlags == GCS_VERBW)
+            {
+                if (SHAnsiToUnicode(g_StaticInvokeCmdMap[i].szStringVerb, (LPWSTR)lpszName, uMaxNameLen))
+                    return S_OK;
+            }
+        }
+    }
+
+    return E_INVALIDARG;
 }
 
 HRESULT
@@ -1592,47 +1283,80 @@ CDefaultContextMenu::HandleMenuMsg(
     WPARAM wParam,
     LPARAM lParam)
 {
+    /* FIXME: Should we implement this as well? */
     return S_OK;
 }
 
-static
-HRESULT
-IDefaultContextMenu_Constructor(
-    const DEFCONTEXTMENU *pdcm,
-    REFIID riid,
-    void **ppv)
+HRESULT 
+WINAPI 
+CDefaultContextMenu::HandleMenuMsg2(
+    UINT uMsg, 
+    WPARAM wParam, 
+    LPARAM lParam, 
+    LRESULT *plResult)
 {
-    if (ppv == NULL)
-        return E_POINTER;
-    *ppv = NULL;
-
-    CComObject<CDefaultContextMenu> *pCM;
-    HRESULT hr = CComObject<CDefaultContextMenu>::CreateInstance(&pCM);
-    if (FAILED(hr))
-        return hr;
-    pCM->AddRef(); // CreateInstance returns object with 0 ref count */
-
-    CComPtr<IUnknown> pResult;
-    hr = pCM->QueryInterface(riid, (void **)&pResult);
-    if (FAILED(hr))
+    switch (uMsg)
     {
-        pCM->Release();
-        return hr;
+    case WM_INITMENUPOPUP:
+    {
+        PDynamicShellEntry pEntry = m_pDynamicEntries;
+        while (pEntry)
+        {
+            SHForwardContextMenuMsg(pEntry->pCM, uMsg, wParam, lParam, plResult, TRUE);
+            pEntry = pEntry->pNext;
+        }
+        break;
     }
-
-    hr = pCM->Initialize(pdcm);
-    if (FAILED(hr))
+    case WM_DRAWITEM:
     {
-        pCM->Release();
-        return hr;
+        DRAWITEMSTRUCT* pDrawStruct = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
+        PDynamicShellEntry pEntry = GetDynamicEntry(pDrawStruct->itemID);
+        if (pEntry)
+            SHForwardContextMenuMsg(pEntry->pCM, uMsg, wParam, lParam, plResult, TRUE);
+        break;
+    }
+    case WM_MEASUREITEM:
+    {
+        MEASUREITEMSTRUCT* pMeasureStruct = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
+        PDynamicShellEntry pEntry = GetDynamicEntry(pMeasureStruct->itemID);
+        if (pEntry)
+            SHForwardContextMenuMsg(pEntry->pCM, uMsg, wParam, lParam, plResult, TRUE);
+        break;
+    }
+    case WM_MENUCHAR :
+        /* FIXME */
+        break;
+    default:
+        ERR("Got unknown message:%d\n", uMsg);
     }
+   return S_OK;
+}
 
-    *ppv = pResult.Detach();
-    pCM->Release();
-    TRACE("This(%p) cidl %u\n", *ppv, pdcm->cidl);
+HRESULT
+WINAPI
+CDefaultContextMenu::SetSite(IUnknown *pUnkSite)
+{
+    m_site = pUnkSite;
     return S_OK;
 }
 
+HRESULT 
+WINAPI 
+CDefaultContextMenu::GetSite(REFIID riid, void **ppvSite)
+{
+    if (!m_site)
+        return E_FAIL;
+
+    return m_site->QueryInterface(riid, ppvSite);
+}
+
+static
+HRESULT
+CDefaultContextMenu_CreateInstance(const DEFCONTEXTMENU *pdcm, LPFNDFMCALLBACK lpfn, REFIID riid, void **ppv)
+{
+    return ShellObjectCreatorInit<CDefaultContextMenu>(pdcm, lpfn, riid, ppv);
+}
+
 /*************************************************************************
  * SHCreateDefaultContextMenu            [SHELL32.325] Vista API
  *
@@ -1640,17 +1364,13 @@ IDefaultContextMenu_Constructor(
 
 HRESULT
 WINAPI
-SHCreateDefaultContextMenu(
-    const DEFCONTEXTMENU *pdcm,
-    REFIID riid,
-    void **ppv)
+SHCreateDefaultContextMenu(const DEFCONTEXTMENU *pdcm, REFIID riid, void **ppv)
 {
-    *ppv = NULL;
-    HRESULT hr = IDefaultContextMenu_Constructor(pdcm, riid, ppv);
-    if (FAILED(hr))
-        ERR("IDefaultContextMenu_Constructor failed: %x\n", hr);
-    TRACE("pcm %p hr %x\n", pdcm, hr);
-    return hr;
+    HRESULT hr = CDefaultContextMenu_CreateInstance(pdcm, NULL, riid, ppv);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    return S_OK;
 }
 
 /*************************************************************************
@@ -1661,28 +1381,30 @@ SHCreateDefaultContextMenu(
 HRESULT
 WINAPI
 CDefFolderMenu_Create2(
-    LPCITEMIDLIST pidlFolder,
+    PCIDLIST_ABSOLUTE pidlFolder,
     HWND hwnd,
     UINT cidl,
-    LPCITEMIDLIST *apidl,
+    PCUITEMID_CHILD_ARRAY apidl,
     IShellFolder *psf,
     LPFNDFMCALLBACK lpfn,
     UINT nKeys,
     const HKEY *ahkeyClsKeys,
     IContextMenu **ppcm)
 {
-    DEFCONTEXTMENU pdcm;
-    pdcm.hwnd = hwnd;
-    pdcm.pcmcb = NULL;
-    pdcm.pidlFolder = pidlFolder;
-    pdcm.psf = psf;
-    pdcm.cidl = cidl;
-    pdcm.apidl = apidl;
-    pdcm.punkAssociationInfo = NULL;
-    pdcm.cKeys = nKeys;
-    pdcm.aKeys = ahkeyClsKeys;
-
-    HRESULT hr = SHCreateDefaultContextMenu(&pdcm, IID_PPV_ARG(IContextMenu, ppcm));
-    return hr;
-}
+    DEFCONTEXTMENU dcm;
+    dcm.hwnd = hwnd;
+    dcm.pcmcb = NULL;
+    dcm.pidlFolder = pidlFolder;
+    dcm.psf = psf;
+    dcm.cidl = cidl;
+    dcm.apidl = apidl;
+    dcm.punkAssociationInfo = NULL;
+    dcm.cKeys = nKeys;
+    dcm.aKeys = ahkeyClsKeys;
+
+    HRESULT hr = CDefaultContextMenu_CreateInstance(&dcm, lpfn, IID_PPV_ARG(IContextMenu, ppcm));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
+    return S_OK;
+}