#include "shellprv.h" #include "ftascstr.h" //for now, until CoCreateInstance #include "ftassoc.h" //for now, until CoCreate IAssocInfo #include "ftenum.h" #define EHKCR_NONE 0 #define EHKCR_EXT 1 #define EHKCR_PROGID 2 /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // CFTEnumAssocInfo /////////////////////////////////////////////////////////////////////////////// // Contructor / Destructor CFTEnumAssocInfo::CFTEnumAssocInfo() : _cRef(1) { //DLLAddRef(); } CFTEnumAssocInfo::~CFTEnumAssocInfo() { //DLLRelease(); } /////////////////////////////////////////////////////////////////////////////// // IUnknown methods HRESULT CFTEnumAssocInfo::QueryInterface(REFIID riid, PVOID* ppv) { //nothing for now return E_NOTIMPL; } ULONG CFTEnumAssocInfo::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CFTEnumAssocInfo::Release() { if (InterlockedDecrement(&_cRef) > 0) return _cRef; delete this; return 0; } /////////////////////////////////////////////////////////////////////////////// // IEnum methods HRESULT CFTEnumAssocInfo::Init(ASENUM asenumFlags, LPTSTR pszStr, AIINIT aiinitFlags) { HRESULT hres = E_INVALIDARG; if (((ASENUM_PROGID & asenumFlags) && !(ASENUM_EXT & asenumFlags)) || (!(ASENUM_PROGID & asenumFlags) && (ASENUM_EXT & asenumFlags)) || (ASENUM_ACTION & asenumFlags) ) { hres = S_OK; _asenumFlags = asenumFlags; _aiinitFlags = aiinitFlags; if (pszStr) StrCpyN(_szInitStr, pszStr, ARRAYSIZE(_szInitStr)); else _szInitStr[0] = 0; } return hres; } HRESULT CFTEnumAssocInfo::Next(IAssocInfo** ppAI) { HRESULT hres = E_FAIL; TCHAR szStr[MAX_FTMAX]; DWORD cchStr = ARRAYSIZE(szStr); AIINIT aiinitFlags = 0; *szStr = 0; switch(_aiinitFlags) { // We go through the registry case AIINIT_NONE: { switch(_asenumFlags & ASENUM_MAINMASK) { case ASENUM_EXT: hres = _EnumHKCR(_asenumFlags, szStr, &cchStr); aiinitFlags = AIINIT_EXT; break; case ASENUM_PROGID: hres = _EnumHKCR(_asenumFlags, szStr, &cchStr); aiinitFlags = AIINIT_PROGID; break; default: hres = E_INVALIDARG; break; } break; } // In theory, we go through the value linked to a progID case AIINIT_PROGID: { switch(_asenumFlags & ASENUM_MAINMASK) { case ASENUM_EXT: hres = _EnumHKCR(_asenumFlags, szStr, &cchStr); aiinitFlags = AIINIT_EXT; break; case ASENUM_ACTION: hres = _EnumProgIDActions(szStr, &cchStr); break; default: hres = E_INVALIDARG; break; } break; } default: hres = E_INVALIDARG; break; } if (S_OK==hres) { if (*szStr) { *ppAI = new CFTAssocInfo(); if (*ppAI) { if (ASENUM_ACTION != (_asenumFlags & ASENUM_MAINMASK)) hres = (*ppAI)->Init(aiinitFlags, szStr); else hres = (*ppAI)->InitComplex(AIINIT_PROGID, _szInitStr, AIINIT_ACTION, szStr); } else hres = E_OUTOFMEMORY; } else hres = E_FAIL; } return hres; } // This beast goes through the HKCR reg key and check that the // key meets the criteria of dwFlags (mostly extension vs progID) HRESULT CFTEnumAssocInfo::_EnumHKCR(ASENUM asenumFlags, LPTSTR pszStr, DWORD* pcchStr) { HRESULT hres = E_FAIL; BOOL fNext = TRUE; while (fNext) { // This will mean "no more item" hres = S_FALSE; DWORD cchStr = *pcchStr; LONG lRes = RegEnumKeyEx(HKEY_CLASSES_ROOT, _dwIndex, pszStr, &cchStr, NULL, NULL, NULL, NULL); ++_dwIndex; if (lRes != ERROR_NO_MORE_ITEMS) { if (TEXT('*') != *pszStr) { if (!_EnumKCRStop(asenumFlags, pszStr)) { if (!_EnumKCRSkip(asenumFlags, pszStr)) { hres = S_OK; fNext = FALSE; } } else { hres = S_FALSE; fNext = FALSE; } } } else { fNext = FALSE; } } // Did we found the first ext? if (!_fFirstExtFound && S_OK==hres && (TEXT('.') == *pszStr)) { // Yes _fFirstExtFound = TRUE; } return hres; } HRESULT CFTEnumAssocInfo::_EnumProgIDActions(LPTSTR pszStr, DWORD* pcchStr) { // 5 for "shell" TCHAR szSubKey[MAX_PROGID + 5 + 1]; HRESULT hres = S_OK; HKEY hKey = NULL; StrCpyN(szSubKey, _szInitStr, MAX_PROGID); StrCat(szSubKey, TEXT("\\shell")); if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szSubKey, 0, KEY_READ, &hKey)) { LONG lRes = RegEnumKeyEx(hKey, _dwIndex, pszStr, pcchStr, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS !=lRes) { if (ERROR_NO_MORE_ITEMS == lRes) hres = S_FALSE; else hres = E_FAIL; } #if 0 else { TCHAR szNiceText[MAX_ACTIONDESCR]; LONG lNiceText = ARRAYSIZE(szNiceText); #endif ++_dwIndex; #if 0 // Check if there is nice text for the action if ((ERROR_SUCCESS == SHRegQueryValue(hKey, pszStr, szNiceText, &lNiceText)) && (lNiceText > SIZEOF(TCHAR))) { StrCpyN(pszStr, szNiceText, ARRAYSIZE(pszStr)); } } #endif RegCloseKey(hKey); } return hres; } /////////////////////////////////////////////////////////////////////////////// // Helpers BOOL CFTEnumAssocInfo::_EnumKCRSkip(DWORD asenumFlags, LPTSTR pszExt) { BOOL fRet = FALSE; if (AIINIT_NONE == _aiinitFlags) { CFTAssocStore* pAssocStore = NULL; // Do we want the Exts? if (!(ASENUM_EXT & asenumFlags)) { // No // Is the first char a '.'? if (TEXT('.') == *pszExt) { // Yes, skip this one fRet = TRUE; } } else { // Yes // Is the first char a '.'? if (TEXT('.') != *pszExt) { // No, skip it fRet = TRUE; } } // we want to skip all the ext having explorer.exe as the executable for // their default verb. if ((ASENUM_NOEXPLORERSHELLACTION & asenumFlags) && !fRet) { IQueryAssociations* pQA = NULL; ASSERT(ASENUM_EXT & asenumFlags); HRESULT hres = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID*)&pQA); if (SUCCEEDED(hres)) { WCHAR szwExt[MAX_EXT]; DWORD cchExt = ARRAYSIZE(szwExt); SHTCharToUnicode(pszExt, szwExt, ARRAYSIZE(szwExt)); hres = pQA->Init(0, szwExt, NULL, NULL); if (SUCCEEDED(hres)) { WCHAR szwExec[MAX_APPFRIENDLYNAME]; DWORD cchExec = ARRAYSIZE(szwExec); hres = pQA->GetString(ASSOCF_VERIFY, ASSOCSTR_EXECUTABLE, NULL, szwExec, &cchExec); if (!StrCmpIW(PathFindFileNameW(szwExec), L"explorer.exe")) { fRet = TRUE; } } pQA->Release(); } } if ((ASENUM_NOEXCLUDED & asenumFlags) && !fRet) { IAssocInfo* pAI = NULL; HRESULT hres = E_FAIL; if (!pAssocStore) pAssocStore = new CFTAssocStore(); ASSERT(ASENUM_EXT & asenumFlags); if (pAssocStore) hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI); if (SUCCEEDED(hres)) { hres = pAI->GetBOOL(AIBOOL_EXCLUDE, &fRet); pAI->Release(); } } if ((ASENUM_NOEXE & asenumFlags) && !fRet) { ASSERT(ASENUM_EXT & asenumFlags); fRet = PathIsExe(pszExt); } if ((ASENUM_ASSOC_YES & asenumFlags) && (ASENUM_ASSOC_ALL != (ASENUM_ASSOC_ALL & asenumFlags)) && !fRet) { IAssocInfo* pAI = NULL; HRESULT hres = E_FAIL; if (!pAssocStore) pAssocStore = new CFTAssocStore(); ASSERT(ASENUM_EXT & asenumFlags); if (pAssocStore) hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI); if (SUCCEEDED(hres)) { BOOL fExtAssociated = FALSE; hres = pAI->GetBOOL(AIBOOL_EXTASSOCIATED, &fExtAssociated); fRet = (fExtAssociated ? FALSE : TRUE); pAI->Release(); } } if ((ASENUM_ASSOC_NO & asenumFlags) && (ASENUM_ASSOC_ALL != (ASENUM_ASSOC_ALL & asenumFlags)) && !fRet) { IAssocInfo* pAI = NULL; HRESULT hres = E_FAIL; if (!pAssocStore) pAssocStore = new CFTAssocStore(); ASSERT(ASENUM_EXT & asenumFlags); if (pAssocStore) hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI); if (SUCCEEDED(hres)) { hres = pAI->GetBOOL(AIBOOL_EXTASSOCIATED, &fRet); pAI->Release(); } } if ((ASENUM_SHOWONLY & asenumFlags) && !fRet) { IAssocInfo* pAI = NULL; HRESULT hres = E_FAIL; if (!pAssocStore) pAssocStore = new CFTAssocStore(); ASSERT(ASENUM_PROGID & asenumFlags); // I know pszExt is not an Extension but a progID... if (pAssocStore) hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_PROGID, &pAI); if (SUCCEEDED(hres)) { BOOL fTmpRet = FALSE; hres = pAI->GetBOOL(AIBOOL_SHOW, &fTmpRet); // If it has the show flag (FTA_Show), we don't skip it, so // invert the fTmpRet fRet = fTmpRet ? FALSE : TRUE; pAI->Release(); } } if (pAssocStore) delete pAssocStore; } else { if (AIINIT_PROGID == _aiinitFlags) { fRet = TRUE; // Do we want the Exts? if (ASENUM_EXT & asenumFlags) { DWORD dwType = 0; TCHAR szProgID[MAX_PROGID]; DWORD cbProgID = ARRAYSIZE(szProgID) * sizeof(TCHAR); LONG lRes = SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, &dwType, szProgID, &cbProgID); if (ERROR_SUCCESS == lRes) { // Does it have the same progID? if (!lstrcmpi(szProgID, _szInitStr)) { // Yes, don't skip fRet = FALSE; } } } } } return fRet; } BOOL CFTEnumAssocInfo::_EnumKCRStop(DWORD asenumFlags, LPTSTR pszExt) { BOOL fRet = FALSE; // NT returns the extension in alphabetical order, not Win9X // If we want only the extensions, and the first char is not a '.', then stop if (ASENUM_EXT & asenumFlags) { // Don't go out if we haven't found the first extension if ((TEXT('.') != *pszExt) && _fFirstExtFound) fRet = TRUE; } return fRet; } /////////////////////////////////////////////////////////////////////////////// // Non-implemented IEnum methods HRESULT CFTEnumAssocInfo::Clone(IEnumAssocInfo* pEnum) { // Will never be implemented return E_FAIL; } HRESULT CFTEnumAssocInfo::Skip(DWORD dwSkip) { return E_NOTIMPL; } HRESULT CFTEnumAssocInfo::Reset() { return E_NOTIMPL; }