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.

585 lines
14 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: Typelibrary cache
  6. File: tlbcache.cpp
  7. Owner: DmitryR
  8. This is the typelibrary cache source file.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "tlbcache.h"
  13. #include "memchk.h"
  14. /*===================================================================
  15. Globals
  16. ===================================================================*/
  17. CTypelibCache g_TypelibCache;
  18. /*===================================================================
  19. C T y p e l i b C a c h e E n t r y
  20. ===================================================================*/
  21. /*===================================================================
  22. CTypelibCacheEntry::CTypelibCacheEntry
  23. Constructor
  24. ===================================================================*/
  25. CTypelibCacheEntry::CTypelibCacheEntry()
  26. :
  27. m_fInited(FALSE), m_fIdsCached(FALSE), m_fStrAllocated(FALSE),
  28. m_wszProgId(NULL), m_clsid(CLSID_NULL), m_cmModel(cmUnknown),
  29. m_idOnStartPage(DISPID_UNKNOWN), m_idOnEndPage(DISPID_UNKNOWN),
  30. m_gipTypelib(NULL_GIP_COOKIE)
  31. {
  32. }
  33. /*===================================================================
  34. CTypelibCacheEntry::~CTypelibCacheEntry
  35. Destructor
  36. ===================================================================*/
  37. CTypelibCacheEntry::~CTypelibCacheEntry()
  38. {
  39. if (m_gipTypelib != NULL_GIP_COOKIE)
  40. {
  41. g_GIPAPI.Revoke(m_gipTypelib);
  42. }
  43. if (m_fStrAllocated)
  44. {
  45. Assert(m_wszProgId);
  46. free(m_wszProgId);
  47. }
  48. }
  49. /*===================================================================
  50. CTypelibCacheEntry::StoreProgID
  51. Store ProgID with the structure
  52. Parameters
  53. wszProgId ProgId
  54. cbProgId ProgId byte length
  55. Returns
  56. HRESULT
  57. ===================================================================*/
  58. HRESULT CTypelibCacheEntry::StoreProgID
  59. (
  60. LPWSTR wszProgId,
  61. DWORD cbProgId
  62. )
  63. {
  64. Assert(wszProgId);
  65. Assert(*wszProgId != L'\0');
  66. Assert(cbProgId == (wcslen(wszProgId) * sizeof(WCHAR)));
  67. // required buffer length
  68. DWORD cbBuffer = cbProgId + sizeof(WCHAR);
  69. WCHAR *wszBuffer = (WCHAR *)m_rgbStrBuffer;
  70. if (cbBuffer > sizeof(m_rgbStrBuffer))
  71. {
  72. // the prog id doesn't fit into the member buffer -> allocate
  73. wszBuffer = (WCHAR *)malloc(cbBuffer);
  74. if (!wszBuffer)
  75. return E_OUTOFMEMORY;
  76. m_fStrAllocated = TRUE;
  77. }
  78. memcpy(wszBuffer, wszProgId, cbBuffer);
  79. m_wszProgId = wszBuffer;
  80. return S_OK;
  81. }
  82. /*===================================================================
  83. CTypelibCacheEntry::InitByProgID
  84. Real constructor.
  85. Store ProgID. Init CLinkElem portion with ProgID.
  86. Parameters
  87. wszProgId ProgId
  88. cbProgId ProgId byte length
  89. Returns
  90. HRESULT
  91. ===================================================================*/
  92. HRESULT CTypelibCacheEntry::InitByProgID
  93. (
  94. LPWSTR wszProgId,
  95. DWORD cbProgId
  96. )
  97. {
  98. StoreProgID(wszProgId, cbProgId);
  99. // init link with prog id as key (length excludes null term)
  100. CLinkElem::Init(m_wszProgId, cbProgId);
  101. m_fInited = TRUE;
  102. return S_OK;
  103. }
  104. /*===================================================================
  105. CTypelibCacheEntry::InitByCLSID
  106. Real constructor.
  107. Store ProgID. Init CLinkElem portion with CLSID.
  108. Parameters
  109. clsid CLSID
  110. wszProgId ProgId
  111. Returns
  112. HRESULT
  113. ===================================================================*/
  114. HRESULT CTypelibCacheEntry::InitByCLSID
  115. (
  116. const CLSID &clsid,
  117. LPWSTR wszProgid
  118. )
  119. {
  120. StoreProgID(wszProgid, CbWStr(wszProgid));
  121. m_clsid = clsid;
  122. // init link with CLSID id as key
  123. CLinkElem::Init(&m_clsid, sizeof(m_clsid));
  124. m_fInited = TRUE;
  125. return S_OK;
  126. }
  127. /*===================================================================
  128. C T y p e l i b C a c h e
  129. ===================================================================*/
  130. /*===================================================================
  131. CTypelibCache::CTypelibCache
  132. Constructor
  133. ===================================================================*/
  134. CTypelibCache::CTypelibCache()
  135. :
  136. m_fInited(FALSE)
  137. {
  138. }
  139. /*===================================================================
  140. CTypelibCache::~CTypelibCache
  141. Destructor
  142. ===================================================================*/
  143. CTypelibCache::~CTypelibCache()
  144. {
  145. UnInit();
  146. }
  147. /*===================================================================
  148. CTypelibCache::Init
  149. Init
  150. Returns
  151. HRESULT
  152. ===================================================================*/
  153. HRESULT CTypelibCache::Init()
  154. {
  155. HRESULT hr;
  156. hr = m_htProgIdEntries.Init(199);
  157. if (FAILED(hr))
  158. return hr;
  159. hr = m_htCLSIDEntries.Init(97);
  160. if (FAILED(hr))
  161. return hr;
  162. ErrInitCriticalSection(&m_csLock, hr);
  163. if (FAILED(hr))
  164. return(hr);
  165. m_fInited = TRUE;
  166. return S_OK;
  167. }
  168. /*===================================================================
  169. CTypelibCache::UnInit
  170. UnInit
  171. Returns
  172. HRESULT
  173. ===================================================================*/
  174. HRESULT CTypelibCache::UnInit()
  175. {
  176. CTypelibCacheEntry *pEntry;
  177. CLinkElem *pLink;
  178. // ProgID Hash table
  179. pLink = m_htProgIdEntries.Head();
  180. while (pLink)
  181. {
  182. pEntry = static_cast<CTypelibCacheEntry *>(pLink);
  183. pLink = pLink->m_pNext;
  184. // remove the entry
  185. delete pEntry;
  186. }
  187. m_htProgIdEntries.UnInit();
  188. // CLSID Hash table
  189. pLink = m_htCLSIDEntries.Head();
  190. while (pLink)
  191. {
  192. pEntry = static_cast<CTypelibCacheEntry *>(pLink);
  193. pLink = pLink->m_pNext;
  194. // remove the entry
  195. delete pEntry;
  196. }
  197. m_htCLSIDEntries.UnInit();
  198. // Critical section
  199. if (m_fInited)
  200. {
  201. DeleteCriticalSection(&m_csLock);
  202. m_fInited = FALSE;
  203. }
  204. return S_OK;
  205. }
  206. /*===================================================================
  207. CTypelibCache::CreateComponent
  208. Create the component using the cached info.
  209. Adds cache entry if needed.
  210. To be called from Server.CreateObject
  211. Parameters
  212. bstrProgID prog id
  213. pHitObj HitObj needed for creation
  214. ppdisp [out] IDispatch *
  215. pclsid [out] CLSID
  216. Returns
  217. HRESULT
  218. ===================================================================*/
  219. HRESULT CTypelibCache::CreateComponent
  220. (
  221. BSTR bstrProgID,
  222. CHitObj *pHitObj,
  223. IDispatch **ppdisp,
  224. CLSID *pclsid
  225. )
  226. {
  227. HRESULT hr;
  228. CLinkElem *pElem;
  229. CTypelibCacheEntry *pEntry;
  230. CComponentObject *pObj;
  231. COnPageInfo OnPageInfo;
  232. CompModel cmModel;
  233. *pclsid = CLSID_NULL;
  234. *ppdisp = NULL;
  235. if (bstrProgID == NULL || *bstrProgID == L'\0')
  236. return E_FAIL;
  237. WCHAR *wszProgId = bstrProgID;
  238. DWORD cbProgId = CbWStr(wszProgId); // do strlen once
  239. BOOL fFound = FALSE;
  240. BOOL bDispIdsCached = FALSE;
  241. Lock();
  242. pElem = m_htProgIdEntries.FindElem(wszProgId, cbProgId);
  243. if (pElem)
  244. {
  245. // remember the elements of the entry while inside lock
  246. pEntry = static_cast<CTypelibCacheEntry *>(pElem);
  247. // return clsid
  248. *pclsid = pEntry->m_clsid;
  249. // prepate OnPageInfo with DispIds to pass to the creation function
  250. if (pEntry->m_fIdsCached)
  251. {
  252. OnPageInfo.m_rgDispIds[ONPAGEINFO_ONSTARTPAGE] = pEntry->m_idOnStartPage;
  253. OnPageInfo.m_rgDispIds[ONPAGEINFO_ONENDPAGE] = pEntry->m_idOnEndPage;
  254. bDispIdsCached = TRUE;
  255. }
  256. // remember the model
  257. cmModel = pEntry->m_cmModel;
  258. fFound = TRUE;
  259. }
  260. UnLock();
  261. if (fFound)
  262. {
  263. // create the object
  264. hr = pHitObj->PPageComponentManager()->AddScopedUnnamedInstantiated
  265. (
  266. csPage,
  267. *pclsid,
  268. cmModel,
  269. bDispIdsCached ? &OnPageInfo : NULL,
  270. &pObj
  271. );
  272. // get IDispatch*
  273. if (SUCCEEDED(hr))
  274. hr = pObj->GetAddRefdIDispatch(ppdisp);
  275. // return if succeeded
  276. if (SUCCEEDED(hr))
  277. {
  278. // don't keep the object around unless needed
  279. if (pObj->FEarlyReleaseAllowed())
  280. pHitObj->PPageComponentManager()->RemoveComponent(pObj);
  281. return S_OK;
  282. }
  283. // on failure remove from the cache and pretend
  284. // as if it was never found
  285. Lock();
  286. pElem = m_htProgIdEntries.DeleteElem(wszProgId, cbProgId);
  287. UnLock();
  288. if (pElem)
  289. {
  290. // Element removed from cache - delete the CacheEntry
  291. pEntry = static_cast<CTypelibCacheEntry *>(pElem);
  292. delete pEntry;
  293. }
  294. // don't return bogus CLSID
  295. *pclsid = CLSID_NULL;
  296. }
  297. // Not found in the cache. Create the object, get the info, and
  298. // insert the new cache entry.
  299. hr = CLSIDFromProgID((LPCOLESTR)wszProgId, pclsid);
  300. if (FAILED(hr))
  301. return hr; // couldn't even get clsid - don't cache
  302. hr = pHitObj->PPageComponentManager()->AddScopedUnnamedInstantiated
  303. (
  304. csPage,
  305. *pclsid,
  306. cmUnknown,
  307. NULL,
  308. &pObj
  309. );
  310. if (FAILED(hr))
  311. return hr; // couldn't create object - don't cache
  312. // object created - get IDispatch*
  313. if (SUCCEEDED(hr))
  314. hr = pObj->GetAddRefdIDispatch(ppdisp);
  315. if (FAILED(hr))
  316. return hr; // couldn't get IDispatch* - don't cache
  317. // create new CTypelibCacheEntry
  318. pEntry = new CTypelibCacheEntry;
  319. if (!pEntry)
  320. return S_OK; // no harm
  321. // init link entry
  322. if (FAILED(pEntry->InitByProgID(wszProgId, cbProgId)))
  323. {
  324. delete pEntry;
  325. return S_OK; // no harm
  326. }
  327. // remember stuff in pEntry
  328. pEntry->m_clsid = *pclsid;
  329. pEntry->m_cmModel = pObj->GetModel();
  330. const COnPageInfo *pOnPageInfo = pObj->GetCachedOnPageInfo();
  331. if (pOnPageInfo)
  332. {
  333. pEntry->m_fIdsCached = TRUE;
  334. pEntry->m_idOnStartPage = pOnPageInfo->m_rgDispIds[ONPAGEINFO_ONSTARTPAGE];
  335. pEntry->m_idOnEndPage = pOnPageInfo->m_rgDispIds[ONPAGEINFO_ONENDPAGE];
  336. }
  337. else
  338. {
  339. pEntry->m_fIdsCached = FALSE;
  340. pEntry->m_idOnStartPage = DISPID_UNKNOWN;
  341. pEntry->m_idOnEndPage = DISPID_UNKNOWN;
  342. }
  343. // try to get the typelib
  344. pEntry->m_gipTypelib = NULL_GIP_COOKIE;
  345. if (FIsWinNT()) // don't do GIP cookies on Win95
  346. {
  347. ITypeInfo *ptinfo;
  348. if (SUCCEEDED((*ppdisp)->GetTypeInfo(0, 0, &ptinfo)))
  349. {
  350. ITypeLib *ptlib;
  351. UINT idx;
  352. if (SUCCEEDED(ptinfo->GetContainingTypeLib(&ptlib, &idx)))
  353. {
  354. // got it! convert to gip cookie
  355. DWORD gip;
  356. if (SUCCEEDED(g_GIPAPI.Register(ptlib, IID_ITypeLib, &gip)))
  357. {
  358. // remember the gip cookie with pEntry
  359. pEntry->m_gipTypelib = gip;
  360. }
  361. ptlib->Release();
  362. }
  363. ptinfo->Release();
  364. }
  365. }
  366. // pEntry is ready -- try to insert it into cache
  367. BOOL fInserted = FALSE;
  368. Lock();
  369. // make sure some other thread didn't insert it already
  370. if (m_htProgIdEntries.FindElem(wszProgId, cbProgId) == NULL)
  371. {
  372. if (m_htProgIdEntries.AddElem(pEntry))
  373. fInserted = TRUE;
  374. }
  375. UnLock();
  376. // cleanup
  377. if (!fInserted)
  378. delete pEntry;
  379. // don't keep the object around unless needed
  380. if (pObj->FEarlyReleaseAllowed())
  381. pHitObj->PPageComponentManager()->RemoveComponent(pObj);
  382. return S_OK;
  383. }
  384. /*===================================================================
  385. CTypelibCache::RememberProgidToCLSIDMapping
  386. Adds an entry to CLSID hashtable.
  387. To be called from template after mapping ProgId to CLSID.
  388. Parameters
  389. wszProgID prog id
  390. clsid clsid
  391. Returns
  392. HRESULT
  393. ===================================================================*/
  394. HRESULT CTypelibCache::RememberProgidToCLSIDMapping
  395. (
  396. WCHAR *wszProgid,
  397. const CLSID &clsid
  398. )
  399. {
  400. HRESULT hr;
  401. CLinkElem *pElem;
  402. CTypelibCacheEntry *pEntry;
  403. // check if already there first
  404. BOOL fFound = FALSE;
  405. Lock();
  406. if (m_htCLSIDEntries.FindElem(&clsid, sizeof(CLSID)) != NULL)
  407. fFound = TRUE;
  408. UnLock();
  409. if (fFound)
  410. return S_OK;
  411. // create new entry
  412. pEntry = new CTypelibCacheEntry;
  413. if (!pEntry)
  414. return E_OUTOFMEMORY;
  415. BOOL fInserted = FALSE;
  416. // remember prog id and init link entry
  417. hr = pEntry->InitByCLSID(clsid, wszProgid);
  418. if (SUCCEEDED(hr))
  419. {
  420. Lock();
  421. // make sure some other thread didn't insert it already
  422. if (m_htCLSIDEntries.FindElem(&clsid, sizeof(CLSID)) == NULL)
  423. {
  424. if (m_htCLSIDEntries.AddElem(pEntry))
  425. fInserted = TRUE;
  426. }
  427. UnLock();
  428. }
  429. // cleanup
  430. if (!fInserted)
  431. delete pEntry;
  432. return hr;
  433. }
  434. /*===================================================================
  435. CTypelibCache::UpdateMappedCLSID
  436. Update CLSID since remembered.
  437. To be called from object creation code to update CLSID
  438. if the object creation failed.
  439. Parameters
  440. *pclsid [in, out] CLSID
  441. Returns
  442. HRESULT
  443. S_FALSE = didn't change
  444. S_OK = did change and the new one found
  445. ===================================================================*/
  446. HRESULT CTypelibCache::UpdateMappedCLSID
  447. (
  448. CLSID *pclsid
  449. )
  450. {
  451. HRESULT hr = S_FALSE; // not found
  452. CLinkElem *pElem;
  453. CTypelibCacheEntry *pEntry;
  454. CLSID clsidNew;
  455. Lock();
  456. // Do everything under lock so the ProgID stored in
  457. // the entry is still valid.
  458. // Not very perfomant -- but is is an error path anyway
  459. pElem = m_htCLSIDEntries.FindElem(pclsid, sizeof(CLSID));
  460. if (pElem)
  461. {
  462. pEntry = static_cast<CTypelibCacheEntry *>(pElem);
  463. // find new mapping
  464. if (SUCCEEDED(CLSIDFromProgID(pEntry->m_wszProgId, &clsidNew)))
  465. {
  466. // compare with the old one
  467. if (!IsEqualCLSID(clsidNew, *pclsid))
  468. {
  469. // the mapping did change!
  470. *pclsid = clsidNew;
  471. hr = S_OK;
  472. }
  473. }
  474. }
  475. UnLock();
  476. return hr;
  477. }