|
|
//+----------------------------------------------------------------------------
//
// File: PbkCache.cpp
//
// Module: Common pbk parser
//
// Synopsis: Caches parsed pbk files to improve performance. Through
// XP, we would re-load and re-parse the phonebook file
// every time a RAS API is called. Really, we need to
// reload the file only when the file on disk changes or when
// a new device is introduced to the system.
//
// Copyright (c) 2000-2001 Microsoft Corporation
//
// Author: 11/03/01 Paul Mayfield
//
//+----------------------------------------------------------------------------
#ifdef _PBK_CACHE_
extern "C" { #include <windows.h> // Win32 core
#include <pbkp.h>
#include <nouiutil.h>
#include <dtl.h>
}
#define PBK_CACHE_MAX_RASFILES 500 // Should match MAX_RASFILES
#define PBK_CACHE_INVALID_SLOT (PBK_CACHE_MAX_RASFILES + 1)
//+----------------------------------------------------------------------------
//
// Synopsis: A node in the pbk cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
class PbkCacheNode { public: PbkCacheNode(); ~PbkCacheNode();
VOID Close(); DWORD SetFileName(IN WCHAR* pszFileName);
WCHAR* GetPath() {return m_pbFile.pszPath;} FILETIME GetReadTime() {return m_ftRead;} DWORD GetLastWriteTime(FILETIME* pTime);
DWORD Reload();
DTLLIST* GetEntryList() {return m_pbFile.pdtllistEntries;} private: PBFILE m_pbFile; FILETIME m_ftRead; PWCHAR m_pszFileName; };
//+----------------------------------------------------------------------------
//
// Synopsis: The phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
class PbkCache { public: PbkCache(); ~PbkCache();
DWORD Initialize();
DWORD GetEntry( IN WCHAR* pszPhonebook, IN WCHAR* pszEntry, OUT DTLNODE** ppEntryNode);
VOID Lock() {EnterCriticalSection(&m_csLock);}
VOID Unlock() {LeaveCriticalSection(&m_csLock);}
private: PbkCacheNode* m_Files[PBK_CACHE_MAX_RASFILES]; CRITICAL_SECTION m_csLock;
DWORD InsertNewNode( IN PWCHAR pszPhonebook, IN DWORD dwSlot, OUT PbkCacheNode** ppNode);
VOID FindFile( IN WCHAR* pszFileName, OUT PbkCacheNode** ppNode, OUT DWORD* pdwIndex); };
static PbkCache* g_pPbkCache = NULL;
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCacheNode::PbkCacheNode() : m_pszFileName(NULL) { ZeroMemory(&m_pbFile, sizeof(m_pbFile)); ZeroMemory(&m_ftRead, sizeof(m_ftRead)); m_pbFile.hrasfile = -1; }
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCacheNode::~PbkCacheNode() { Close(); SetFileName(NULL); }
//+----------------------------------------------------------------------------
//
// Synopsis: Closes the file referred to by this cache node
//
// Created: pmay
//
//-----------------------------------------------------------------------------
VOID PbkCacheNode::Close() { if (m_pbFile.hrasfile != -1) { ClosePhonebookFile(&m_pbFile); }
ZeroMemory(&m_pbFile, sizeof(m_pbFile)); m_pbFile.hrasfile = -1; ZeroMemory(&m_ftRead, sizeof(m_ftRead)); }
//+----------------------------------------------------------------------------
//
// Synopsis: Sets the file name for this node
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCacheNode::SetFileName( IN WCHAR* pszFileName) { Free0(m_pszFileName); m_pszFileName = NULL;
// Copy the file name
//
if (pszFileName) { m_pszFileName = StrDup( pszFileName ); if (m_pszFileName == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } }
return NO_ERROR; }
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCacheNode::GetLastWriteTime( OUT FILETIME* pTime) { BOOL fOk; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwErr = NO_ERROR;
//For whistler bug 537369 gangz
//We cannot leave the handle open for ever, have to close it after using it.
// so delete the m_hFile data member
// Rather, re-open it and get its information by handle
if (m_pszFileName == NULL || TEXT('\0') == m_pszFileName[0] ) { return ERROR_CAN_NOT_COMPLETE; }
if( NULL == pTime ) { return ERROR_INVALID_PARAMETER; }
dwErr = GetFileLastWriteTime( m_pszFileName, pTime );
return dwErr; }
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCacheNode::Reload() { DWORD dwErr = NO_ERROR;
if (m_pszFileName == NULL) { return ERROR_CAN_NOT_COMPLETE; }
do { Close(); // Load the RasFile
//
dwErr = ReadPhonebookFileEx( m_pszFileName, NULL, NULL, RPBF_NoCreate, &m_pbFile, &m_ftRead); if (dwErr != NO_ERROR) { break; } } while (FALSE);
// Cleanup
//
{ if (dwErr != NO_ERROR) { Close(); } }
return dwErr; }
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCache::PbkCache() { ZeroMemory(m_Files, sizeof(m_Files)); }
//+----------------------------------------------------------------------------
//
// Synopsis: Destroys the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCache::~PbkCache() { UINT i; DeleteCriticalSection(&m_csLock); for (i = 0; i < PBK_CACHE_MAX_RASFILES; i++) { if (m_Files[i]) { delete m_Files[i]; m_Files[i] = NULL; } } }
//+----------------------------------------------------------------------------
//
// Synopsis: Initializes the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCache::Initialize() { DWORD dwErr = NO_ERROR; __try { InitializeCriticalSection(&m_csLock); } __except (EXCEPTION_EXECUTE_HANDLER) { dwErr = HRESULT_FROM_WIN32(GetExceptionCode()); }
return dwErr; }
//+----------------------------------------------------------------------------
//
// Synopsis: Initializes the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCache::GetEntry( IN WCHAR* pszPhonebook, IN WCHAR* pszEntry, OUT DTLNODE** ppEntryNode) { DWORD dwErr, dwRet, dwSlot = PBK_CACHE_INVALID_SLOT; PbkCacheNode* pCacheNode = NULL; DTLNODE* pEntryNode, *pCopyNode = NULL; PBENTRY* pEntry; FILETIME ftWrite, ftRead; BOOL fFound = FALSE;
TRACE2("PbkCache::GetEntry %S %S", pszPhonebook, pszEntry);
Lock(); do { FindFile(pszPhonebook, &pCacheNode, &dwSlot); // The file is not in the cache. Insert it.
//
if (pCacheNode == NULL) { TRACE1("Inserting new pbk cache node %d", dwSlot); dwErr = InsertNewNode(pszPhonebook, dwSlot, &pCacheNode); if (dwErr != NO_ERROR) { break; } }
// The file is in the cache. Reload it if needed
//
else { ftRead = pCacheNode->GetReadTime(); dwErr = pCacheNode->GetLastWriteTime(&ftWrite); if (dwErr != NO_ERROR) { break; }
if (CompareFileTime(&ftRead, &ftWrite) < 0) { TRACE2("Reloading pbk cache %d (%S)", dwSlot, pszPhonebook); dwErr = pCacheNode->Reload(); if (dwErr != NO_ERROR) { break; } } }
// Find the entry in question
//
dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY; for (pEntryNode = DtlGetFirstNode( pCacheNode->GetEntryList() ); pEntryNode; pEntryNode = DtlGetNextNode( pEntryNode )) { pEntry = (PBENTRY*) DtlGetData(pEntryNode); if (lstrcmpi(pEntry->pszEntryName, pszEntry) == 0) { fFound = TRUE; dwErr = NO_ERROR; pCopyNode = DuplicateEntryNode(pEntryNode); if (pCopyNode == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } break; } } } while (FALSE);
Unlock();
// Prepare the return value
//
if (pCopyNode) { *ppEntryNode = pCopyNode; dwRet = NO_ERROR; } else if (dwErr == ERROR_CANNOT_FIND_PHONEBOOK_ENTRY) { dwRet = dwErr; } else { dwRet = ERROR_CANNOT_OPEN_PHONEBOOK; }
TRACE3( "PbkCache::GetEntry returning 0x%x 0x%x fFound=%d", dwErr, dwRet, fFound);
return dwRet; }
//+----------------------------------------------------------------------------
//
// Synopsis: Searches for a phonebook file in the cache. If the file is not
// in the cache, then the index in which to insert that file is
// returned.
//
// Return values:
// If file is found, *ppNode has node and *pdwIndex has the index
// If file not found, *ppNode == NULL. *pdwIndex has insert point
// If cache is full and file not found:
// *ppNode == NULL,
// *pdwIndex == PBK_CACHE_INVALID_SLOT
// Created: pmay
//
//-----------------------------------------------------------------------------
VOID PbkCache::FindFile( IN WCHAR* pszFileName, OUT PbkCacheNode** ppNode, OUT DWORD* pdwIndex) { DWORD i;
*pdwIndex = PBK_CACHE_INVALID_SLOT; for (i = 0; i < PBK_CACHE_MAX_RASFILES; i++) { if (m_Files[i]) { if (lstrcmpi(pszFileName, m_Files[i]->GetPath()) == 0) { *ppNode = m_Files[i]; *pdwIndex = i; break; } } else { if (*pdwIndex == PBK_CACHE_INVALID_SLOT) { *pdwIndex = i; } } } }
//+----------------------------------------------------------------------------
//
// Synopsis: Inserts a node in the give slot in the cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCache::InsertNewNode( IN PWCHAR pszPhonebook, IN DWORD dwSlot, OUT PbkCacheNode** ppNode) { PbkCacheNode* pCacheNode = NULL; DWORD dwErr = NO_ERROR; do { if (dwSlot == PBK_CACHE_INVALID_SLOT) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
pCacheNode = new PbkCacheNode(); if (pCacheNode == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
dwErr = pCacheNode->SetFileName(pszPhonebook); if (dwErr != NO_ERROR) { break; } dwErr = pCacheNode->Reload(); if (dwErr != NO_ERROR) { break; }
m_Files[dwSlot] = pCacheNode; *ppNode = pCacheNode; } while (FALSE);
// Cleanup
//
{ if (dwErr != NO_ERROR) { if (pCacheNode) { delete pCacheNode; } } }
return dwErr; }
//+----------------------------------------------------------------------------
//
// Synopsis: check if the phonebook cache is initialized
//
// Created: gangz
//
//-----------------------------------------------------------------------------
BOOL IsPbkCacheInit() {
return g_pPbkCache ? TRUE : FALSE; }
//+----------------------------------------------------------------------------
//
// Synopsis: Initializes the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCacheInit() { DWORD dwErr;
ASSERT(g_pPbkCache == NULL); g_pPbkCache = new PbkCache; if (g_pPbkCache == NULL) { return ERROR_NOT_ENOUGH_MEMORY; }
dwErr = g_pPbkCache->Initialize(); if (dwErr != NO_ERROR) { delete g_pPbkCache; g_pPbkCache = NULL; } return dwErr; }
//+----------------------------------------------------------------------------
//
// Synopsis: Cleans up the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
VOID PbkCacheCleanup() { PbkCache* pCache = g_pPbkCache;
g_pPbkCache = NULL; if (pCache) { delete pCache; } }
//+----------------------------------------------------------------------------
//
// Synopsis: Gets an entry from the cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD PbkCacheGetEntry( IN WCHAR* pszPhonebook, IN WCHAR* pszEntry, OUT DTLNODE** ppEntryNode) { if (g_pPbkCache) { return g_pPbkCache->GetEntry(pszPhonebook, pszEntry, ppEntryNode); }
return ERROR_CAN_NOT_COMPLETE; }
#endif //endof #ifdef _PBK_CACHE_
|