/*----------------------------------------------------------------------------- Microsoft Denali Microsoft Confidential Copyright 1996 Microsoft Corporation. All Rights Reserved. Component: File/Application map File: CFileApp.cpp Owner: cgrant File/Application mapping implementation -----------------------------------------------------------------------------*/ #include "denpre.h" #pragma hdrstop #include "dbgutil.h" #include "memchk.h" CFileApplicationMap g_FileAppMap; /*=================================================================== CFileApplnList::CFileApplnList Constructor Parameters: None Returns: Nothing ===================================================================*/ CFileApplnList::CFileApplnList() : m_pszFilename(NULL), m_fInited(FALSE) { } /*=================================================================== CFileApplnList::~CFileApplnList Destructor Parameters: None Returns: Nothing ===================================================================*/ CFileApplnList::~CFileApplnList() { // We should have no applications in our list DBG_ASSERT(m_rgpvApplications.Count() == 0); // Free the string used as the hash key if (m_pszFilename) { delete [] m_pszFilename; m_pszFilename = NULL; } } /*=================================================================== CFileApplnList::Init Initialize the file application list by setting the key to file name Parameters: pApplication pointer to the applicaiton Returns: S_OK if successful ===================================================================*/ HRESULT CFileApplnList::Init(const TCHAR* pszFilename) { HRESULT hr = S_OK; DBG_ASSERT(pszFilename); // Make a copy of the file name to // use as the hash key DWORD cch = _tcslen(pszFilename); m_pszFilename = new TCHAR[cch+1]; if (!m_pszFilename) { return E_OUTOFMEMORY; } _tcscpy(m_pszFilename, pszFilename); if (FAILED(CLinkElem::Init(m_pszFilename, cch*sizeof(TCHAR)))) { return E_FAIL; } m_fInited = TRUE; return hr; } /*=================================================================== CFileApplnList::UnInit Clean up the application list Parameters: pApplication pointer to the applicaiton Returns: S_OK if successful ===================================================================*/ HRESULT CFileApplnList::UnInit(void) { HRESULT hr = S_OK; DBG_ASSERT(m_fInited); while(m_rgpvApplications.Count()) { CAppln* pAppln = static_cast(m_rgpvApplications[0]); DBG_ASSERT(pAppln); // Remove this appliation from the array m_rgpvApplications.Remove(pAppln); // Release the array's refcount on the application // This may result in the application being deleted pAppln->Release(); } m_rgpvApplications.Clear(); m_fInited = FALSE; return hr; } /*=================================================================== CFileApplnList::AddApplication Add an application pointer to the list of applications Parameters: pApplication pointer to the applicaiton Returns: S_OK if successful Comments The caller should hold a lock on the hash table containing the element ===================================================================*/ HRESULT CFileApplnList::AddApplication(void *pApplication) { DBG_ASSERT(m_fInited); DBG_ASSERT(pApplication); HRESULT hr = S_OK; int index; // See if the application is alreay in the list hr = m_rgpvApplications.Find(pApplication, &index); if (hr == S_FALSE) { // Not found, add it. // We are going to hold a reference to the application static_cast(pApplication)->AddRef(); // Add the application to the list if (FAILED(hr = m_rgpvApplications.Append(pApplication))) { // We failed so give back the refcount we took. static_cast(pApplication)->Release(); } } return hr; } /*=================================================================== CFileApplnList::RemoveApplication Removes an application pointer from the list of applications Parameters: pApplication pointer to the applicaiton Returns: S_OK if successful Comments The caller should hold a lock on the hash table containing the element ===================================================================*/ HRESULT CFileApplnList::RemoveApplication(void *pApplication) { DBG_ASSERT(m_fInited); DBG_ASSERT(pApplication); HRESULT hr = S_OK; int index; #ifdef DBG_NOTIFICATION #if UNICODE DBGPRINTF((DBG_CONTEXT, "Removing Application entry for %S\n", reinterpret_cast(pApplication)->GetApplnPath())); #else DBGPRINTF((DBG_CONTEXT, "Removing Application entry for %s\n", reinterpret_cast(pApplication)->GetApplnPath())); #endif #endif // DBG_NOTIFICATION // Remove the application from the list hr = m_rgpvApplications.Remove(pApplication); // If the count of applications in the list goes // to 0, remove the element from the hash table // and delete it if (m_rgpvApplications.Count() == 0) { #ifdef DBG_NOTIFICATION #if UNICODE DBGPRINTF((DBG_CONTEXT, "Deleting File/Application entry for %s\n", m_pszFilename)); #else DBGPRINTF((DBG_CONTEXT, "Deleting File/Application entry for %s\n", m_pszFilename)); #endif #endif // DBG_NOTIFICATION g_FileAppMap.RemoveElem(this); delete this; } // If we found the application to remove it // we need to release a ref count on the application if (hr == S_OK) { static_cast(pApplication)->Release(); } return hr; } /*=================================================================== CFileApplnList::GetShutdownApplications Obtain a list of applications to shut down Parameters: None ===================================================================*/ VOID CFileApplnList::GetShutdownApplications(CPtrArray *prgpapplnRestartList) { DBG_ASSERT(m_fInited); HRESULT hr = S_OK; #ifdef DBG_NOTIFICATION #if UNICODE DBGPRINTF((DBG_CONTEXT, "[CFileApplnList] Shutting down %d applications depending on %S.\n", m_rgpvApplications.Count(), m_pszFilename)); #else DBGPRINTF((DBG_CONTEXT, "[CFileApplnList] Shutting down %d applications depending on %s.\n", m_rgpvApplications.Count(), m_pszFilename)); #endif #endif // DBG_NOTIFICATION for (int i = m_rgpvApplications.Count() - 1; i >= 0; i--) { CAppln* pAppln = static_cast(m_rgpvApplications[i]); DBG_ASSERT(pAppln); // If not already tombstoned, shut the application down. // When the application is uninited it will remove itself // from this list if (!pAppln->FTombstone()) { pAppln->AddRef(); prgpapplnRestartList->Append(pAppln); } } } /*=================================================================== CFileApplicationMap::CFileApplicationMap Constructor Parameters: None Returns: Nothing ===================================================================*/ CFileApplicationMap::CFileApplicationMap() : m_fInited(FALSE), m_fHashTableInited(FALSE), m_fCriticalSectionInited(FALSE) { } /*=================================================================== CFileApplicationMap::~CFileApplicationMap Destructor Parameters: None Returns: Nothing ===================================================================*/ CFileApplicationMap::~CFileApplicationMap() { if (m_fInited) { UnInit(); } } /*=================================================================== CFileApplicationMap::Init Initialize the hash table and critical section Parameters: None Returns: S_OK if successful ===================================================================*/ HRESULT CFileApplicationMap::Init() { HRESULT hr = S_OK; Assert(!m_fInited); hr = CHashTable::Init(NUM_FILEAPP_HASHING_BUCKETS); if (FAILED(hr)) { return hr; } m_fHashTableInited = TRUE; // Init critical section ErrInitCriticalSection(&m_csLock, hr); if (FAILED(hr)) { return(hr); } m_fCriticalSectionInited = TRUE; m_fInited = TRUE; return S_OK; } /*=================================================================== CFileApplicationMap::UnInit Uninitialize the hash table and critical section Free any applications lists remaining in the hash table elements Parameters: None Returns: S_OK if successful ===================================================================*/ HRESULT CFileApplicationMap::UnInit() { if (m_fHashTableInited) { // Delete any elements remaining in the hash table CFileApplnList *pNukeElem = static_cast(Head()); while (pNukeElem != NULL) { CFileApplnList *pNext = static_cast(pNukeElem->m_pNext); pNukeElem->UnInit(); delete pNukeElem; pNukeElem = pNext; } // Uninit the hash table CHashTable::UnInit(); m_fHashTableInited = FALSE; } if (m_fCriticalSectionInited) { DeleteCriticalSection(&m_csLock); m_fCriticalSectionInited = FALSE; } m_fInited = FALSE; return S_OK; } /*=================================================================== CFileApplicationMap::AddFileApplication Add a file-application pair to the hash table Parameters: pszFilename pointer to string containing name of the file pAppln pointer to the application associated with the file Returns: S_OK if successful ===================================================================*/ HRESULT CFileApplicationMap::AddFileApplication(const TCHAR* pszFilename, CAppln* pAppln) { // We must have both a file and an application DBG_ASSERT(pszFilename); DBG_ASSERT(pAppln); HRESULT hr = S_OK; Lock(); #ifdef DBG_NOTIFICATION #if UNICODE DBGPRINTF((DBG_CONTEXT, "Adding File/Application entry for %S\n", pszFilename)); #else DBGPRINTF((DBG_CONTEXT, "Adding File/Application entry for %s\n", pszFilename)); #endif #endif // DBG_NOTIFICATION // See if the file already has an entry CFileApplnList* pFileApplns = static_cast(CHashTable::FindElem(pszFilename, _tcslen(pszFilename)*sizeof(TCHAR))); if (pFileApplns == NULL) { // Not found, create new CFileApplnList object pFileApplns = new CFileApplnList; if (!pFileApplns) { hr = E_OUTOFMEMORY; goto LExit; } // Init CFileApplnList object hr = pFileApplns->Init(pszFilename); if (FAILED(hr)) { delete pFileApplns; goto LExit; } // Add FileApplns object to hash table if (!CHashTable::AddElem(pFileApplns)) { delete pFileApplns; hr = E_FAIL; goto LExit; } } // Add the application to the list associated with this file hr = pFileApplns->AddApplication(pAppln); // Keep this file mapping in the application // The application will remove itself from this list // when it is uninited. pAppln->AddFileApplnEntry(pFileApplns); LExit: UnLock(); return hr; } /*=================================================================== CFileApplicationMap::ShutdownApplications Shutdown the applications associated with a file Parameters: pszFilename pointer to string containing name of the file Returns: TRUE if an application was shutdown, FALSE otherwise ===================================================================*/ BOOL CFileApplicationMap::ShutdownApplications(const TCHAR *pszFilename) { DBG_ASSERT(pszFilename); BOOL fResult = TRUE; Lock(); CFileApplnList* pFileApplns = static_cast(CHashTable::FindElem(pszFilename, _tcslen(pszFilename)*sizeof(TCHAR))); if (pFileApplns) { // Get a list of applications we need to shutdown CPtrArray rgpapplnRestartList; pFileApplns->GetShutdownApplications(&rgpapplnRestartList); // Now that we have the list of applications we need to shut down // we can release the lock UnLock(); for (int i = 0; i < rgpapplnRestartList.Count(); i++) { CAppln *pAppln = (CAppln *)rgpapplnRestartList[i]; pAppln->Restart(); pAppln->Release(); } // Flush the script cache if any applications were restarted if (rgpapplnRestartList.Count()) g_ScriptManager.FlushAll(); } else { // No applications to shut down, release the lock UnLock(); fResult = FALSE; } return fResult; }