Source code of Windows XP (NT5)
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.

534 lines
13 KiB

  1. /*-----------------------------------------------------------------------------
  2. Microsoft Denali
  3. Microsoft Confidential
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: File/Application map
  6. File: CFileApp.cpp
  7. Owner: cgrant
  8. File/Application mapping implementation
  9. -----------------------------------------------------------------------------*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "dbgutil.h"
  13. #include "memchk.h"
  14. CFileApplicationMap g_FileAppMap;
  15. /*===================================================================
  16. CFileApplnList::CFileApplnList
  17. Constructor
  18. Parameters:
  19. None
  20. Returns:
  21. Nothing
  22. ===================================================================*/
  23. CFileApplnList::CFileApplnList() :
  24. m_pszFilename(NULL),
  25. m_fInited(FALSE)
  26. {
  27. }
  28. /*===================================================================
  29. CFileApplnList::~CFileApplnList
  30. Destructor
  31. Parameters:
  32. None
  33. Returns:
  34. Nothing
  35. ===================================================================*/
  36. CFileApplnList::~CFileApplnList()
  37. {
  38. // We should have no applications in our list
  39. DBG_ASSERT(m_rgpvApplications.Count() == 0);
  40. // Free the string used as the hash key
  41. if (m_pszFilename)
  42. {
  43. delete [] m_pszFilename;
  44. m_pszFilename = NULL;
  45. }
  46. }
  47. /*===================================================================
  48. CFileApplnList::Init
  49. Initialize the file application list by setting the key to file name
  50. Parameters:
  51. pApplication pointer to the applicaiton
  52. Returns:
  53. S_OK if successful
  54. ===================================================================*/
  55. HRESULT CFileApplnList::Init(const TCHAR* pszFilename)
  56. {
  57. HRESULT hr = S_OK;
  58. DBG_ASSERT(pszFilename);
  59. // Make a copy of the file name to
  60. // use as the hash key
  61. DWORD cch = _tcslen(pszFilename);
  62. m_pszFilename = new TCHAR[cch+1];
  63. if (!m_pszFilename)
  64. {
  65. return E_OUTOFMEMORY;
  66. }
  67. _tcscpy(m_pszFilename, pszFilename);
  68. if (FAILED(CLinkElem::Init(m_pszFilename, cch*sizeof(TCHAR))))
  69. {
  70. return E_FAIL;
  71. }
  72. m_fInited = TRUE;
  73. return hr;
  74. }
  75. /*===================================================================
  76. CFileApplnList::UnInit
  77. Clean up the application list
  78. Parameters:
  79. pApplication pointer to the applicaiton
  80. Returns:
  81. S_OK if successful
  82. ===================================================================*/
  83. HRESULT CFileApplnList::UnInit(void)
  84. {
  85. HRESULT hr = S_OK;
  86. DBG_ASSERT(m_fInited);
  87. while(m_rgpvApplications.Count())
  88. {
  89. CAppln* pAppln = static_cast<CAppln *>(m_rgpvApplications[0]);
  90. DBG_ASSERT(pAppln);
  91. // Remove this appliation from the array
  92. m_rgpvApplications.Remove(pAppln);
  93. // Release the array's refcount on the application
  94. // This may result in the application being deleted
  95. pAppln->Release();
  96. }
  97. m_rgpvApplications.Clear();
  98. m_fInited = FALSE;
  99. return hr;
  100. }
  101. /*===================================================================
  102. CFileApplnList::AddApplication
  103. Add an application pointer to the list of applications
  104. Parameters:
  105. pApplication pointer to the applicaiton
  106. Returns:
  107. S_OK if successful
  108. Comments
  109. The caller should hold a lock on the hash table containing
  110. the element
  111. ===================================================================*/
  112. HRESULT CFileApplnList::AddApplication(void *pApplication)
  113. {
  114. DBG_ASSERT(m_fInited);
  115. DBG_ASSERT(pApplication);
  116. HRESULT hr = S_OK;
  117. int index;
  118. // See if the application is alreay in the list
  119. hr = m_rgpvApplications.Find(pApplication, &index);
  120. if (hr == S_FALSE)
  121. {
  122. // Not found, add it.
  123. // We are going to hold a reference to the application
  124. static_cast<CAppln *>(pApplication)->AddRef();
  125. // Add the application to the list
  126. if (FAILED(hr = m_rgpvApplications.Append(pApplication)))
  127. {
  128. // We failed so give back the refcount we took.
  129. static_cast<CAppln *>(pApplication)->Release();
  130. }
  131. }
  132. return hr;
  133. }
  134. /*===================================================================
  135. CFileApplnList::RemoveApplication
  136. Removes an application pointer from the list of applications
  137. Parameters:
  138. pApplication pointer to the applicaiton
  139. Returns:
  140. S_OK if successful
  141. Comments
  142. The caller should hold a lock on the hash table containing
  143. the element
  144. ===================================================================*/
  145. HRESULT CFileApplnList::RemoveApplication(void *pApplication)
  146. {
  147. DBG_ASSERT(m_fInited);
  148. DBG_ASSERT(pApplication);
  149. HRESULT hr = S_OK;
  150. int index;
  151. #ifdef DBG_NOTIFICATION
  152. #if UNICODE
  153. DBGPRINTF((DBG_CONTEXT, "Removing Application entry for %S\n", reinterpret_cast<CAppln *>(pApplication)->GetApplnPath()));
  154. #else
  155. DBGPRINTF((DBG_CONTEXT, "Removing Application entry for %s\n", reinterpret_cast<CAppln *>(pApplication)->GetApplnPath()));
  156. #endif
  157. #endif // DBG_NOTIFICATION
  158. // Remove the application from the list
  159. hr = m_rgpvApplications.Remove(pApplication);
  160. // If the count of applications in the list goes
  161. // to 0, remove the element from the hash table
  162. // and delete it
  163. if (m_rgpvApplications.Count() == 0)
  164. {
  165. #ifdef DBG_NOTIFICATION
  166. #if UNICODE
  167. DBGPRINTF((DBG_CONTEXT, "Deleting File/Application entry for %s\n", m_pszFilename));
  168. #else
  169. DBGPRINTF((DBG_CONTEXT, "Deleting File/Application entry for %s\n", m_pszFilename));
  170. #endif
  171. #endif // DBG_NOTIFICATION
  172. g_FileAppMap.RemoveElem(this);
  173. delete this;
  174. }
  175. // If we found the application to remove it
  176. // we need to release a ref count on the application
  177. if (hr == S_OK)
  178. {
  179. static_cast<CAppln *>(pApplication)->Release();
  180. }
  181. return hr;
  182. }
  183. /*===================================================================
  184. CFileApplnList::GetShutdownApplications
  185. Obtain a list of applications to shut down
  186. Parameters:
  187. None
  188. ===================================================================*/
  189. VOID CFileApplnList::GetShutdownApplications(CPtrArray *prgpapplnRestartList)
  190. {
  191. DBG_ASSERT(m_fInited);
  192. HRESULT hr = S_OK;
  193. #ifdef DBG_NOTIFICATION
  194. #if UNICODE
  195. DBGPRINTF((DBG_CONTEXT, "[CFileApplnList] Shutting down %d applications depending on %S.\n", m_rgpvApplications.Count(), m_pszFilename));
  196. #else
  197. DBGPRINTF((DBG_CONTEXT, "[CFileApplnList] Shutting down %d applications depending on %s.\n", m_rgpvApplications.Count(), m_pszFilename));
  198. #endif
  199. #endif // DBG_NOTIFICATION
  200. for (int i = m_rgpvApplications.Count() - 1; i >= 0; i--)
  201. {
  202. CAppln* pAppln = static_cast<CAppln *>(m_rgpvApplications[i]);
  203. DBG_ASSERT(pAppln);
  204. // If not already tombstoned, shut the application down.
  205. // When the application is uninited it will remove itself
  206. // from this list
  207. if (!pAppln->FTombstone())
  208. {
  209. pAppln->AddRef();
  210. prgpapplnRestartList->Append(pAppln);
  211. }
  212. }
  213. }
  214. /*===================================================================
  215. CFileApplicationMap::CFileApplicationMap
  216. Constructor
  217. Parameters:
  218. None
  219. Returns:
  220. Nothing
  221. ===================================================================*/
  222. CFileApplicationMap::CFileApplicationMap()
  223. : m_fInited(FALSE),
  224. m_fHashTableInited(FALSE),
  225. m_fCriticalSectionInited(FALSE)
  226. {
  227. }
  228. /*===================================================================
  229. CFileApplicationMap::~CFileApplicationMap
  230. Destructor
  231. Parameters:
  232. None
  233. Returns:
  234. Nothing
  235. ===================================================================*/
  236. CFileApplicationMap::~CFileApplicationMap()
  237. {
  238. if (m_fInited)
  239. {
  240. UnInit();
  241. }
  242. }
  243. /*===================================================================
  244. CFileApplicationMap::Init
  245. Initialize the hash table and critical section
  246. Parameters:
  247. None
  248. Returns:
  249. S_OK if successful
  250. ===================================================================*/
  251. HRESULT CFileApplicationMap::Init()
  252. {
  253. HRESULT hr = S_OK;
  254. Assert(!m_fInited);
  255. hr = CHashTable::Init(NUM_FILEAPP_HASHING_BUCKETS);
  256. if (FAILED(hr))
  257. {
  258. return hr;
  259. }
  260. m_fHashTableInited = TRUE;
  261. // Init critical section
  262. ErrInitCriticalSection(&m_csLock, hr);
  263. if (FAILED(hr))
  264. {
  265. return(hr);
  266. }
  267. m_fCriticalSectionInited = TRUE;
  268. m_fInited = TRUE;
  269. return S_OK;
  270. }
  271. /*===================================================================
  272. CFileApplicationMap::UnInit
  273. Uninitialize the hash table and critical section
  274. Free any applications lists remaining in the hash
  275. table elements
  276. Parameters:
  277. None
  278. Returns:
  279. S_OK if successful
  280. ===================================================================*/
  281. HRESULT CFileApplicationMap::UnInit()
  282. {
  283. if (m_fHashTableInited)
  284. {
  285. // Delete any elements remaining in the hash table
  286. CFileApplnList *pNukeElem = static_cast<CFileApplnList *>(Head());
  287. while (pNukeElem != NULL)
  288. {
  289. CFileApplnList *pNext = static_cast<CFileApplnList *>(pNukeElem->m_pNext);
  290. pNukeElem->UnInit();
  291. delete pNukeElem;
  292. pNukeElem = pNext;
  293. }
  294. // Uninit the hash table
  295. CHashTable::UnInit();
  296. m_fHashTableInited = FALSE;
  297. }
  298. if (m_fCriticalSectionInited)
  299. {
  300. DeleteCriticalSection(&m_csLock);
  301. m_fCriticalSectionInited = FALSE;
  302. }
  303. m_fInited = FALSE;
  304. return S_OK;
  305. }
  306. /*===================================================================
  307. CFileApplicationMap::AddFileApplication
  308. Add a file-application pair to the hash table
  309. Parameters:
  310. pszFilename pointer to string containing name of the file
  311. pAppln pointer to the application associated with the file
  312. Returns:
  313. S_OK if successful
  314. ===================================================================*/
  315. HRESULT CFileApplicationMap::AddFileApplication(const TCHAR* pszFilename, CAppln* pAppln)
  316. {
  317. // We must have both a file and an application
  318. DBG_ASSERT(pszFilename);
  319. DBG_ASSERT(pAppln);
  320. HRESULT hr = S_OK;
  321. Lock();
  322. #ifdef DBG_NOTIFICATION
  323. #if UNICODE
  324. DBGPRINTF((DBG_CONTEXT, "Adding File/Application entry for %S\n", pszFilename));
  325. #else
  326. DBGPRINTF((DBG_CONTEXT, "Adding File/Application entry for %s\n", pszFilename));
  327. #endif
  328. #endif // DBG_NOTIFICATION
  329. // See if the file already has an entry
  330. CFileApplnList* pFileApplns = static_cast<CFileApplnList *>(CHashTable::FindElem(pszFilename, _tcslen(pszFilename)*sizeof(TCHAR)));
  331. if (pFileApplns == NULL)
  332. {
  333. // Not found, create new CFileApplnList object
  334. pFileApplns = new CFileApplnList;
  335. if (!pFileApplns)
  336. {
  337. hr = E_OUTOFMEMORY;
  338. goto LExit;
  339. }
  340. // Init CFileApplnList object
  341. hr = pFileApplns->Init(pszFilename);
  342. if (FAILED(hr))
  343. {
  344. delete pFileApplns;
  345. goto LExit;
  346. }
  347. // Add FileApplns object to hash table
  348. if (!CHashTable::AddElem(pFileApplns))
  349. {
  350. delete pFileApplns;
  351. hr = E_FAIL;
  352. goto LExit;
  353. }
  354. }
  355. // Add the application to the list associated with this file
  356. hr = pFileApplns->AddApplication(pAppln);
  357. // Keep this file mapping in the application
  358. // The application will remove itself from this list
  359. // when it is uninited.
  360. pAppln->AddFileApplnEntry(pFileApplns);
  361. LExit:
  362. UnLock();
  363. return hr;
  364. }
  365. /*===================================================================
  366. CFileApplicationMap::ShutdownApplications
  367. Shutdown the applications associated with a file
  368. Parameters:
  369. pszFilename pointer to string containing name of the file
  370. Returns:
  371. TRUE if an application was shutdown, FALSE otherwise
  372. ===================================================================*/
  373. BOOL CFileApplicationMap::ShutdownApplications(const TCHAR *pszFilename)
  374. {
  375. DBG_ASSERT(pszFilename);
  376. BOOL fResult = TRUE;
  377. Lock();
  378. CFileApplnList* pFileApplns = static_cast<CFileApplnList *>(CHashTable::FindElem(pszFilename, _tcslen(pszFilename)*sizeof(TCHAR)));
  379. if (pFileApplns)
  380. {
  381. // Get a list of applications we need to shutdown
  382. CPtrArray rgpapplnRestartList;
  383. pFileApplns->GetShutdownApplications(&rgpapplnRestartList);
  384. // Now that we have the list of applications we need to shut down
  385. // we can release the lock
  386. UnLock();
  387. for (int i = 0; i < rgpapplnRestartList.Count(); i++)
  388. {
  389. CAppln *pAppln = (CAppln *)rgpapplnRestartList[i];
  390. pAppln->Restart();
  391. pAppln->Release();
  392. }
  393. // Flush the script cache if any applications were restarted
  394. if (rgpapplnRestartList.Count())
  395. g_ScriptManager.FlushAll();
  396. }
  397. else
  398. {
  399. // No applications to shut down, release the lock
  400. UnLock();
  401. fResult = FALSE;
  402. }
  403. return fResult;
  404. }