ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

defcontextmenu.cpp
Go to the documentation of this file.
00001 /*
00002  * PROJECT:     shell32
00003  * LICENSE:     GPL - See COPYING in the top level directory
00004  * FILE:        dll/win32/shell32/shv_item_new.c
00005  * PURPOSE:     provides default context menu implementation
00006  * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
00007  */
00008 
00009 /*
00010 TODO:
00011 1. In DoStaticShellExtensions, check for "Explore" and "Open" verbs, and for BrowserFlags or
00012     ExplorerFlags under those entries. These flags indicate if we should browse to the new item
00013     instead of attempting to open it.
00014 2. The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
00015     example of the wrong way to do it.
00016 */
00017 
00018 #include <precomp.h>
00019 
00020 WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
00021 
00022 typedef struct _DynamicShellEntry_
00023 {
00024     UINT iIdCmdFirst;
00025     UINT NumIds;
00026     CLSID ClassID;
00027     IContextMenu *pCM;
00028     struct _DynamicShellEntry_ *pNext;
00029 } DynamicShellEntry, *PDynamicShellEntry;
00030 
00031 typedef struct _StaticShellEntry_
00032 {
00033     LPWSTR szVerb;
00034     LPWSTR szClass;
00035     struct _StaticShellEntry_ *pNext;
00036 } StaticShellEntry, *PStaticShellEntry;
00037 
00038 class CDefaultContextMenu :
00039     public CComObjectRootEx<CComMultiThreadModelNoCS>,
00040     public IContextMenu2
00041 {
00042     private:
00043         DEFCONTEXTMENU m_Dcm;
00044         IDataObject *m_pDataObj;
00045         LPCITEMIDLIST m_pidlFolder;
00046         DWORD m_bGroupPolicyActive;
00047         PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */
00048         UINT m_iIdSHEFirst; /* first used id */
00049         UINT m_iIdSHELast; /* last used id */
00050         PStaticShellEntry m_pStaticEntries; /* first static shell extension entry */
00051         UINT m_iIdSCMFirst; /* first static used id */
00052         UINT m_iIdSCMLast; /* last static used id */
00053 
00054         void AddStaticEntry(LPCWSTR pwszVerb, LPCWSTR pwszClass);
00055         void AddStaticEntryForKey(HKEY hKey, LPCWSTR pwszClass);
00056         void AddStaticEntryForFileClass(LPCWSTR pwszExt);
00057         BOOL IsShellExtensionAlreadyLoaded(const CLSID *pclsid);
00058         HRESULT LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid);
00059         BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey);
00060         UINT InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast);
00061         UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
00062         UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
00063         UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
00064         HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi);
00065         HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
00066         HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
00067         HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
00068         HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy);
00069         HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
00070         HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
00071         HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
00072         HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
00073         HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
00074 
00075     public:
00076         CDefaultContextMenu();
00077         ~CDefaultContextMenu();
00078         HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm);
00079 
00080         // IContextMenu
00081         virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
00082         virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
00083         virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
00084 
00085         // IContextMenu2
00086         virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
00087 
00088         BEGIN_COM_MAP(CDefaultContextMenu)
00089         COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
00090         COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
00091         END_COM_MAP()
00092 };
00093 
00094 CDefaultContextMenu::CDefaultContextMenu()
00095 {
00096     memset(&m_Dcm, 0, sizeof(m_Dcm));
00097     m_pDataObj = NULL;
00098     m_pidlFolder = NULL;
00099     m_bGroupPolicyActive = 0;
00100     m_pDynamicEntries = NULL;
00101     m_iIdSHEFirst = 0;
00102     m_iIdSHELast = 0;
00103     m_pStaticEntries = NULL;
00104     m_iIdSCMFirst = 0;
00105     m_iIdSCMLast = 0;
00106 }
00107 
00108 CDefaultContextMenu::~CDefaultContextMenu()
00109 {
00110     /* Free dynamic shell extension entries */
00111     PDynamicShellEntry pDynamicEntry = m_pDynamicEntries, pNextDynamic;
00112     while (pDynamicEntry)
00113     {
00114         pNextDynamic = pDynamicEntry->pNext;
00115         pDynamicEntry->pCM->Release();
00116         HeapFree(GetProcessHeap(), 0, pDynamicEntry);
00117         pDynamicEntry = pNextDynamic;
00118     }
00119 
00120     /* Free static shell extension entries */
00121     PStaticShellEntry pStaticEntry = m_pStaticEntries, pNextStatic;
00122     while (pStaticEntry)
00123     {
00124         pNextStatic = pStaticEntry->pNext;
00125         HeapFree(GetProcessHeap(), 0, pStaticEntry->szClass);
00126         HeapFree(GetProcessHeap(), 0, pStaticEntry->szVerb);
00127         HeapFree(GetProcessHeap(), 0, pStaticEntry);
00128         pStaticEntry = pNextStatic;
00129     }
00130 
00131     if (m_pidlFolder)
00132         ILFree((_ITEMIDLIST*)m_pidlFolder);
00133     if (m_pDataObj)
00134         m_pDataObj->Release();
00135 }
00136 
00137 HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
00138 {
00139     IDataObject *pDataObj;
00140 
00141     TRACE("cidl %u\n", pdcm->cidl);
00142     if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_IDataObject, (void**)&pDataObj)))
00143         m_pDataObj = pDataObj;
00144 
00145     if (!pdcm->cidl)
00146     {
00147         /* Init pidlFolder only if it is background context menu. See IShellExtInit::Initialize */
00148         if (pdcm->pidlFolder)
00149             m_pidlFolder = ILClone(pdcm->pidlFolder);
00150         else
00151         {
00152             IPersistFolder2 *pf = NULL;
00153             if (SUCCEEDED(pdcm->psf->QueryInterface(IID_IPersistFolder2, (PVOID*)&pf)))
00154             {
00155                 if (FAILED(pf->GetCurFolder((_ITEMIDLIST**)&m_pidlFolder)))
00156                     ERR("GetCurFolder failed\n");
00157                 pf->Release();
00158             }
00159         }
00160         TRACE("pidlFolder %p\n", m_pidlFolder);
00161     }
00162 
00163     CopyMemory(&m_Dcm, pdcm, sizeof(DEFCONTEXTMENU));
00164     return S_OK;
00165 }
00166 
00167 void
00168 CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
00169 {
00170     PStaticShellEntry pEntry = m_pStaticEntries, pLastEntry = NULL;
00171     while(pEntry)
00172     {
00173         if (!wcsicmp(pEntry->szVerb, szVerb))
00174         {
00175             /* entry already exists */
00176             return;
00177         }
00178         pLastEntry = pEntry;
00179         pEntry = pEntry->pNext;
00180     }
00181 
00182     TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
00183 
00184     pEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
00185     if (pEntry)
00186     {
00187         pEntry->pNext = NULL;
00188         pEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb) + 1) * sizeof(WCHAR));
00189         if (pEntry->szVerb)
00190             wcscpy(pEntry->szVerb, szVerb);
00191         pEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass) + 1) * sizeof(WCHAR));
00192         if (pEntry->szClass)
00193             wcscpy(pEntry->szClass, szClass);
00194     }
00195 
00196     if (!wcsicmp(szVerb, L"open"))
00197     {
00198         /* open verb is always inserted in front */
00199         pEntry->pNext = m_pStaticEntries;
00200         m_pStaticEntries = pEntry;
00201     }
00202     else if (pLastEntry)
00203         pLastEntry->pNext = pEntry;
00204     else
00205         m_pStaticEntries = pEntry;
00206 }
00207 
00208 void
00209 CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey, const WCHAR *pwszClass)
00210 {
00211     WCHAR wszName[40];
00212     DWORD cchName, dwIndex = 0;
00213 
00214     TRACE("AddStaticEntryForKey %x %ls\n", hKey, pwszClass);
00215 
00216     while(TRUE)
00217     {
00218         cchName = _countof(wszName);
00219         if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
00220             break;
00221 
00222         AddStaticEntry(wszName, pwszClass);
00223     }
00224 }
00225 
00226 void
00227 CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR * szExt)
00228 {
00229     WCHAR szBuffer[100];
00230     HKEY hKey;
00231     LONG result;
00232     DWORD dwBuffer;
00233     UINT Length;
00234     static WCHAR szShell[] = L"\\shell";
00235     static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
00236 
00237     TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt));
00238 
00239     Length = wcslen(szExt);
00240     if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
00241     {
00242         wcscpy(szBuffer, szExt);
00243         wcscpy(&szBuffer[Length], szShell);
00244         result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
00245         if (result == ERROR_SUCCESS)
00246         {
00247             szBuffer[Length] = 0;
00248             AddStaticEntryForKey(hKey, szExt);
00249             RegCloseKey(hKey);
00250         }
00251     }
00252 
00253     dwBuffer = sizeof(szBuffer);
00254     result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer);
00255     if (result == ERROR_SUCCESS)
00256     {
00257         Length = wcslen(szBuffer);
00258         if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
00259         {
00260             wcscpy(&szBuffer[Length], szShell);
00261             TRACE("szBuffer %s\n", debugstr_w(szBuffer));
00262 
00263             result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
00264             if (result == ERROR_SUCCESS)
00265             {
00266                 szBuffer[Length] = 0;
00267                 AddStaticEntryForKey(hKey, szBuffer);
00268                 RegCloseKey(hKey);
00269             }
00270         }
00271     }
00272 
00273     wcscpy(szBuffer, szShellAssoc);
00274     dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR);
00275     result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer);
00276     if (result == ERROR_SUCCESS)
00277     {
00278         Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc);
00279         wcscat(szBuffer, L"\\shell");
00280         TRACE("szBuffer %s\n", debugstr_w(szBuffer));
00281 
00282         result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
00283         if (result == ERROR_SUCCESS)
00284         {
00285             szBuffer[Length] = 0;
00286             AddStaticEntryForKey(hKey, szBuffer);
00287             RegCloseKey(hKey);
00288         }
00289     }
00290 }
00291 
00292 static
00293 BOOL
00294 HasClipboardData()
00295 {
00296     BOOL bRet = FALSE;
00297     IDataObject *pDataObj;
00298 
00299     if(SUCCEEDED(OleGetClipboard(&pDataObj)))
00300     {
00301         STGMEDIUM medium;
00302         FORMATETC formatetc;
00303 
00304         TRACE("pDataObj=%p\n", pDataObj);
00305 
00306         /* Set the FORMATETC structure*/
00307         InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
00308         if(SUCCEEDED(pDataObj->GetData(&formatetc, &medium)))
00309         {
00310             bRet = TRUE;
00311             ReleaseStgMedium(&medium);
00312         }
00313 
00314         pDataObj->Release();
00315     }
00316 
00317     return bRet;
00318 }
00319 
00320 static
00321 VOID
00322 DisablePasteOptions(HMENU hMenu)
00323 {
00324     MENUITEMINFOW mii;
00325 
00326     mii.cbSize = sizeof(mii);
00327     mii.fMask = MIIM_STATE;
00328     mii.fState = MFS_DISABLED;
00329 
00330     TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii));
00331     TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii));
00332 }
00333 
00334 BOOL
00335 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID *pclsid)
00336 {
00337     PDynamicShellEntry pEntry = m_pDynamicEntries;
00338 
00339     while (pEntry)
00340     {
00341         if (!memcmp(&pEntry->ClassID, pclsid, sizeof(CLSID)))
00342             return TRUE;
00343         pEntry = pEntry->pNext;
00344     }
00345 
00346     return FALSE;
00347 }
00348 
00349 HRESULT
00350 CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid)
00351 {
00352     HRESULT hr;
00353 
00354     TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey, wine_dbgstr_guid(pclsid));
00355 
00356     if (IsShellExtensionAlreadyLoaded(pclsid))
00357         return S_OK;
00358 
00359     IContextMenu *pcm;
00360     hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_IContextMenu, (void**)&pcm);
00361     if (hr != S_OK)
00362     {
00363         ERR("SHCoCreateInstance failed %x\n", GetLastError());
00364         return hr;
00365     }
00366 
00367     IShellExtInit *pExtInit;
00368     hr = pcm->QueryInterface(IID_IShellExtInit, (void**)&pExtInit);
00369     if (hr != S_OK)
00370     {
00371         ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
00372         pcm->Release();
00373         return hr;
00374     }
00375 
00376     hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey);
00377     pExtInit->Release();
00378     if (hr != S_OK)
00379     {
00380         TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
00381         pcm->Release();
00382         return hr;
00383     }
00384 
00385     PDynamicShellEntry pEntry = (DynamicShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
00386     if (!pEntry)
00387     {
00388         pcm->Release();
00389         return E_OUTOFMEMORY;
00390     }
00391 
00392     pEntry->iIdCmdFirst = 0;
00393     pEntry->pNext = NULL;
00394     pEntry->NumIds = 0;
00395     pEntry->pCM = pcm;
00396     memcpy(&pEntry->ClassID, pclsid, sizeof(CLSID));
00397 
00398     if (m_pDynamicEntries)
00399     {
00400         PDynamicShellEntry pLastEntry = m_pDynamicEntries;
00401 
00402         while (pLastEntry->pNext)
00403             pLastEntry = pLastEntry->pNext;
00404 
00405         pLastEntry->pNext = pEntry;
00406     }
00407     else
00408         m_pDynamicEntries = pEntry;
00409 
00410     return S_OK;
00411 }
00412 
00413 BOOL
00414 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
00415 {
00416     
00417     WCHAR wszName[MAX_PATH], wszBuf[MAX_PATH], *pwszClsid;
00418     DWORD cchName;
00419     HRESULT hr;
00420     HKEY hKey;
00421 
00422     if (RegOpenKeyExW(hRootKey, L"shellex\\ContextMenuHandlers", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
00423     {
00424         TRACE("RegOpenKeyExW failed\n");
00425         return FALSE;
00426     }
00427 
00428     DWORD dwIndex = 0;
00429     while (TRUE)
00430     {
00431         cchName = _countof(wszName);
00432         if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
00433             break;
00434 
00435         /* Key name or key value is CLSID */
00436         CLSID clsid;
00437         hr = CLSIDFromString(wszName, &clsid);
00438         if (hr == S_OK)
00439             pwszClsid = wszName;
00440         else
00441         {
00442             DWORD cchBuf = _countof(wszBuf);
00443             if (RegGetValueW(hKey, wszName, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &cchBuf) == ERROR_SUCCESS)
00444                 hr = CLSIDFromString(wszBuf, &clsid);
00445             pwszClsid = wszBuf;
00446         }
00447         if (SUCCEEDED(hr))
00448         {
00449             if (m_bGroupPolicyActive)
00450             {
00451                 if (RegGetValueW(HKEY_LOCAL_MACHINE,
00452                                 L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
00453                                 pwszClsid,
00454                                 RRF_RT_REG_SZ,
00455                                 NULL,
00456                                 NULL,
00457                                 NULL) == ERROR_SUCCESS)
00458                 {
00459                     LoadDynamicContextMenuHandler(hKey, &clsid);
00460                 }
00461             }
00462             else
00463                 LoadDynamicContextMenuHandler(hKey, &clsid);
00464         }
00465     }
00466 
00467     RegCloseKey(hKey);
00468     return TRUE;
00469 }
00470 
00471 UINT
00472 CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast)
00473 {
00474     if (!m_pDynamicEntries)
00475     {
00476         m_iIdSHEFirst = 0;
00477         m_iIdSHELast = 0;
00478         return IndexMenu;
00479     }
00480 
00481     PDynamicShellEntry pEntry = m_pDynamicEntries;
00482     idCmdFirst = 0x5000;
00483     idCmdLast =  0x6000;
00484     m_iIdSHEFirst = idCmdFirst;
00485     do
00486     {
00487         HRESULT hr = pEntry->pCM->QueryContextMenu(hMenu, IndexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL);
00488         if (SUCCEEDED(hr))
00489         {
00490             pEntry->iIdCmdFirst = idCmdFirst;
00491             pEntry->NumIds = LOWORD(hr);
00492             IndexMenu += pEntry->NumIds;
00493             idCmdFirst += pEntry->NumIds + 0x10;
00494         }
00495         TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry, hr, pEntry->pCM, pEntry->iIdCmdFirst, pEntry->NumIds);
00496         pEntry = pEntry->pNext;
00497     } while (pEntry);
00498 
00499     m_iIdSHELast = idCmdFirst;
00500     TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst, m_iIdSHELast);
00501     return IndexMenu;
00502 }
00503 
00504 UINT
00505 CDefaultContextMenu::BuildBackgroundContextMenu(
00506     HMENU hMenu,
00507     UINT iIdCmdFirst,
00508     UINT iIdCmdLast,
00509     UINT uFlags)
00510 {
00511     UINT IndexMenu = 0;
00512     HMENU hSubMenu;
00513 
00514     TRACE("BuildBackgroundContextMenu entered\n");
00515 
00516     if (!_ILIsDesktop(m_pidlFolder))
00517     {
00518         WCHAR wszBuf[MAX_PATH];
00519 
00520         /* view option is only available in browsing mode */
00521         hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
00522         if (hSubMenu && LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, wszBuf, _countof(wszBuf)))
00523         {
00524             TRACE("wszBuf %s\n", debugstr_w(wszBuf));
00525 
00526             MENUITEMINFOW mii;
00527             ZeroMemory(&mii, sizeof(mii));
00528             mii.cbSize = sizeof(mii);
00529             mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
00530             mii.fType = MFT_STRING;
00531             mii.wID = iIdCmdFirst++;
00532             mii.dwTypeData = wszBuf;
00533             mii.cch = wcslen(mii.dwTypeData);
00534             mii.fState = MFS_ENABLED;
00535             mii.hSubMenu = hSubMenu;
00536             InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
00537             DestroyMenu(hSubMenu);
00538         }
00539     }
00540 
00541     hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002");
00542     if (hSubMenu)
00543     {
00544         /* merge general background context menu in */
00545         iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), IndexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1;
00546         DestroyMenu(hSubMenu);
00547     }
00548 
00549     if (!HasClipboardData())
00550     {
00551         TRACE("disabling paste options\n");
00552         DisablePasteOptions(hMenu);
00553     }
00554 
00555     /* Directory is progid of filesystem folders only */
00556     LPITEMIDLIST pidlFolderLast = ILFindLastID(m_pidlFolder);
00557     if (_ILIsDesktop(pidlFolderLast) || _ILIsDrive(pidlFolderLast) || _ILIsFolder(pidlFolderLast))
00558     {
00559         /* Load context menu handlers */
00560         TRACE("Add background handlers: %p\n", m_pidlFolder);
00561         HKEY hKey;
00562         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory\\Background", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00563         {
00564             EnumerateDynamicContextHandlerForKey(hKey);
00565             RegCloseKey(hKey);
00566         }
00567 
00568         if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu, GetMenuItemCount(hMenu) - 1, iIdCmdFirst, iIdCmdLast))
00569         {
00570             /* seperate dynamic context menu items */
00571             _InsertMenuItemW(hMenu, GetMenuItemCount(hMenu) - 1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
00572         }
00573     }
00574 
00575     return iIdCmdLast;
00576 }
00577 
00578 UINT
00579 CDefaultContextMenu::AddStaticContextMenusToMenu(
00580     HMENU hMenu,
00581     UINT IndexMenu)
00582 {
00583     MENUITEMINFOW mii;
00584     UINT idResource;
00585     WCHAR wszVerb[40];
00586     UINT fState;
00587 
00588     mii.cbSize = sizeof(mii);
00589     mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
00590     mii.fType = MFT_STRING;
00591     mii.wID = 0x4000;
00592     mii.dwTypeData = NULL;
00593     m_iIdSCMFirst = mii.wID;
00594 
00595     PStaticShellEntry pEntry = m_pStaticEntries;
00596 
00597     while (pEntry)
00598     {
00599         fState = MFS_ENABLED;
00600         mii.dwTypeData = NULL;
00601 
00602         if (!wcsicmp(pEntry->szVerb, L"open"))
00603         {
00604             fState |= MFS_DEFAULT;
00605             idResource = IDS_OPEN_VERB;
00606         }
00607         else if (!wcsicmp(pEntry->szVerb, L"explore"))
00608             idResource = IDS_EXPLORE_VERB;
00609         else if (!wcsicmp(pEntry->szVerb, L"runas"))
00610             idResource = IDS_RUNAS_VERB;
00611         else if (!wcsicmp(pEntry->szVerb, L"edit"))
00612             idResource = IDS_EDIT_VERB;
00613         else if (!wcsicmp(pEntry->szVerb, L"find"))
00614             idResource = IDS_FIND_VERB;
00615         else if (!wcsicmp(pEntry->szVerb, L"print"))
00616             idResource = IDS_PRINT_VERB;
00617         else if (!wcsicmp(pEntry->szVerb, L"printto"))
00618         {
00619             pEntry = pEntry->pNext;
00620             continue;
00621         }
00622         else
00623             idResource = 0;
00624 
00625         /* By default use verb for menu item name */
00626         mii.dwTypeData = pEntry->szVerb;
00627 
00628         if (idResource > 0)
00629         {
00630             if (LoadStringW(shell32_hInstance, idResource, wszVerb, _countof(wszVerb)))
00631                 mii.dwTypeData = wszVerb; /* use translated verb */
00632             else
00633                 ERR("Failed to load string\n");
00634         }
00635         else
00636         {
00637             WCHAR wszKey[256];
00638             HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
00639             
00640             if (SUCCEEDED(hr))
00641             {
00642                 DWORD cbVerb = sizeof(wszVerb);
00643 
00644                 if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, NULL, RRF_RT_REG_SZ, NULL, wszVerb, &cbVerb) == ERROR_SUCCESS)
00645                     mii.dwTypeData = wszVerb; /* use description for the menu entry */
00646             }
00647         }
00648 
00649         mii.cch = wcslen(mii.dwTypeData);
00650         mii.fState = fState;
00651         InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
00652 
00653         mii.wID++;
00654         pEntry = pEntry->pNext;
00655     }
00656 
00657     m_iIdSCMLast = mii.wID - 1;
00658     return IndexMenu;
00659 }
00660 
00661 void WINAPI _InsertMenuItemW(
00662     HMENU hMenu,
00663     UINT indexMenu,
00664     BOOL fByPosition,
00665     UINT wID,
00666     UINT fType,
00667     LPCWSTR dwTypeData,
00668     UINT fState)
00669 {
00670     MENUITEMINFOW mii;
00671     WCHAR wszText[100];
00672 
00673     ZeroMemory(&mii, sizeof(mii));
00674     mii.cbSize = sizeof(mii);
00675     if (fType == MFT_SEPARATOR)
00676         mii.fMask = MIIM_ID | MIIM_TYPE;
00677     else if (fType == MFT_STRING)
00678     {
00679         mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
00680         if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
00681         {
00682             if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), wszText, _countof(wszText)))
00683                 mii.dwTypeData = wszText;
00684             else
00685             {
00686                 ERR("failed to load string %p\n", dwTypeData);
00687                 return;
00688             }
00689         }
00690         else
00691             mii.dwTypeData = (LPWSTR)dwTypeData;
00692         mii.fState = fState;
00693     }
00694 
00695     mii.wID = wID;
00696     mii.fType = fType;
00697     InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
00698 }
00699 
00700 UINT
00701 CDefaultContextMenu::BuildShellItemContextMenu(
00702     HMENU hMenu,
00703     UINT iIdCmdFirst,
00704     UINT iIdCmdLast,
00705     UINT uFlags)
00706 {
00707     HKEY hKey;
00708     HRESULT hr;
00709 
00710     TRACE("BuildShellItemContextMenu entered\n");
00711     ASSERT(m_Dcm.cidl >= 1);
00712 
00713     STRRET strFile;
00714     hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
00715     if (hr == S_OK)
00716     {
00717         WCHAR wszPath[MAX_PATH];
00718         hr = StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath));
00719         if (hr == S_OK)
00720         {
00721             LPCWSTR pwszExt = PathFindExtensionW(wszPath);
00722             if (pwszExt[0])
00723             {
00724                 /* enumerate dynamic/static for a given file class */
00725                 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00726                 {
00727                     /* add static verbs */
00728                     AddStaticEntryForFileClass(pwszExt);
00729 
00730                     /* load dynamic extensions from file extension key */
00731                     EnumerateDynamicContextHandlerForKey(hKey);
00732                     RegCloseKey(hKey);
00733                 }
00734 
00735                 WCHAR wszTemp[40];
00736                 DWORD dwSize = sizeof(wszTemp);
00737                 if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
00738                 {
00739                     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00740                     {
00741                         /* add static verbs from progid key */
00742                         AddStaticEntryForFileClass(wszTemp);
00743 
00744                         /* load dynamic extensions from progid key */
00745                         EnumerateDynamicContextHandlerForKey(hKey);
00746                         RegCloseKey(hKey);
00747                     }
00748                 }
00749             }
00750 
00751             if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00752             {
00753                 /* load default extensions */
00754                 EnumerateDynamicContextHandlerForKey(hKey);
00755                 RegCloseKey(hKey);
00756             }
00757         }
00758     }
00759     else
00760         ERR("GetDisplayNameOf failed: %x\n", hr);
00761 
00762     GUID *pGuid = _ILGetGUIDPointer(m_Dcm.apidl[0]);
00763     if (pGuid)
00764     {
00765         LPOLESTR pwszCLSID;
00766         WCHAR buffer[60];
00767 
00768         wcscpy(buffer, L"CLSID\\");
00769         hr = StringFromCLSID(*pGuid, &pwszCLSID);
00770         if (hr == S_OK)
00771         {
00772             wcscpy(&buffer[6], pwszCLSID);
00773             TRACE("buffer %s\n", debugstr_w(buffer));
00774             if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00775             {
00776                 EnumerateDynamicContextHandlerForKey(hKey);
00777                 AddStaticEntryForFileClass(buffer);
00778                 RegCloseKey(hKey);
00779             }
00780             CoTaskMemFree(pwszCLSID);
00781         }
00782     }
00783 
00784     if (_ILIsDrive(m_Dcm.apidl[0]))
00785     {
00786         AddStaticEntryForFileClass(L"Drive");
00787         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00788         {
00789             EnumerateDynamicContextHandlerForKey(hKey);
00790             RegCloseKey(hKey);
00791         }
00792 
00793     }
00794 
00795     /* add static actions */
00796     SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
00797     hr = m_Dcm.psf->GetAttributesOf(m_Dcm.cidl, m_Dcm.apidl, &rfg);
00798     if (FAILED(hr))
00799     {
00800         ERR("GetAttributesOf failed: %x\n", hr);
00801         rfg = 0;
00802     }
00803 
00804     if (rfg & SFGAO_FOLDER)
00805     {
00806         /* add the default verbs open / explore */
00807         AddStaticEntryForFileClass(L"Folder");
00808         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00809         {
00810             EnumerateDynamicContextHandlerForKey(hKey);
00811             RegCloseKey(hKey);
00812         }
00813 
00814         /* Directory is only loaded for real filesystem directories */
00815         if (_ILIsFolder(m_Dcm.apidl[0]))
00816         {
00817             AddStaticEntryForFileClass(L"Directory");
00818             if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00819             {
00820                 EnumerateDynamicContextHandlerForKey(hKey);
00821                 RegCloseKey(hKey);
00822             }
00823         }
00824     }
00825 
00826     /* AllFilesystemObjects class is loaded only for files and directories */
00827     if (_ILIsFolder(m_Dcm.apidl[0]) || _ILIsValue(m_Dcm.apidl[0]))
00828     {
00829         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00830         {
00831             /* sendto service is registered here */
00832             EnumerateDynamicContextHandlerForKey(hKey);
00833             RegCloseKey(hKey);
00834         }
00835     }
00836 
00837     /* add static context menu handlers */
00838     UINT IndexMenu = AddStaticContextMenusToMenu(hMenu, 0);
00839 
00840     /* now process dynamic context menu handlers */
00841     BOOL bAddSep = FALSE;
00842     IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, iIdCmdFirst, iIdCmdLast);
00843     TRACE("IndexMenu %d\n", IndexMenu);
00844 
00845     if (_ILIsDrive(m_Dcm.apidl[0]))
00846     {
00847         /* The 'Format' option must be always available,
00848          * thus it is not registered as a static shell extension */
00849         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
00850         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
00851         bAddSep = TRUE;
00852     }
00853 
00854     BOOL bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM));
00855     if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData)
00856     {
00857         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
00858         if (rfg & SFGAO_CANMOVE)
00859             _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_ENABLED);
00860         if (rfg & SFGAO_CANCOPY)
00861             _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, MAKEINTRESOURCEW(IDS_COPY), MFS_ENABLED);
00862         if (bClipboardData)
00863             _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_INSERT, MFT_STRING, MAKEINTRESOURCEW(IDS_INSERT), MFS_ENABLED);
00864 
00865         bAddSep = TRUE;
00866     }
00867 
00868     if (rfg & SFGAO_CANLINK)
00869     {
00870         bAddSep = FALSE;
00871         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
00872         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
00873     }
00874 
00875     if (rfg & SFGAO_CANDELETE)
00876     {
00877         if (bAddSep)
00878         {
00879             bAddSep = FALSE;
00880             _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
00881         }
00882         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), MFS_ENABLED);
00883     }
00884 
00885     if (rfg & SFGAO_CANRENAME)
00886     {
00887         if (bAddSep)
00888         {
00889             _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
00890         }
00891         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_RENAME), MFS_ENABLED);
00892         bAddSep = TRUE;
00893     }
00894 
00895     if (rfg & SFGAO_HASPROPSHEET)
00896     {
00897         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
00898         _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
00899     }
00900 
00901     return iIdCmdLast;
00902 }
00903 
00904 HRESULT
00905 WINAPI
00906 CDefaultContextMenu::QueryContextMenu(
00907     HMENU hMenu,
00908     UINT IndexMenu,
00909     UINT idCmdFirst,
00910     UINT idCmdLast,
00911     UINT uFlags)
00912 {
00913     if (m_Dcm.cidl)
00914         idCmdFirst = BuildShellItemContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
00915     else
00916         idCmdFirst = BuildBackgroundContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
00917 
00918     return S_OK;
00919 }
00920 
00921 static
00922 HRESULT
00923 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
00924 {
00925     /* Note: CWM_GETISHELLBROWSER returns not referenced object */
00926     LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
00927     if (!lpSB)
00928         return E_FAIL;
00929 
00930     LPSHELLVIEW lpSV = NULL;
00931     if (FAILED(lpSB->QueryActiveShellView(&lpSV)))
00932         return E_FAIL;
00933 
00934     if (LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_REFRESH || bRefresh)
00935         lpSV->Refresh();
00936     else
00937     {
00938         HWND hwndSV = NULL;
00939         if (SUCCEEDED(lpSV->GetWindow(&hwndSV)))
00940             SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
00941     }
00942 
00943     lpSV->Release();
00944     return S_OK;
00945 }
00946 
00947 HRESULT
00948 CDefaultContextMenu::DoPaste(
00949     LPCMINVOKECOMMANDINFO lpcmi)
00950 {
00951     HRESULT hr;
00952 
00953     IDataObject *pda;
00954     if (OleGetClipboard(&pda) != S_OK)
00955         return E_FAIL;
00956 
00957     STGMEDIUM medium;
00958     FORMATETC formatetc;
00959     InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
00960     hr = pda->GetData(&formatetc, &medium);
00961 
00962     if (FAILED(hr))
00963     {
00964         pda->Release();
00965         return E_FAIL;
00966     }
00967 
00968     /* lock the handle */
00969     LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
00970     if (!lpcida)
00971     {
00972         ReleaseStgMedium(&medium);
00973         pda->Release();
00974         return E_FAIL;
00975     }
00976 
00977     /* convert the data into pidl */
00978     LPITEMIDLIST pidl;
00979     LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
00980 
00981     if (!apidl)
00982         return E_FAIL;
00983 
00984     IShellFolder *psfDesktop;
00985     if (FAILED(SHGetDesktopFolder(&psfDesktop)))
00986     {
00987         SHFree(pidl);
00988         _ILFreeaPidl(apidl, lpcida->cidl);
00989         ReleaseStgMedium(&medium);
00990         pda->Release();
00991         return E_FAIL;
00992     }
00993 
00994     /* Find source folder */
00995     IShellFolder *psfFrom = NULL;
00996     if (_ILIsDesktop(pidl))
00997     {
00998         /* use desktop shellfolder */
00999         psfFrom = psfDesktop;
01000     }
01001     else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom)))
01002     {
01003         ERR("no IShellFolder\n");
01004 
01005         psfDesktop->Release();
01006         SHFree(pidl);
01007         _ILFreeaPidl(apidl, lpcida->cidl);
01008         ReleaseStgMedium(&medium);
01009         pda->Release();
01010 
01011         return E_FAIL;
01012     }
01013 
01014     /* Find target folder */
01015     IShellFolder *psfTarget = NULL;
01016     if (m_Dcm.cidl)
01017     {
01018         psfDesktop->Release();
01019         hr = m_Dcm.psf->BindToObject(m_Dcm.apidl[0], NULL, IID_IShellFolder, (LPVOID*)&psfTarget);
01020     }
01021     else
01022     {
01023         IPersistFolder2 *ppf2 = NULL;
01024         LPITEMIDLIST pidl;
01025 
01026         /* cidl is zero due to explorer view */
01027         hr = m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2);
01028         if (SUCCEEDED(hr))
01029         {
01030             hr = ppf2->GetCurFolder(&pidl);
01031             ppf2->Release();
01032             if (SUCCEEDED(hr))
01033             {
01034                 if (_ILIsDesktop(pidl))
01035                 {
01036                     /* use desktop shellfolder */
01037                     psfTarget = psfDesktop;
01038                 }
01039                 else
01040                 {
01041                     /* retrieve target desktop folder */
01042                     hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfTarget);
01043                 }
01044                 TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget, _ILIsDesktop(pidl));
01045                 ILFree(pidl);
01046             }
01047         }
01048     }
01049 
01050     if (FAILED(hr))
01051     {
01052         ERR("no IShellFolder\n");
01053 
01054         psfFrom->Release();
01055         SHFree(pidl);
01056         _ILFreeaPidl(apidl, lpcida->cidl);
01057         ReleaseStgMedium(&medium);
01058         pda->Release();
01059 
01060         return E_FAIL;
01061     }
01062 
01063     /* get source and destination shellfolder */
01064     ISFHelper *psfhlpdst;
01065     if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst)))
01066     {
01067         ERR("no IID_ISFHelper for destination\n");
01068 
01069         psfFrom->Release();
01070         psfTarget->Release();
01071         SHFree(pidl);
01072         _ILFreeaPidl(apidl, lpcida->cidl);
01073         ReleaseStgMedium(&medium);
01074         pda->Release();
01075 
01076         return E_FAIL;
01077     }
01078 
01079     ISFHelper *psfhlpsrc;
01080     if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
01081     {
01082         ERR("no IID_ISFHelper for source\n");
01083 
01084         psfhlpdst->Release();
01085         psfFrom->Release();
01086         psfTarget->Release();
01087         SHFree(pidl);
01088         _ILFreeaPidl(apidl, lpcida->cidl);
01089         ReleaseStgMedium(&medium);
01090         pda->Release();
01091         return E_FAIL;
01092     }
01093 
01094     /* FIXXME
01095      * do we want to perform a copy or move ???
01096      */
01097     hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
01098 
01099     psfhlpdst->Release();
01100     psfhlpsrc->Release();
01101     psfFrom->Release();
01102     psfTarget->Release();
01103     SHFree(pidl);
01104     _ILFreeaPidl(apidl, lpcida->cidl);
01105     ReleaseStgMedium(&medium);
01106     pda->Release();
01107     TRACE("CP result %x\n", hr);
01108     return S_OK;
01109 }
01110 
01111 HRESULT
01112 CDefaultContextMenu::DoOpenOrExplore(
01113     LPCMINVOKECOMMANDINFO lpcmi)
01114 {
01115     UNIMPLEMENTED;
01116     return E_FAIL;
01117 }
01118 
01119 BOOL
01120 GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
01121 {
01122     WCHAR wszLink[40];
01123 
01124     if (!bShortcut)
01125     {
01126         if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
01127             wszLink[0] = L'\0';
01128     }
01129 
01130     if (!bShortcut)
01131         swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
01132     else
01133         swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
01134 
01135     for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
01136     {
01137         if (!bShortcut)
01138             swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
01139         else
01140             swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
01141     }
01142 
01143     return TRUE;
01144 
01145 }
01146 
01147 HRESULT
01148 CDefaultContextMenu::DoCreateLink(
01149     LPCMINVOKECOMMANDINFO lpcmi)
01150 {
01151     WCHAR wszTarget[MAX_PATH];
01152     IPersistFile *ppf;
01153     HRESULT hr;
01154     STRRET strFile;
01155 
01156     if (m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
01157     {
01158         ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
01159         return E_FAIL;
01160     }
01161 
01162     WCHAR wszPath[MAX_PATH];
01163     if (StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath)) != S_OK)
01164         return E_FAIL;
01165 
01166     LPWSTR pwszExt = PathFindExtensionW(wszPath);
01167 
01168     if (!wcsicmp(pwszExt, L".lnk"))
01169     {
01170         if (!GetUniqueFileName(wszPath, pwszExt, wszTarget, TRUE))
01171             return E_FAIL;
01172 
01173         hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, m_Dcm.apidl[0], (LPVOID*)&ppf);
01174         if (hr != S_OK)
01175             return hr;
01176 
01177         hr = ppf->Save(wszTarget, FALSE);
01178         ppf->Release();
01179         NotifyShellViewWindow(lpcmi, TRUE);
01180         return hr;
01181     }
01182     else
01183     {
01184         if (!GetUniqueFileName(wszPath, L".lnk", wszTarget, TRUE))
01185             return E_FAIL;
01186 
01187         IShellLinkW *pLink;
01188         hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_IShellLinkW, (void**)&pLink);
01189         if (hr != S_OK)
01190             return hr;
01191 
01192         WCHAR szDirPath[MAX_PATH], *pwszFile;
01193         GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
01194         if (pwszFile) pwszFile[0] = 0;
01195 
01196         if (SUCCEEDED(pLink->SetPath(wszPath)) &&
01197             SUCCEEDED(pLink->SetWorkingDirectory(szDirPath)))
01198         {
01199             if (SUCCEEDED(pLink->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
01200             {
01201                 hr = ppf->Save(wszTarget, TRUE);
01202                 ppf->Release();
01203             }
01204         }
01205         pLink->Release();
01206         NotifyShellViewWindow(lpcmi, TRUE);
01207         return hr;
01208     }
01209 }
01210 
01211 HRESULT
01212 CDefaultContextMenu::DoDelete(
01213     LPCMINVOKECOMMANDINFO lpcmi)
01214 {
01215     STRRET strTemp;
01216     HRESULT hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strTemp);
01217     if(hr != S_OK)
01218     {
01219         ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
01220         return hr;
01221     }
01222 
01223     WCHAR wszPath[MAX_PATH];
01224     hr = StrRetToBufW(&strTemp, m_Dcm.apidl[0], wszPath, _countof(wszPath));
01225     if (hr != S_OK)
01226     {
01227         ERR("StrRetToBufW failed with %x\n", hr);
01228         return hr;
01229     }
01230 
01231     /* Only keep the base path */
01232     LPWSTR pwszFilename = PathFindFileNameW(wszPath);
01233     *pwszFilename = L'\0';
01234 
01235     /* Build paths list */
01236     LPWSTR pwszPaths = BuildPathsList(wszPath, m_Dcm.cidl, m_Dcm.apidl);
01237     if (!pwszPaths)
01238         return E_FAIL;
01239 
01240     /* Delete them */
01241     SHFILEOPSTRUCTW FileOp;
01242     ZeroMemory(&FileOp, sizeof(FileOp));
01243     FileOp.hwnd = GetActiveWindow();
01244     FileOp.wFunc = FO_DELETE;
01245     FileOp.pFrom = pwszPaths;
01246     FileOp.fFlags = FOF_ALLOWUNDO;
01247 
01248     if (SHFileOperationW(&FileOp) != 0)
01249     {
01250         ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths));
01251         return S_OK;
01252     }
01253 
01254     /* Get the active IShellView */
01255     LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
01256     if (lpSB)
01257     {
01258         /* Is the treeview focused */
01259         HWND hwnd;
01260         if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
01261         {
01262             /* Remove selected items from treeview */
01263             HTREEITEM hItem = TreeView_GetSelection(hwnd);
01264             if (hItem)
01265                 (void)TreeView_DeleteItem(hwnd, hItem);
01266         }
01267     }
01268     NotifyShellViewWindow(lpcmi, TRUE);
01269 
01270     HeapFree(GetProcessHeap(), 0, pwszPaths);
01271     return S_OK;
01272 
01273 }
01274 
01275 HRESULT
01276 CDefaultContextMenu::DoCopyOrCut(
01277     LPCMINVOKECOMMANDINFO lpcmi,
01278     BOOL bCopy)
01279 {
01280     LPDATAOBJECT pDataObj;
01281     HRESULT hr;
01282 
01283     if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_IDataObject, (void**)&pDataObj)))
01284     {
01285         hr = OleSetClipboard(pDataObj);
01286         pDataObj->Release();
01287         return hr;
01288     }
01289 
01290     /* Note: CWM_GETISHELLBROWSER returns not referenced object */
01291     LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
01292     if (!lpSB)
01293     {
01294         ERR("failed to get shellbrowser\n");
01295         return E_FAIL;
01296     }
01297 
01298     LPSHELLVIEW lpSV;
01299     hr = lpSB->QueryActiveShellView(&lpSV);
01300     if (FAILED(hr))
01301     {
01302         ERR("failed to query the active shellview\n");
01303         return hr;
01304     }
01305 
01306     hr = lpSV->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (LPVOID*)&pDataObj);
01307     if (SUCCEEDED(hr))
01308     {
01309         hr = OleSetClipboard(pDataObj);
01310         if (FAILED(hr))
01311             ERR("OleSetClipboard failed");
01312         pDataObj->Release();
01313     } else
01314         ERR("failed to get item object\n");
01315 
01316     lpSV->Release();
01317     return hr;
01318 }
01319 
01320 HRESULT
01321 CDefaultContextMenu::DoRename(
01322     LPCMINVOKECOMMANDINFO lpcmi)
01323 {
01324     /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
01325     LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
01326     if (!lpSB)
01327     {
01328         ERR("CWM_GETISHELLBROWSER failed\n");
01329         return E_FAIL;
01330     }
01331 
01332     /* is the treeview focused */
01333     HWND hwnd;
01334     if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
01335     {
01336         HTREEITEM hItem = TreeView_GetSelection(hwnd);
01337         if (hItem)
01338             (void)TreeView_EditLabel(hwnd, hItem);
01339     }
01340 
01341     LPSHELLVIEW lpSV;
01342     HRESULT hr = lpSB->QueryActiveShellView(&lpSV);
01343     if (FAILED(hr))
01344     {
01345         ERR("CWM_GETISHELLBROWSER failed\n");
01346         return hr;
01347     }
01348 
01349     lpSV->SelectItem(m_Dcm.apidl[0],
01350                      SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT);
01351     lpSV->Release();
01352     return S_OK;
01353 }
01354 
01355 HRESULT
01356 CDefaultContextMenu::DoProperties(
01357     LPCMINVOKECOMMANDINFO lpcmi)
01358 {
01359     HRESULT hr = S_OK;
01360     const ITEMIDLIST *pidlParent = m_Dcm.pidlFolder, *pidlChild;
01361 
01362     if (!pidlParent)
01363     {
01364         IPersistFolder2 *pf;
01365         
01366         /* pidlFolder is optional */
01367         if (SUCCEEDED(m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (PVOID*)&pf)))
01368         {
01369             pf->GetCurFolder((_ITEMIDLIST**)&pidlParent);
01370             pf->Release();
01371         }
01372     }
01373 
01374     if (m_Dcm.cidl > 0)
01375         pidlChild = m_Dcm.apidl[0];
01376     else
01377     {
01378         /* Set pidlChild to last pidl of current folder */
01379         if (pidlParent == m_Dcm.pidlFolder)
01380             pidlParent = (ITEMIDLIST*)ILClone(pidlParent);
01381 
01382         pidlChild = (ITEMIDLIST*)ILClone(ILFindLastID(pidlParent));
01383         ILRemoveLastID((ITEMIDLIST*)pidlParent);
01384     }
01385 
01386     if (_ILIsMyComputer(pidlChild))
01387     {
01388         if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL))
01389             hr = E_FAIL;
01390     }
01391     else if (_ILIsDesktop(pidlChild))
01392     {
01393         if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
01394             hr = E_FAIL;
01395     }
01396     else if (_ILIsDrive(pidlChild))
01397     {
01398         WCHAR wszBuf[MAX_PATH];
01399         ILGetDisplayName(pidlChild, wszBuf);
01400         if (!SH_ShowDriveProperties(wszBuf, pidlParent, &pidlChild))
01401             hr = E_FAIL;
01402     }
01403     else if (_ILIsNetHood(pidlChild))
01404     {
01405         // FIXME path!
01406         if (32 >= (UINT)ShellExecuteW(NULL, L"open", L"explorer.exe",
01407                                       L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
01408                                       NULL, SW_SHOWDEFAULT))
01409             hr = E_FAIL;
01410     }
01411     else if (_ILIsBitBucket(pidlChild))
01412     {
01413         /* FIXME: detect the drive path of bitbucket if appropiate */
01414         if(!SH_ShowRecycleBinProperties(L'C'))
01415             hr = E_FAIL;
01416     }
01417     else
01418     {
01419         if (m_Dcm.cidl > 1)
01420             WARN("SHMultiFileProperties is not yet implemented\n");
01421 
01422         STRRET strFile;
01423         hr = m_Dcm.psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
01424         if (SUCCEEDED(hr))
01425         {
01426             WCHAR wszBuf[MAX_PATH];
01427             hr = StrRetToBufW(&strFile, pidlChild, wszBuf, _countof(wszBuf));
01428             if (SUCCEEDED(hr))
01429                 hr = SH_ShowPropertiesDialog(wszBuf, pidlParent, &pidlChild);
01430             else
01431                 ERR("StrRetToBufW failed\n");
01432         }
01433         else
01434             ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
01435     }
01436 
01437     /* Free allocated PIDLs */
01438     if (pidlParent != m_Dcm.pidlFolder)
01439         ILFree((ITEMIDLIST*)pidlParent);
01440     if (m_Dcm.cidl < 1 || pidlChild != m_Dcm.apidl[0])
01441         ILFree((ITEMIDLIST*)pidlChild);
01442 
01443     return hr;
01444 }
01445 
01446 HRESULT
01447 CDefaultContextMenu::DoFormat(
01448     LPCMINVOKECOMMANDINFO lpcmi)
01449 {
01450     char szDrive[8] = {0};
01451 
01452     if (!_ILGetDrive(m_Dcm.apidl[0], szDrive, sizeof(szDrive)))
01453     {
01454         ERR("pidl is not a drive\n");
01455         return E_FAIL;
01456     }
01457 
01458     SHFormatDrive(lpcmi->hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
01459     return S_OK;
01460 }
01461 
01462 HRESULT
01463 CDefaultContextMenu::DoDynamicShellExtensions(
01464     LPCMINVOKECOMMANDINFO lpcmi)
01465 {
01466     UINT idCmd = LOWORD(lpcmi->lpVerb);
01467     PDynamicShellEntry pEntry = m_pDynamicEntries;
01468 
01469     TRACE("verb %p first %x last %x", lpcmi->lpVerb, m_iIdSHEFirst, m_iIdSHELast);
01470 
01471     while(pEntry && idCmd > pEntry->iIdCmdFirst + pEntry->NumIds)
01472         pEntry = pEntry->pNext;
01473 
01474     if (!pEntry)
01475         return E_FAIL;
01476 
01477     if (idCmd >= pEntry->iIdCmdFirst && idCmd <= pEntry->iIdCmdFirst + pEntry->NumIds)
01478     {
01479         /* invoke the dynamic context menu */
01480         lpcmi->lpVerb = MAKEINTRESOURCEA(idCmd - pEntry->iIdCmdFirst);
01481         return pEntry->pCM->InvokeCommand(lpcmi);
01482     }
01483 
01484     return E_FAIL;
01485 }
01486 
01487 
01488 HRESULT
01489 CDefaultContextMenu::DoStaticShellExtensions(
01490     LPCMINVOKECOMMANDINFO lpcmi)
01491 {
01492     PStaticShellEntry pEntry = m_pStaticEntries;
01493     INT iCmd = LOWORD(lpcmi->lpVerb) - m_iIdSCMFirst;
01494     HRESULT hr;
01495 
01496     while (pEntry && (iCmd--) > 0)
01497         pEntry = pEntry->pNext;
01498 
01499     if (iCmd > 0)
01500         return E_FAIL;
01501 
01502     STRRET strFile;
01503     hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
01504     if (hr != S_OK)
01505     {
01506         ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
01507         return hr;
01508     }
01509 
01510     WCHAR wszPath[MAX_PATH];
01511     hr = StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, MAX_PATH);
01512     if (hr != S_OK)
01513         return hr;
01514 
01515     WCHAR wszDir[MAX_PATH];
01516     wcscpy(wszDir, wszPath);
01517     PathRemoveFileSpec(wszDir);
01518 
01519     SHELLEXECUTEINFOW sei;
01520     ZeroMemory(&sei, sizeof(sei));
01521     sei.cbSize = sizeof(sei);
01522     sei.fMask = SEE_MASK_CLASSNAME;
01523     sei.lpClass = pEntry->szClass;
01524     sei.hwnd = lpcmi->hwnd;
01525     sei.nShow = SW_SHOWNORMAL;
01526     sei.lpVerb = pEntry->szVerb;
01527     sei.lpFile = wszPath;
01528     sei.lpDirectory = wszDir;
01529     ShellExecuteExW(&sei);
01530     return S_OK;
01531 }
01532 
01533 HRESULT
01534 WINAPI
01535 CDefaultContextMenu::InvokeCommand(
01536     LPCMINVOKECOMMANDINFO lpcmi)
01537 {
01538     switch(LOWORD(lpcmi->lpVerb))
01539     {
01540         case FCIDM_SHVIEW_BIGICON:
01541         case FCIDM_SHVIEW_SMALLICON:
01542         case FCIDM_SHVIEW_LISTVIEW:
01543         case FCIDM_SHVIEW_REPORTVIEW:
01544         case 0x30: /* FIX IDS in resource files */
01545         case 0x31:
01546         case 0x32:
01547         case 0x33:
01548         case FCIDM_SHVIEW_AUTOARRANGE:
01549         case FCIDM_SHVIEW_SNAPTOGRID:
01550         case FCIDM_SHVIEW_REFRESH:
01551             return NotifyShellViewWindow(lpcmi, FALSE);
01552         case FCIDM_SHVIEW_INSERT:
01553         case FCIDM_SHVIEW_INSERTLINK:
01554             return DoPaste(lpcmi);
01555         case FCIDM_SHVIEW_OPEN:
01556         case FCIDM_SHVIEW_EXPLORE:
01557             return DoOpenOrExplore(lpcmi);
01558         case FCIDM_SHVIEW_COPY:
01559         case FCIDM_SHVIEW_CUT:
01560             return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
01561         case FCIDM_SHVIEW_CREATELINK:
01562             return DoCreateLink(lpcmi);
01563         case FCIDM_SHVIEW_DELETE:
01564             return DoDelete(lpcmi);
01565         case FCIDM_SHVIEW_RENAME:
01566             return DoRename(lpcmi);
01567         case FCIDM_SHVIEW_PROPERTIES:
01568             return DoProperties(lpcmi);
01569         case 0x7ABC:
01570             return DoFormat(lpcmi);
01571     }
01572 
01573     if (m_iIdSHEFirst && m_iIdSHELast)
01574     {
01575         if (LOWORD(lpcmi->lpVerb) >= m_iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSHELast)
01576             return DoDynamicShellExtensions(lpcmi);
01577     }
01578 
01579     if (m_iIdSCMFirst && m_iIdSCMLast)
01580     {
01581         if (LOWORD(lpcmi->lpVerb) >= m_iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSCMLast)
01582             return DoStaticShellExtensions(lpcmi);
01583     }
01584 
01585     FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi->lpVerb));
01586     return E_UNEXPECTED;
01587 }
01588 
01589 HRESULT
01590 WINAPI
01591 CDefaultContextMenu::GetCommandString(
01592     UINT_PTR idCommand,
01593     UINT uFlags,
01594     UINT* lpReserved,
01595     LPSTR lpszName,
01596     UINT uMaxNameLen)
01597 {
01598     return S_OK;
01599 }
01600 
01601 HRESULT
01602 WINAPI
01603 CDefaultContextMenu::HandleMenuMsg(
01604     UINT uMsg,
01605     WPARAM wParam,
01606     LPARAM lParam)
01607 {
01608     return S_OK;
01609 }
01610 
01611 static
01612 HRESULT
01613 IDefaultContextMenu_Constructor(
01614     const DEFCONTEXTMENU *pdcm,
01615     REFIID riid,
01616     void **ppv)
01617 {
01618     if (ppv == NULL)
01619         return E_POINTER;
01620     *ppv = NULL;
01621 
01622     CComObject<CDefaultContextMenu> *pCM;
01623     HRESULT hr = CComObject<CDefaultContextMenu>::CreateInstance(&pCM);
01624     if (FAILED(hr))
01625         return hr;
01626     pCM->AddRef(); // CreateInstance returns object with 0 ref count */
01627 
01628     CComPtr<IUnknown> pResult;
01629     hr = pCM->QueryInterface(riid, (void **)&pResult);
01630     if (FAILED(hr))
01631     {
01632         pCM->Release();
01633         return hr;
01634     }
01635 
01636     hr = pCM->Initialize(pdcm);
01637     if (FAILED(hr))
01638     {
01639         pCM->Release();
01640         return hr;
01641     }
01642 
01643     *ppv = pResult.Detach();
01644     pCM->Release();
01645     TRACE("This(%p) cidl %u\n", *ppv, pdcm->cidl);
01646     return S_OK;
01647 }
01648 
01649 /*************************************************************************
01650  * SHCreateDefaultContextMenu            [SHELL32.325] Vista API
01651  *
01652  */
01653 
01654 HRESULT
01655 WINAPI
01656 SHCreateDefaultContextMenu(
01657     const DEFCONTEXTMENU *pdcm,
01658     REFIID riid,
01659     void **ppv)
01660 {
01661     *ppv = NULL;
01662     HRESULT hr = IDefaultContextMenu_Constructor(pdcm, riid, ppv);
01663     if (FAILED(hr))
01664         ERR("IDefaultContextMenu_Constructor failed: %x\n", hr);
01665     TRACE("pcm %p hr %x\n", pdcm, hr);
01666     return hr;
01667 }
01668 
01669 /*************************************************************************
01670  * CDefFolderMenu_Create2            [SHELL32.701]
01671  *
01672  */
01673 
01674 HRESULT
01675 WINAPI
01676 CDefFolderMenu_Create2(
01677     LPCITEMIDLIST pidlFolder,
01678     HWND hwnd,
01679     UINT cidl,
01680     LPCITEMIDLIST *apidl,
01681     IShellFolder *psf,
01682     LPFNDFMCALLBACK lpfn,
01683     UINT nKeys,
01684     const HKEY *ahkeyClsKeys,
01685     IContextMenu **ppcm)
01686 {
01687     DEFCONTEXTMENU pdcm;
01688     pdcm.hwnd = hwnd;
01689     pdcm.pcmcb = NULL;
01690     pdcm.pidlFolder = pidlFolder;
01691     pdcm.psf = psf;
01692     pdcm.cidl = cidl;
01693     pdcm.apidl = apidl;
01694     pdcm.punkAssociationInfo = NULL;
01695     pdcm.cKeys = nKeys;
01696     pdcm.aKeys = ahkeyClsKeys;
01697 
01698     HRESULT hr = SHCreateDefaultContextMenu(&pdcm, IID_IContextMenu, (void**)ppcm);
01699     return hr;
01700 }
01701 

Generated on Sun May 27 2012 04:26:17 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.