You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
461 lines
9.7 KiB
461 lines
9.7 KiB
// File: mrulist.cpp
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "mrulist2.h"
|
|
|
|
typedef struct {
|
|
LPTSTR psz1;
|
|
LPTSTR psz2;
|
|
} SZSZ;
|
|
typedef SZSZ * PSZSZ;
|
|
|
|
typedef struct {
|
|
LPTSTR psz1;
|
|
LPTSTR psz2;
|
|
DWORD dw;
|
|
} SZSZDW;
|
|
typedef SZSZDW * PSZSZDW;
|
|
|
|
|
|
static LPTSTR PszAlloc(LPCTSTR pszSrc)
|
|
{
|
|
if (NULL == pszSrc)
|
|
return NULL;
|
|
|
|
LPTSTR pszDest = new TCHAR[lstrlen(pszSrc) + 1];
|
|
if (NULL != pszDest)
|
|
{
|
|
lstrcpy(pszDest, pszSrc);
|
|
}
|
|
return pszDest;
|
|
}
|
|
|
|
/* C M R U L I S T */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: CMRUList2
|
|
|
|
-------------------------------------------------------------------------*/
|
|
CMRUList2::CMRUList2(const DWSTR * prgDwStr, int cEntryMax, BOOL fReversed) :
|
|
m_prgDwStr (prgDwStr),
|
|
m_cEntryMax (cEntryMax),
|
|
m_fReversed (fReversed),
|
|
m_cEntry (0),
|
|
m_rgpEntry (NULL),
|
|
m_fDirty (FALSE)
|
|
{
|
|
DBGENTRY(CMRUList2::CMRUList2);
|
|
|
|
ASSERT(NULL != prgDwStr);
|
|
m_cCol = m_prgDwStr[0].dw;
|
|
|
|
int cb = m_cEntryMax * sizeof(PMRUE);
|
|
m_rgpEntry = new PMRUE[cb];
|
|
if (NULL == m_rgpEntry)
|
|
{
|
|
ERROR_OUT(("CMRUList2 - out of memory"));
|
|
return;
|
|
}
|
|
ZeroMemory(m_rgpEntry, cb);
|
|
|
|
RegEntry re(PszRegKey(), HKEY_CURRENT_USER);
|
|
if (ERROR_SUCCESS != re.GetError())
|
|
return;
|
|
|
|
m_cEntry = min(re.GetNumber(REGVAL_MRU_COUNT, 0), m_cEntryMax);
|
|
for (int i = 0; i < m_cEntry; i++)
|
|
{
|
|
m_rgpEntry[i] = LoadEntry(&re, i);
|
|
}
|
|
}
|
|
|
|
CMRUList2::~CMRUList2()
|
|
{
|
|
DBGENTRY(CMRUList2::~CMRUList2);
|
|
|
|
if (m_fDirty)
|
|
{
|
|
Save();
|
|
}
|
|
|
|
for (int i = 0; i < m_cEntry; i++)
|
|
{
|
|
DeleteEntry(m_rgpEntry[i]);
|
|
}
|
|
delete m_rgpEntry;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
PMRUE CMRUList2::LoadEntry(RegEntry * pre, int iItem)
|
|
{
|
|
if (m_fReversed)
|
|
{
|
|
iItem = (m_cEntry - (iItem+1));
|
|
}
|
|
|
|
PMRUE pEntry = (PMRUE) new PVOID[m_cCol*sizeof(PVOID)];
|
|
if (NULL != pEntry)
|
|
{
|
|
PVOID ** ppv = (PVOID **) pEntry;
|
|
for (int iCol = 0; iCol < m_cCol; iCol++, ppv++)
|
|
{
|
|
TCHAR szKey[MAX_PATH];
|
|
wsprintf(szKey, TEXT("%s%d"), PszPrefixForCol(iCol), iItem);
|
|
switch (MruTypeForCol(iCol))
|
|
{
|
|
default:
|
|
case MRUTYPE_SZ:
|
|
* (LPTSTR *)ppv = PszAlloc(pre->GetString(szKey));
|
|
break;
|
|
case MRUTYPE_DW:
|
|
* (DWORD *) ppv = pre->GetNumber(szKey);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pEntry;
|
|
}
|
|
|
|
VOID CMRUList2::StoreEntry(RegEntry * pre, int iItem)
|
|
{
|
|
PVOID ** ppv = (PVOID **) GetEntry(iItem);
|
|
|
|
if (m_fReversed)
|
|
{
|
|
iItem = (m_cEntry - (iItem+1));
|
|
}
|
|
|
|
for (int iCol = 0; iCol < m_cCol; iCol++, ppv++)
|
|
{
|
|
TCHAR szKey[MAX_PATH];
|
|
wsprintf(szKey, TEXT("%s%d"), PszPrefixForCol(iCol), iItem);
|
|
switch (MruTypeForCol(iCol))
|
|
{
|
|
default:
|
|
case MRUTYPE_SZ:
|
|
pre->SetValue(szKey, * (LPCTSTR *)ppv);
|
|
break;
|
|
case MRUTYPE_DW:
|
|
pre->SetValue(szKey, * (ULONG *) ppv);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CMRUList2::DeleteEntry(PMRUE pEntry)
|
|
{
|
|
PVOID ** ppv = (PVOID **) pEntry;
|
|
for (int iCol = 0; iCol < m_cCol; iCol++, ppv++)
|
|
{
|
|
switch (MruTypeForCol(iCol))
|
|
{
|
|
default:
|
|
case MRUTYPE_SZ:
|
|
delete *ppv;
|
|
break;
|
|
case MRUTYPE_DW:
|
|
break;
|
|
}
|
|
}
|
|
delete pEntry;
|
|
}
|
|
|
|
VOID CMRUList2::DeleteEntry(int iItem)
|
|
{
|
|
if ((iItem < 0) || (iItem >= m_cEntry))
|
|
return; // nothing to do
|
|
|
|
// delete the data
|
|
DeleteEntry(m_rgpEntry[iItem]);
|
|
|
|
// decrement the count
|
|
m_cEntry--;
|
|
|
|
// shift items up
|
|
for ( ; iItem < m_cEntry; iItem++)
|
|
{
|
|
m_rgpEntry[iItem] = m_rgpEntry[iItem+1];
|
|
}
|
|
|
|
// the list has been modified
|
|
m_fDirty = TRUE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------//
|
|
// CMRUList2::DeleteEntry. //
|
|
// This DeleteEntry() deletes the first entry it finds thats primary //
|
|
// string matches the one passed in. //
|
|
//--------------------------------------------------------------------------//
|
|
void
|
|
CMRUList2::DeleteEntry
|
|
(
|
|
const TCHAR * const primaryString
|
|
){
|
|
int items = GetNumEntries();
|
|
|
|
for( int nn = 0; nn < items; nn++ )
|
|
{
|
|
if( StrCmpI( primaryString, * ((const TCHAR * const * const) m_rgpEntry[ nn ]) ) == 0 )
|
|
{
|
|
DeleteEntry( nn );
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // End of CMRUList2::DeleteEntry.
|
|
|
|
|
|
/* C O M P A R E E N T R Y */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: CompareEntry
|
|
|
|
-------------------------------------------------------------------------*/
|
|
int CMRUList2::CompareEntry(int iItem, PMRUE pEntry)
|
|
{
|
|
ASSERT(NULL != pEntry);
|
|
|
|
int iRet = 0;
|
|
|
|
PVOID * ppv1 = (PVOID *) GetEntry(iItem);
|
|
PVOID * ppv2 = (PVOID *) pEntry;
|
|
for (int iCol = 0; iCol < m_cCol; iCol++, ppv1++, ppv2++)
|
|
{
|
|
switch (MruTypeForCol(iCol))
|
|
{
|
|
default:
|
|
case MRUTYPE_SZ:
|
|
iRet = lstrcmpi(* (LPCTSTR *) ppv1, * (LPCTSTR *) ppv2);
|
|
break;
|
|
case MRUTYPE_DW:
|
|
iRet = (* (int *) ppv1) - (* (int *) ppv2);
|
|
break;
|
|
}
|
|
|
|
if (0 != iRet)
|
|
break;
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/* F I N D E N T R Y */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: FindEntry
|
|
|
|
Return -1 if the item is not found.
|
|
-------------------------------------------------------------------------*/
|
|
int CMRUList2::FindEntry(PMRUE pEntry)
|
|
{
|
|
int cItems = GetNumEntries();
|
|
for (int i = 0; i < cItems; i++)
|
|
{
|
|
if (0 == CompareEntry(i, pEntry))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1; // not found
|
|
}
|
|
|
|
|
|
|
|
|
|
/* S A V E */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: Save
|
|
|
|
-------------------------------------------------------------------------*/
|
|
HRESULT CMRUList2::Save(void)
|
|
{
|
|
DBGENTRY(CMRUList2::Save);
|
|
|
|
// Retrieve the data from the registry
|
|
RegEntry re(PszRegKey(), HKEY_CURRENT_USER);
|
|
if (ERROR_SUCCESS != re.GetError())
|
|
return E_FAIL;
|
|
|
|
re.SetValue(REGVAL_MRU_COUNT, m_cEntry);
|
|
for (int i = 0; i < m_cEntry; i++)
|
|
{
|
|
StoreEntry(&re, i);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* S H I F T E N T R I E S D O W N */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: ShiftEntriesDown
|
|
|
|
Shift the entires down by one slot leaving the first position open.
|
|
-------------------------------------------------------------------------*/
|
|
VOID CMRUList2::ShiftEntriesDown(int cItem)
|
|
{
|
|
if (cItem < 1)
|
|
return; // nothing to do
|
|
|
|
int iItem;
|
|
for (iItem = cItem; iItem > 0; iItem--)
|
|
{
|
|
m_rgpEntry[iItem] = m_rgpEntry[iItem-1];
|
|
}
|
|
|
|
// the list has been modified
|
|
m_fDirty = TRUE;
|
|
}
|
|
|
|
|
|
/* M O V E E N T R Y T O T O P */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: MoveEntryToTop
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID CMRUList2::MoveEntryToTop(int iItem)
|
|
{
|
|
DBGENTRY(CMRUList2::MoveEntryToTop);
|
|
|
|
if ((iItem < 1) || (iItem >= m_cEntry))
|
|
return; // nothing to do
|
|
|
|
PMRUE pEntry = GetEntry(iItem);
|
|
ShiftEntriesDown(iItem);
|
|
m_rgpEntry[0] = pEntry;
|
|
}
|
|
|
|
|
|
/* A D D E N T R Y */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: AddEntry
|
|
|
|
Put the entry into the top of the list.
|
|
The data is owned by the list after this.
|
|
|
|
Returns:
|
|
S_OK - added to the head of the list
|
|
S_FALSE - already in list (item is moved to top)
|
|
-------------------------------------------------------------------------*/
|
|
HRESULT CMRUList2::AddEntry(PMRUE pEntry)
|
|
{
|
|
DBGENTRY(CMRUList2::AddEntry);
|
|
|
|
// the list has been modified
|
|
m_fDirty = TRUE;
|
|
|
|
int iItem = FindEntry(pEntry);
|
|
if (-1 != iItem)
|
|
{
|
|
// This entry already exists, move it to the top:
|
|
MoveEntryToTop(iItem);
|
|
DeleteEntry(pEntry); // don't need this data
|
|
return S_FALSE; // Success, but already in the list
|
|
}
|
|
|
|
int cShift;
|
|
if (m_cEntryMax == m_cEntry)
|
|
{
|
|
// drop the last item
|
|
DeleteEntry(m_rgpEntry[m_cEntry-1]);
|
|
cShift = m_cEntry-1;
|
|
}
|
|
else
|
|
{
|
|
cShift = m_cEntry;
|
|
m_cEntry++;
|
|
}
|
|
ShiftEntriesDown(cShift);
|
|
|
|
// add it to the head of the list
|
|
m_rgpEntry[0] = pEntry;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CMRUList2::AddEntry(LPCTSTR pcsz)
|
|
{
|
|
LPTSTR * ppsz = new LPTSTR;
|
|
LPTSTR psz = PszAlloc(pcsz);
|
|
if ((NULL == ppsz) || (NULL == psz))
|
|
{
|
|
delete ppsz;
|
|
delete psz;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppsz = psz;
|
|
|
|
return AddEntry((PMRUE) ppsz);
|
|
}
|
|
|
|
HRESULT CMRUList2::AddEntry(LPCTSTR pcsz1, LPCTSTR pcsz2)
|
|
{
|
|
PSZSZ pSzSz = new SZSZ;
|
|
if (NULL == pSzSz)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pSzSz->psz1 = PszAlloc(pcsz1);
|
|
pSzSz->psz2 = PszAlloc(pcsz2);
|
|
if ((NULL == pSzSz->psz1) || (NULL == pSzSz->psz1))
|
|
{
|
|
// something failed - don't add anything
|
|
DeleteEntry(pSzSz);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return AddEntry((PMRUE) pSzSz);
|
|
}
|
|
|
|
HRESULT CMRUList2::AddEntry(LPCTSTR pcsz1, LPCTSTR pcsz2, DWORD dw3)
|
|
{
|
|
PSZSZDW pData = new SZSZDW;
|
|
if (NULL == pData)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pData->psz1 = PszAlloc(pcsz1);
|
|
pData->psz2 = PszAlloc(pcsz2);
|
|
if ((NULL == pData->psz1) || (NULL == pData->psz1))
|
|
{
|
|
// something failed - don't add anything
|
|
DeleteEntry(pData);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pData->dw = dw3;
|
|
|
|
return AddEntry((PMRUE) pData);
|
|
}
|
|
|
|
|
|
/* P S Z E N T R Y */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: PszEntry
|
|
|
|
Return the main string associated with the entry
|
|
-------------------------------------------------------------------------*/
|
|
LPCTSTR CMRUList2::PszEntry(int iItem)
|
|
{
|
|
PMRUE pEntry = GetEntry(iItem);
|
|
return (LPCTSTR) * ((LPTSTR *)pEntry);
|
|
}
|
|
|
|
LPCTSTR CMRUList2::PszData2(int iItem)
|
|
{
|
|
PMRUE pEntry = GetEntry(iItem);
|
|
LPTSTR * ppsz = ((LPTSTR *)pEntry);
|
|
return * (ppsz+1);
|
|
}
|
|
|
|
DWORD_PTR CMRUList2::PszData3(int iItem)
|
|
{
|
|
PMRUE pEntry = GetEntry(iItem);
|
|
LPTSTR * ppsz = ((LPTSTR *)pEntry);
|
|
return (DWORD_PTR) * (ppsz+2);
|
|
}
|
|
|
|
|