496 lines
13 KiB
C++
496 lines
13 KiB
C++
|
#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;
|
||
|
}
|