diff --git a/reactos/dll/win32/shell32/CDefaultContextMenu.cpp b/reactos/dll/win32/shell32/CDefaultContextMenu.cpp index 4d6b1a8221a..492515d2089 100644 --- a/reactos/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/reactos/dll/win32/shell32/CDefaultContextMenu.cpp @@ -29,7 +29,7 @@ typedef struct _DynamicShellEntry_ typedef struct _StaticShellEntry_ { LPWSTR szVerb; - LPWSTR szClass; + HKEY hkClass; struct _StaticShellEntry_ *pNext; } StaticShellEntry, *PStaticShellEntry; @@ -64,6 +64,8 @@ class CDefaultContextMenu : UINT m_cidl; PCUITEMID_CHILD_ARRAY m_apidl; CComPtr m_pDataObj; + HKEY* m_aKeys; + UINT m_cKeys; PIDLIST_ABSOLUTE m_pidlFolder; DWORD m_bGroupPolicyActive; PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */ @@ -73,9 +75,8 @@ class CDefaultContextMenu : UINT m_iIdSCMFirst; /* first static used id */ UINT m_iIdSCMLast; /* last static used id */ - void AddStaticEntry(LPCWSTR pwszVerb, LPCWSTR pwszClass); - void AddStaticEntryForKey(HKEY hKey, LPCWSTR pwszClass); - void AddStaticEntryForFileClass(LPCWSTR pwszExt); + void AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb); + void AddStaticEntriesForKey(HKEY hKey); BOOL IsShellExtensionAlreadyLoaded(const CLSID *pclsid); HRESULT LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid); BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey); @@ -135,6 +136,8 @@ CDefaultContextMenu::CDefaultContextMenu() : m_cidl(0), m_apidl(NULL), m_pDataObj(NULL), + m_aKeys(NULL), + m_cKeys(NULL), m_pidlFolder(NULL), m_bGroupPolicyActive(0), m_pDynamicEntries(NULL), @@ -163,12 +166,15 @@ CDefaultContextMenu::~CDefaultContextMenu() while (pStaticEntry) { pNextStatic = pStaticEntry->pNext; - HeapFree(GetProcessHeap(), 0, pStaticEntry->szClass); HeapFree(GetProcessHeap(), 0, pStaticEntry->szVerb); HeapFree(GetProcessHeap(), 0, pStaticEntry); pStaticEntry = pNextStatic; } + for (UINT i = 0; i < m_cKeys; i++) + RegCloseKey(m_aKeys[i]); + HeapFree(GetProcessHeap(), 0, m_aKeys); + if (m_pidlFolder) CoTaskMemFree(m_pidlFolder); _ILFreeaPidl(const_cast(m_apidl), m_cidl); @@ -184,6 +190,15 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm) return E_OUTOFMEMORY; m_psf = pdcm->psf; + m_cKeys = pdcm->cKeys; + if (pdcm->cKeys) + { + m_aKeys = (HKEY*)HeapAlloc(GetProcessHeap(), 0, sizeof(HKEY) * pdcm->cKeys); + if (!m_aKeys) + return E_OUTOFMEMORY; + memcpy(m_aKeys, pdcm->aKeys, sizeof(HKEY) * pdcm->cKeys); + } + m_psf->GetUIObjectOf(pdcm->hwnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &m_pDataObj)); if (pdcm->pidlFolder) @@ -204,8 +219,7 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm) return S_OK; } -void -CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass) +void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb) { PStaticShellEntry pEntry = m_pStaticEntries, pLastEntry = NULL; while(pEntry) @@ -219,7 +233,7 @@ CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass) pEntry = pEntry->pNext; } - TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass)); + TRACE("adding verb %s\n", debugstr_w(szVerb)); pEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry)); if (pEntry) @@ -228,9 +242,7 @@ CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass) pEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb) + 1) * sizeof(WCHAR)); if (pEntry->szVerb) wcscpy(pEntry->szVerb, szVerb); - pEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass) + 1) * sizeof(WCHAR)); - if (pEntry->szClass) - wcscpy(pEntry->szClass, szClass); + pEntry->hkClass = hkeyClass; } if (!wcsicmp(szVerb, L"open")) @@ -245,88 +257,26 @@ CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass) m_pStaticEntries = pEntry; } -void -CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey, const WCHAR *pwszClass) +void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey) { WCHAR wszName[40]; DWORD cchName, dwIndex = 0; + HKEY hShellKey; - TRACE("AddStaticEntryForKey %x %ls\n", hKey, pwszClass); + LRESULT lres = RegOpenKeyExW(hKey, L"shell", 0, KEY_READ, &hShellKey); + if (lres != STATUS_SUCCESS) + return; while(TRUE) { cchName = _countof(wszName); - if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + if (RegEnumKeyExW(hShellKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) break; - AddStaticEntry(wszName, pwszClass); - } -} - -void -CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR * szExt) -{ - WCHAR szBuffer[100]; - HKEY hKey; - LONG result; - DWORD dwBuffer; - UINT Length; - static WCHAR szShell[] = L"\\shell"; - static WCHAR szShellAssoc[] = L"SystemFileAssociations\\"; - - TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt)); - - Length = wcslen(szExt); - if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR)) - { - wcscpy(szBuffer, szExt); - wcscpy(&szBuffer[Length], szShell); - result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); - if (result == ERROR_SUCCESS) - { - szBuffer[Length] = 0; - AddStaticEntryForKey(hKey, szExt); - RegCloseKey(hKey); - } + AddStaticEntry(hKey, wszName); } - dwBuffer = sizeof(szBuffer); - result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer); - if (result == ERROR_SUCCESS) - { - Length = wcslen(szBuffer); - if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR)) - { - wcscpy(&szBuffer[Length], szShell); - TRACE("szBuffer %s\n", debugstr_w(szBuffer)); - - result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); - if (result == ERROR_SUCCESS) - { - szBuffer[Length] = 0; - AddStaticEntryForKey(hKey, szBuffer); - RegCloseKey(hKey); - } - } - } - - wcscpy(szBuffer, szShellAssoc); - dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR); - result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer); - if (result == ERROR_SUCCESS) - { - Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc); - wcscat(szBuffer, L"\\shell"); - TRACE("szBuffer %s\n", debugstr_w(szBuffer)); - - result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); - if (result == ERROR_SUCCESS) - { - szBuffer[Length] = 0; - AddStaticEntryForKey(hKey, szBuffer); - RegCloseKey(hKey); - } - } + RegCloseKey(hShellKey); } static @@ -672,13 +622,13 @@ CDefaultContextMenu::AddStaticContextMenusToMenu( else { WCHAR wszKey[256]; - HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb); + HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", pEntry->szVerb); if (SUCCEEDED(hr)) { HKEY hkVerb; DWORD cbVerb = sizeof(wszVerb); - LONG res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszKey, &hkVerb); + LONG res = RegOpenKeyW(pEntry->hkClass, wszKey, &hkVerb); if (res == ERROR_SUCCESS) { res = RegLoadMUIStringW(hkVerb, @@ -757,85 +707,15 @@ CDefaultContextMenu::BuildShellItemContextMenu( UINT iIdCmdLast, UINT uFlags) { - HKEY hKey; HRESULT hr; TRACE("BuildShellItemContextMenu entered\n"); ASSERT(m_cidl >= 1); - STRRET strFile; - hr = m_psf->GetDisplayNameOf(m_apidl[0], SHGDN_FORPARSING, &strFile); - if (hr == S_OK) + for (UINT i = 0; i < m_cKeys; i++) { - WCHAR wszPath[MAX_PATH]; - hr = StrRetToBufW(&strFile, m_apidl[0], wszPath, _countof(wszPath)); - if (hr == S_OK) - { - LPCWSTR pwszExt = PathFindExtensionW(wszPath); - if (pwszExt[0]) - { - /* enumerate dynamic/static for a given file class */ - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - /* add static verbs */ - AddStaticEntryForFileClass(pwszExt); - - /* load dynamic extensions from file extension key */ - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - - WCHAR wszTemp[40]; - DWORD dwSize = sizeof(wszTemp); - if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS) - { - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - /* add static verbs from progid key */ - AddStaticEntryForFileClass(wszTemp); - - /* load dynamic extensions from progid key */ - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - } - } - } - } - else - ERR("GetDisplayNameOf failed: %x\n", hr); - - GUID *pGuid = _ILGetGUIDPointer(m_apidl[0]); - if (pGuid) - { - LPOLESTR pwszCLSID; - WCHAR buffer[60]; - - wcscpy(buffer, L"CLSID\\"); - hr = StringFromCLSID(*pGuid, &pwszCLSID); - if (hr == S_OK) - { - wcscpy(&buffer[6], pwszCLSID); - TRACE("buffer %s\n", debugstr_w(buffer)); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - EnumerateDynamicContextHandlerForKey(hKey); - AddStaticEntryForFileClass(buffer); - RegCloseKey(hKey); - } - CoTaskMemFree(pwszCLSID); - } - } - - if (_ILIsDrive(m_apidl[0])) - { - AddStaticEntryForFileClass(L"Drive"); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - + AddStaticEntriesForKey(m_aKeys[i]); + EnumerateDynamicContextHandlerForKey(m_aKeys[i]); } /* add static actions */ @@ -847,48 +727,6 @@ CDefaultContextMenu::BuildShellItemContextMenu( rfg = 0; } - if (rfg & SFGAO_FOLDER) - { - /* add the default verbs open / explore */ - AddStaticEntryForFileClass(L"Folder"); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - - /* Directory is only loaded for real filesystem directories */ - if (rfg & SFGAO_FILESYSTEM) - { - AddStaticEntryForFileClass(L"Directory"); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - } - } - - /* AllFilesystemObjects class is loaded only for files and directories */ - if (rfg & SFGAO_FILESYSTEM) - { - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - /* sendto service is registered here */ - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - - if (!(rfg & SFGAO_FOLDER)) - { - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - EnumerateDynamicContextHandlerForKey(hKey); - RegCloseKey(hKey); - } - } - } - /* add static context menu handlers */ UINT IndexMenu = AddStaticContextMenusToMenu(hMenu, 0); @@ -1398,12 +1236,12 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticSh FlagsName = L"BrowserFlags"; /* Try to get the flag from the verb */ - hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb); + hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", pEntry->szVerb); if (!SUCCEEDED(hr)) return 0; cbVerb = sizeof(wFlags); - if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS) + if (RegGetValueW(pEntry->hkClass, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS) { return wFlags; } @@ -1452,9 +1290,6 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, SHGetPathFromIDListW(m_pidlFolder, wszDir); } - HKEY hkeyClass; - RegOpenKeyExW(HKEY_CLASSES_ROOT, pEntry->szClass, 0, KEY_READ, &hkeyClass); - SHELLEXECUTEINFOW sei; ZeroMemory(&sei, sizeof(sei)); sei.cbSize = sizeof(sei); @@ -1463,7 +1298,7 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, sei.lpVerb = pEntry->szVerb; sei.lpDirectory = wszDir; sei.lpIDList = pidlFull; - sei.hkeyClass = hkeyClass; + sei.hkeyClass = pEntry->hkClass; sei.fMask = SEE_MASK_CLASSKEY | SEE_MASK_IDLIST; if (bHasPath) { @@ -1472,8 +1307,6 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, ShellExecuteExW(&sei); - RegCloseKey(hkeyClass); - ILFree(pidlFull); return S_OK; @@ -1748,10 +1581,96 @@ CDefaultContextMenu_CreateInstance(const DEFCONTEXTMENU *pdcm, REFIID riid, void * */ +static void AddClassKey(const WCHAR * szClass, HKEY* buffer, UINT* cKeys) +{ + LSTATUS result; + HKEY hkey; + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ | KEY_QUERY_VALUE, &hkey); + if (result != ERROR_SUCCESS) + return; + + buffer[*cKeys] = hkey; + *cKeys +=1; +} + +void HackFillKeys(DEFCONTEXTMENU *pdcm, HKEY* buffer) +{ + PCUITEMID_CHILD pidl = pdcm->apidl[0]; + pdcm->cKeys = 0; + pdcm->aKeys = buffer; + + if (_ILIsValue(pidl)) + { + FileStructW* pFileData = _ILGetFileStructW(pidl); + LPWSTR extension = PathFindExtension(pFileData->wszName); + + if (extension) + { + AddClassKey(extension, buffer, &pdcm->cKeys); + + WCHAR wszClass[40], wszClass2[40]; + DWORD dwSize = sizeof(wszClass); + if (RegGetValueW(HKEY_CLASSES_ROOT, extension, NULL, RRF_RT_REG_SZ, NULL, wszClass, &dwSize) == ERROR_SUCCESS) + { + swprintf(wszClass2, L"%s//%s", extension, wszClass); + + AddClassKey(wszClass, buffer, &pdcm->cKeys); + AddClassKey(wszClass2, buffer, &pdcm->cKeys); + } + + swprintf(wszClass2, L"SystemFileAssociations//%s", extension); + AddClassKey(wszClass2, buffer, &pdcm->cKeys); + + if (RegGetValueW(HKEY_CLASSES_ROOT, extension, L"PerceivedType ", RRF_RT_REG_SZ, NULL, wszClass, &dwSize) == ERROR_SUCCESS) + { + swprintf(wszClass2, L"SystemFileAssociations//%s", wszClass); + AddClassKey(wszClass2, buffer, &pdcm->cKeys); + } + } + + AddClassKey(L"AllFilesystemObjects", buffer, &pdcm->cKeys); + AddClassKey(L"*", buffer, &pdcm->cKeys); + } + else if (_ILIsSpecialFolder(pidl)) + { + GUID *pGuid = _ILGetGUIDPointer(pidl); + if (pGuid) + { + LPOLESTR pwszCLSID; + WCHAR key[60]; + + wcscpy(key, L"CLSID\\"); + HRESULT hr = StringFromCLSID(*pGuid, &pwszCLSID); + if (hr == S_OK) + { + wcscpy(&key[6], pwszCLSID); + AddClassKey(key, buffer, &pdcm->cKeys); + } + } + AddClassKey(L"Folder", buffer, &pdcm->cKeys); + } + else if (_ILIsFolder(pidl)) + { + AddClassKey(L"AllFilesystemObjects", buffer, &pdcm->cKeys); + AddClassKey(L"Directory", buffer, &pdcm->cKeys); + AddClassKey(L"Folder", buffer, &pdcm->cKeys); + } + else if (_ILIsDrive(pidl)) + { + AddClassKey(L"Drive", buffer, &pdcm->cKeys); + AddClassKey(L"Folder", buffer, &pdcm->cKeys); + } +} + HRESULT WINAPI SHCreateDefaultContextMenu(const DEFCONTEXTMENU *pdcm, REFIID riid, void **ppv) { + /* HACK: move to the shell folders implementation */ + HKEY hkeyHack[16]; + if (!pdcm->aKeys && pdcm->cidl) + HackFillKeys((DEFCONTEXTMENU *)pdcm, hkeyHack); + return CDefaultContextMenu_CreateInstance(pdcm, riid, ppv); }