Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendefcontextmenu.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
1.7.6.1
|