// 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; /* 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); HRESULT ret = S_OK; // the list has been modified m_fDirty = TRUE; int cShift; int iItem = FindEntry(pEntry); if (-1 != iItem) { // This entry already exists, delete it so we get the new info DeleteEntry(m_rgpEntry[iItem]); cShift = iItem; ret = S_FALSE; // Success, but already in the list } else 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 ret; } 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); } /*------------------------------------------------------------------------- %%Function: GetString Return the data associated with the entry -------------------------------------------------------------------------*/ LPCTSTR CMRUList2::GetString(int iItem, int iCol) { if (!FValidIndex(iItem)) { return(NULL); } return(GetString(GetEntry(iItem), iCol)); } DWORD CMRUList2::GetDWORD(int iItem, int iCol) { if (!FValidIndex(iItem)) { return(0); } return(GetDWORD(GetEntry(iItem), iCol)); } LPCTSTR CMRUList2::GetString(PMRUE pEntry, int iCol) { if (iCol >= m_cCol || MRUTYPE_SZ != m_prgDwStr[iCol+1].dw ) { return(NULL); } LPTSTR * ppsz = reinterpret_cast(pEntry); return * (ppsz+iCol); } DWORD CMRUList2::GetDWORD(PMRUE pEntry, int iCol) { if (iCol >= m_cCol || MRUTYPE_DW != m_prgDwStr[iCol+1].dw ) { return(0); } DWORD * ppdw = reinterpret_cast(pEntry); return * (ppdw+iCol); }