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.

461 lines
14 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: strcache.cpp
  4. //
  5. // Contents: String cache for insert object dialog.
  6. //
  7. // Classes: CStringCache
  8. //
  9. // History: 02-May-99 MPrabhu Created
  10. //
  11. //-----------------------------------------------------------------------------
  12. #include "precomp.h"
  13. #include "common.h"
  14. #include "strcache.h"
  15. #if USE_STRING_CACHE==1
  16. // Global instance of the string Cache object.
  17. CStringCache gInsObjStringCache;
  18. // Was the cache initialized successfully?
  19. BOOL gbCacheInit = FALSE;
  20. // Is the cache in good shape currently?
  21. // This is needed because errors may occur post-initialization
  22. // during caching strings, setting up RegNotify etc.
  23. // If there is any error we do not take further risk and flag the cache
  24. // as useless all the way till process detach.
  25. BOOL gbOKToUseCache = FALSE;
  26. // REVIEW: the above two globals could probably be folded into a single
  27. // dwFlags member in the cache.
  28. //+-------------------------------------------------------------------------
  29. //
  30. // Function: InsertObjCacheInitialize, public
  31. //
  32. // Synopsis: Calls Init() method on the string cache and records
  33. // success/failure for later use.
  34. //
  35. // History: 02-May-99 MPrabhu Created.
  36. //
  37. //--------------------------------------------------------------------------
  38. BOOL InsertObjCacheInitialize()
  39. {
  40. OleDbgAssert(gbCacheInit == FALSE);
  41. OleDbgAssert(gInsObjStringCache);
  42. if (gInsObjStringCache.Init())
  43. {
  44. gbCacheInit = TRUE;
  45. gbOKToUseCache = TRUE;
  46. }
  47. return gbCacheInit;
  48. }
  49. //+-------------------------------------------------------------------------
  50. //
  51. // Function: InsertObjCacheUninitialize, public
  52. //
  53. // Synopsis: Calls CleanUp method on the string cache if it was
  54. // successfully initialized.
  55. //
  56. // History: 02-May-99 MPrabhu Created.
  57. //
  58. //--------------------------------------------------------------------------
  59. void InsertObjCacheUninitialize()
  60. {
  61. OleDbgAssert(gInsObjStringCache);
  62. if (gbCacheInit)
  63. {
  64. gInsObjStringCache.CleanUp();
  65. }
  66. }
  67. //+-------------------------------------------------------------------------
  68. //
  69. // Method: CStringCache::CStringCache, Public
  70. //
  71. // Synopsis: Ctor (empty)
  72. //
  73. // History: 02-May-99 MPrabhu Created
  74. //
  75. //+-------------------------------------------------------------------------
  76. CStringCache::CStringCache()
  77. {
  78. }
  79. //+-------------------------------------------------------------------------
  80. //
  81. // Method: CStringCache::~CStringCache, Public
  82. //
  83. // Synopsis: Dtor (empty)
  84. //
  85. // History: 02-May-99 MPrabhu Created
  86. //
  87. //+-------------------------------------------------------------------------
  88. CStringCache::~CStringCache()
  89. {
  90. }
  91. //+-------------------------------------------------------------------------
  92. //
  93. // Method: CStringCache::Init, Public
  94. //
  95. // Synopsis: Called during dll_proc_attach to set up the initial state
  96. // and allocate memory for the cache.
  97. //
  98. // History: 02-May-99 MPrabhu Created
  99. //
  100. //+-------------------------------------------------------------------------
  101. BOOL CStringCache::Init()
  102. {
  103. m_ulMaxBytes = 0; //We will alloc this below
  104. m_ulMaxStringCount = 0;
  105. m_ulNextStringNum = 1;
  106. m_ulStringCount = 0;
  107. m_pOffsetTable = NULL;
  108. m_pStrings = NULL;
  109. m_cClsidExcludePrev = 0xFFFFFFFF; // bogus initial values
  110. m_ioFlagsPrev = 0xFFFFFFFF;
  111. m_hRegEvent = CreateEventW( NULL, // pointer to security attributes
  112. // (NULL=>can't inherit)
  113. FALSE, // not Manual Reset
  114. FALSE, // not Signaled initially
  115. NULL ); // pointer to event-object name
  116. LONG ret = RegOpenKeyW( HKEY_CLASSES_ROOT,
  117. L"CLSID", // szSubKey
  118. &m_hRegKey );
  119. if ( (!m_hRegEvent) || ((LONG)ERROR_SUCCESS!=ret) )
  120. {
  121. // No point in using the cache if we cannot watch key changes.
  122. return FALSE;
  123. }
  124. ret = RegNotifyChangeKeyValue( m_hRegKey, // key to watch
  125. TRUE, // watch subTree
  126. REG_NOTIFY_CHANGE_NAME // name
  127. | REG_NOTIFY_CHANGE_LAST_SET, // value
  128. m_hRegEvent, // event to signal
  129. TRUE ); // report asynchronously
  130. if (ERROR_SUCCESS!=ret)
  131. {
  132. // No point in using the cache if we cannot watch key changes.
  133. return FALSE;
  134. }
  135. return (ExpandStringTable() && ExpandOffsetTable());
  136. }
  137. //+-------------------------------------------------------------------------
  138. //
  139. // Method: CStringCache::CleanUp, Public
  140. //
  141. // Synopsis: Called during dll_proc_detach to clean up the state
  142. // and free the memory allocated for the cache.
  143. //
  144. // History: 02-May-99 MPrabhu Created
  145. //
  146. //+-------------------------------------------------------------------------
  147. void CStringCache::CleanUp()
  148. {
  149. FlushCache();
  150. CoTaskMemFree(m_pStrings);
  151. CoTaskMemFree(m_pOffsetTable);
  152. if (m_hRegEvent)
  153. CloseHandle(m_hRegEvent);
  154. if (m_hRegKey)
  155. CloseHandle(m_hRegKey);
  156. gbCacheInit = FALSE;
  157. gbOKToUseCache = FALSE;
  158. }
  159. //+-------------------------------------------------------------------------
  160. //
  161. // Method: CStringCache::ExpandStringTable, Private
  162. //
  163. // Synopsis: Called to expand the memory block used to keep strings
  164. //
  165. // History: 02-May-99 MPrabhu Created
  166. //
  167. // Notes: This relies on MemRealloc to copy the existing contents.
  168. // Caller *must* mark cache state as bad if this fails.
  169. //+-------------------------------------------------------------------------
  170. BOOL CStringCache::ExpandStringTable()
  171. {
  172. // Note: we rely on the constructor to set m_ulMaxBytes to 0.
  173. if (m_ulMaxBytes == 0) //first expansion
  174. {
  175. OleDbgAssert(m_pStrings==NULL);
  176. m_ulMaxBytes = CACHE_MAX_BYTES_INITIAL;
  177. }
  178. else
  179. {
  180. // Each expansion doubles the current size.
  181. m_ulMaxBytes = m_ulMaxBytes*2;
  182. }
  183. // CoTaskMemRealloc does a simple alloc when m_pStrings is NULL.
  184. BYTE *pStrings = (BYTE *)CoTaskMemRealloc( m_pStrings, m_ulMaxBytes);
  185. if (!pStrings)
  186. {
  187. // Caller must mark cache as bad.
  188. return FALSE;
  189. }
  190. m_pStrings = pStrings;
  191. return TRUE;
  192. }
  193. //+-------------------------------------------------------------------------
  194. //
  195. // Method: CStringCache::ExpandOffsetTable, Private
  196. //
  197. // Synopsis: Called to expand the memory block used to keep strings
  198. //
  199. // History: 02-May-99 MPrabhu Created
  200. //
  201. // Notes: This relies on MemRealloc to copy the existing contents.
  202. // Caller *must* mark cache state as bad if this fails.
  203. //+-------------------------------------------------------------------------
  204. BOOL CStringCache::ExpandOffsetTable()
  205. {
  206. // Note: we rely on the contructor to set m_ulMaxStringCount to 0.
  207. if (m_ulMaxStringCount == 0)
  208. {
  209. // first expansion
  210. OleDbgAssert(m_pOffsetTable==NULL);
  211. m_ulMaxStringCount = MAX_INDEX_ENTRIES_INITIAL;
  212. }
  213. else
  214. {
  215. // at each expansion we double the current size.
  216. m_ulMaxStringCount = m_ulMaxStringCount*2;
  217. }
  218. // CoTaskMemRealloc does a simple alloc when m_pOffsetTable is NULL.
  219. ULONG *pTable = (ULONG *) CoTaskMemRealloc( m_pOffsetTable,
  220. sizeof(ULONG)*(m_ulMaxStringCount+1));
  221. if (!pTable)
  222. {
  223. // Caller must mark the cache as bad.
  224. return FALSE;
  225. }
  226. m_pOffsetTable = pTable;
  227. if (m_ulMaxStringCount == (ULONG) MAX_INDEX_ENTRIES_INITIAL)
  228. {
  229. // initial expansion case
  230. m_pOffsetTable[0] = 0; //byte offset for first string
  231. }
  232. return TRUE;
  233. }
  234. //+-------------------------------------------------------------------------
  235. //
  236. // Method: CStringCache::NewCall, Public
  237. //
  238. // Synopsis: Called to notify the cache of a fresh OleUIInsertObject call
  239. //
  240. // Parameters: [idFlags] - dwFlags passed in LPOLEUIINSERTOBJECT struct
  241. // [cClsidExclude] - cClsidExclude - do -
  242. //
  243. // History: 02-May-99 MPrabhu Created
  244. //
  245. //+-------------------------------------------------------------------------
  246. void CStringCache::NewCall(DWORD ioFlags, DWORD cClsidExclude)
  247. {
  248. if ( (ioFlags != m_ioFlagsPrev)
  249. ||(cClsidExclude != m_cClsidExcludePrev) )
  250. {
  251. // We clear cache state if either:
  252. // i) InsertObject call flags change from previous call
  253. // ii) Number of clsIds to exclude has changed
  254. m_ioFlagsPrev = ioFlags;
  255. m_cClsidExcludePrev = cClsidExclude;
  256. FlushCache();
  257. }
  258. }
  259. //+-------------------------------------------------------------------------
  260. //
  261. // Method: CStringCache::IsUptodate, Public
  262. //
  263. // Synopsis: Called to check if the cache is up to date.
  264. //
  265. // History: 02-May-99 MPrabhu Created
  266. //
  267. //+-------------------------------------------------------------------------
  268. BOOL CStringCache::IsUptodate()
  269. {
  270. if (m_ulStringCount==0)
  271. {
  272. // The cache has never been setup or has been Flushed recently
  273. return FALSE;
  274. }
  275. BOOL bUptodate;
  276. // Check the notify event if it has fired since we set it up.
  277. DWORD res = WaitForSingleObject( m_hRegEvent,
  278. 0 ); // timeout for wait
  279. if (res == WAIT_TIMEOUT)
  280. {
  281. // Wait timed out => the reg key sub-tree has not changed
  282. // Our cache is up to date.
  283. bUptodate = TRUE;
  284. }
  285. else if (res == WAIT_OBJECT_0)
  286. {
  287. // Some CLSID must have changed => cache not up to date.
  288. bUptodate = FALSE;
  289. // We have to re-Register for the notification!
  290. ResetEvent(m_hRegEvent);
  291. res = RegNotifyChangeKeyValue( m_hRegKey,
  292. TRUE, // watch sub-tree
  293. REG_NOTIFY_CHANGE_NAME
  294. | REG_NOTIFY_CHANGE_LAST_SET,
  295. m_hRegEvent,
  296. TRUE ); // asynchronous call
  297. if (res != ERROR_SUCCESS)
  298. {
  299. // Cache is useless if we cannot watch CLSID sub-tree.
  300. gbOKToUseCache = FALSE;
  301. }
  302. }
  303. else
  304. {
  305. OleDbgAssert(!"Unexpected return from WaitForSingleObject");
  306. bUptodate = FALSE;
  307. }
  308. return bUptodate;
  309. }
  310. //+-------------------------------------------------------------------------
  311. //
  312. // Method: CStringCache::AddString, Public
  313. //
  314. // Synopsis: Called to notify the cache of a fresh OleUIInsertObject call
  315. //
  316. // Parameters: [lpStrAdd] - String to add to the cache.
  317. //
  318. // History: 02-May-99 MPrabhu Created
  319. //
  320. //+-------------------------------------------------------------------------
  321. BOOL CStringCache::AddString(LPTSTR lpStrAdd)
  322. {
  323. if (m_ulStringCount+2 == m_ulMaxStringCount)
  324. {
  325. // The offset array stores the offset of all the existing strings and
  326. // the next one to be added!
  327. // Hence at start of AddString, we must have enough space for the new
  328. // string being added *and* the next one (hence the +2 above)
  329. if (!ExpandOffsetTable())
  330. {
  331. // Something is really wrong.
  332. // Mark the cache as useless hereafter.
  333. gbOKToUseCache = FALSE;
  334. return FALSE;
  335. }
  336. }
  337. ULONG cbStrAdd = sizeof(TCHAR)*(lstrlen(lpStrAdd) + 1);
  338. ULONG offset = m_pOffsetTable[m_ulStringCount];
  339. if ( offset + cbStrAdd > m_ulMaxBytes )
  340. {
  341. // not enough space in the string block
  342. if (!ExpandStringTable())
  343. {
  344. // Something is really wrong.
  345. // Mark the cache as useless hereafter.
  346. gbOKToUseCache = FALSE;
  347. return FALSE;
  348. }
  349. }
  350. if (! lstrcpy( (TCHAR *)(m_pStrings+offset), lpStrAdd))
  351. {
  352. // Mark the cache as useless hereafter.
  353. gbOKToUseCache = FALSE;
  354. return FALSE;
  355. }
  356. // We have successfully added one more string to the cache.
  357. m_ulStringCount++;
  358. // Next string goes at this byte offset in m_pStrings.
  359. m_pOffsetTable[m_ulStringCount] = offset + cbStrAdd;
  360. return TRUE;
  361. }
  362. //+-------------------------------------------------------------------------
  363. //
  364. // Method: CStringCache::NextString, Public
  365. //
  366. // Synopsis: Used to obtain a pointer to the next string during
  367. // during cache enumeration.
  368. //
  369. // History: 02-May-99 MPrabhu Created
  370. //
  371. //+-------------------------------------------------------------------------
  372. LPCTSTR CStringCache::NextString()
  373. {
  374. if (m_ulNextStringNum > m_ulStringCount)
  375. {
  376. return NULL;
  377. }
  378. return (LPCTSTR) (m_pStrings+m_pOffsetTable[m_ulNextStringNum++-1]);
  379. }
  380. //+-------------------------------------------------------------------------
  381. //
  382. // Method: CStringCache::ResetEnumerator, Public
  383. //
  384. // Synopsis: Used to reset the enumerator.
  385. //
  386. // History: 02-May-99 MPrabhu Created
  387. //
  388. //+-------------------------------------------------------------------------
  389. void CStringCache::ResetEnumerator()
  390. {
  391. m_ulNextStringNum = 1;
  392. }
  393. //+-------------------------------------------------------------------------
  394. //
  395. // Method: CStringCache::FlushCache, Public
  396. //
  397. // Synopsis: Invalidates the cache by clearing the counters.
  398. //
  399. // History: 02-May-99 MPrabhu Created
  400. //
  401. //+-------------------------------------------------------------------------
  402. BOOL CStringCache::FlushCache()
  403. {
  404. m_ulNextStringNum = 1;
  405. m_ulStringCount = 0;
  406. return TRUE;
  407. }
  408. //+-------------------------------------------------------------------------
  409. //
  410. // Method: CStringCache::OKToUse, Public
  411. //
  412. // Synopsis: Used to check if cache is in good shape.
  413. //
  414. // History: 02-May-99 MPrabhu Created
  415. //
  416. //+-------------------------------------------------------------------------
  417. BOOL CStringCache::OKToUse()
  418. {
  419. return gbOKToUseCache;
  420. }
  421. #endif // USE_STRING_CACHE==1