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.

580 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: C O M P R E F S . C P P
  7. //
  8. // Contents: Implements the interface to a component's references. A
  9. // component can be referenced (installed by) other components,
  10. // the user, or other software. This module manages the
  11. // interface to that data.
  12. //
  13. // Notes:
  14. //
  15. // Author: shaunco 15 Jan 1999
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <pch.h>
  19. #pragma hdrstop
  20. #include "comp.h"
  21. #include "comprefs.h"
  22. #include "icomp.h"
  23. #include "nceh.h"
  24. #include "ncreg.h"
  25. #define REGSTR_KEY_REFNAMES \
  26. L"SYSTEM\\CurrentControlSet\\Control\\Network\\RefNames"
  27. // Cannot be inline because comprefs.h cannot include comp.h.
  28. //
  29. CComponentReferences::~CComponentReferences ()
  30. {
  31. Assert (this);
  32. // Must use delete on m_pData to get destructors of its members
  33. // to be called.
  34. //
  35. delete m_pData;
  36. }
  37. ULONG
  38. CComponentReferences::CountComponentsReferencedBy () const
  39. {
  40. Assert (this);
  41. if (!m_pData)
  42. {
  43. return 0;
  44. }
  45. return m_pData->RefByComponents.Count ();
  46. }
  47. ULONG
  48. CComponentReferences::CountSoftwareReferencedBy () const
  49. {
  50. Assert (this);
  51. if (!m_pData)
  52. {
  53. return 0;
  54. }
  55. return m_pData->RefBySoftware.size ();
  56. }
  57. ULONG
  58. CComponentReferences::CountTotalReferencedBy () const
  59. {
  60. Assert (this);
  61. if (!m_pData)
  62. {
  63. return 0;
  64. }
  65. return ((m_pData->fRefByUser) ? 1 : 0) +
  66. m_pData->RefByComponents.Count () +
  67. m_pData->RefBySoftware.size ();
  68. }
  69. HRESULT
  70. HrGetSoftwareOboTokenKey (
  71. IN const OBO_TOKEN* pOboToken,
  72. BOOL fRegister,
  73. OUT PWSTR* ppszKey)
  74. {
  75. HRESULT hr;
  76. UINT cch;
  77. Assert (pOboToken);
  78. Assert (OBO_SOFTWARE == pOboToken->Type);
  79. Assert (pOboToken->pszwManufacturer && *pOboToken->pszwManufacturer);
  80. Assert (pOboToken->pszwProduct && *pOboToken->pszwProduct);
  81. Assert (ppszKey);
  82. cch = wcslen (pOboToken->pszwManufacturer) +
  83. wcslen (pOboToken->pszwProduct);
  84. hr = E_OUTOFMEMORY;
  85. *ppszKey = (PWSTR)MemAlloc ((cch + 1) * sizeof(WCHAR));
  86. if (*ppszKey)
  87. {
  88. hr = S_OK;
  89. wcscpy (*ppszKey, pOboToken->pszwManufacturer);
  90. wcscat (*ppszKey, pOboToken->pszwProduct);
  91. if (fRegister)
  92. {
  93. HKEY hkeyRefNames;
  94. hr = HrRegCreateKeyEx (
  95. HKEY_LOCAL_MACHINE,
  96. REGSTR_KEY_REFNAMES,
  97. REG_OPTION_NON_VOLATILE,
  98. KEY_WRITE, NULL, &hkeyRefNames, NULL);
  99. if (SUCCEEDED(hr))
  100. {
  101. hr = HrRegSetSz (
  102. hkeyRefNames,
  103. *ppszKey,
  104. pOboToken->pszwDisplayName);
  105. RegCloseKey (hkeyRefNames);
  106. }
  107. }
  108. }
  109. TraceHr (ttidError, FAL, hr, FALSE, "HrGetSoftwareOboTokenKey");
  110. return hr;
  111. }
  112. BOOL
  113. CComponentReferences::FIsReferencedByComponent (
  114. IN const CComponent* pComponent) const
  115. {
  116. Assert (pComponent);
  117. if (!m_pData)
  118. {
  119. return FALSE;
  120. }
  121. return m_pData->RefByComponents.FComponentInList (pComponent);
  122. }
  123. BOOL
  124. CComponentReferences::FIsReferencedByOboToken (
  125. IN const OBO_TOKEN* pOboToken) const
  126. {
  127. HRESULT hr;
  128. BOOL fIsReferenced;
  129. PWSTR pszKey;
  130. Assert (pOboToken);
  131. if (!m_pData)
  132. {
  133. return FALSE;
  134. }
  135. fIsReferenced = FALSE;
  136. CComponent* pComponent;
  137. switch (pOboToken->Type)
  138. {
  139. case OBO_USER:
  140. fIsReferenced = m_pData->fRefByUser;
  141. break;
  142. case OBO_COMPONENT:
  143. // Can't be referenced if there are no references.
  144. //
  145. if (m_pData->RefByComponents.Count() > 0)
  146. {
  147. pComponent = PComponentFromComInterface (pOboToken->pncc);
  148. fIsReferenced = m_pData->RefByComponents.FComponentInList (
  149. pComponent);
  150. }
  151. break;
  152. case OBO_SOFTWARE:
  153. // Can't be referenced if there are no references.
  154. //
  155. if (m_pData->RefBySoftware.size() > 0)
  156. {
  157. // Get the key for the software token, but don't register
  158. // the display name.
  159. //
  160. hr = HrGetSoftwareOboTokenKey (pOboToken, FALSE, &pszKey);
  161. if (S_OK == hr)
  162. {
  163. fIsReferenced =
  164. find (m_pData->RefBySoftware.begin(),
  165. m_pData->RefBySoftware.end(), pszKey) !=
  166. m_pData->RefBySoftware.end();
  167. MemFree (pszKey);
  168. }
  169. }
  170. break;
  171. default:
  172. AssertSz (FALSE, "Invalid obo token");
  173. }
  174. return fIsReferenced;
  175. }
  176. VOID
  177. CComponentReferences::GetReferenceDescriptionsAsMultiSz (
  178. IN BYTE* pbBuf OPTIONAL,
  179. OUT ULONG* pcbBuf) const
  180. {
  181. ULONG cbBuf;
  182. ULONG cbBufIn;
  183. ULONG cb;
  184. CComponentList::const_iterator iter;
  185. const CComponent* pComponent;
  186. vector<CWideString>::const_iterator pStr;
  187. Assert (this);
  188. Assert (m_pData);
  189. Assert (pcbBuf);
  190. cbBufIn = *pcbBuf;
  191. cbBuf = 0;
  192. // Get/Size the component descriptions.
  193. //
  194. for (iter = m_pData->RefByComponents.begin();
  195. iter != m_pData->RefByComponents.end();
  196. iter++)
  197. {
  198. pComponent = *iter;
  199. Assert (pComponent);
  200. cb = CbOfSzAndTermSafe(pComponent->Ext.PszDescription());
  201. cbBuf += cb;
  202. if (pbBuf && (cbBuf <= cbBufIn))
  203. {
  204. wcscpy ((PWSTR)pbBuf, pComponent->Ext.PszDescription());
  205. pbBuf += cb;
  206. }
  207. }
  208. // Get/Size the software descriptions.
  209. //
  210. if (!m_pData->RefBySoftware.empty())
  211. {
  212. HRESULT hr;
  213. HKEY hkeyRefNames;
  214. hr = HrRegOpenKeyEx (
  215. HKEY_LOCAL_MACHINE,
  216. REGSTR_KEY_REFNAMES,
  217. KEY_READ,
  218. &hkeyRefNames);
  219. if (S_OK == hr)
  220. {
  221. for (pStr = m_pData->RefBySoftware.begin();
  222. pStr != m_pData->RefBySoftware.end();
  223. pStr++)
  224. {
  225. cb = cbBufIn - cbBuf;
  226. hr = HrRegQuerySzBuffer (hkeyRefNames, pStr->c_str(),
  227. (PWSTR)pbBuf, &cb);
  228. if (S_OK == hr)
  229. {
  230. cbBuf += cb;
  231. if (pbBuf)
  232. {
  233. pbBuf += cb;
  234. }
  235. }
  236. }
  237. RegCloseKey (hkeyRefNames);
  238. }
  239. }
  240. // Terminate the multi-sz.
  241. //
  242. cbBuf += sizeof(WCHAR);
  243. if (pbBuf && (cbBuf <= cbBufIn))
  244. {
  245. *(PWSTR)pbBuf = 0;
  246. }
  247. // Return the size of the buffer required.
  248. //
  249. *pcbBuf = cbBuf;
  250. }
  251. BOOL
  252. CComponentReferences::FIsReferencedByOthers () const
  253. {
  254. Assert (this);
  255. if (!m_pData)
  256. {
  257. return FALSE;
  258. }
  259. return m_pData->fRefByUser ||
  260. !m_pData->RefByComponents.empty() ||
  261. !m_pData->RefBySoftware.empty();
  262. }
  263. CComponent*
  264. CComponentReferences::PComponentReferencedByAtIndex (
  265. IN UINT unIndex) const
  266. {
  267. Assert (this);
  268. if (!m_pData)
  269. {
  270. return NULL;
  271. }
  272. return m_pData->RefByComponents.PGetComponentAtIndex (unIndex);
  273. }
  274. const CWideString*
  275. CComponentReferences::PSoftwareReferencedByAtIndex (
  276. IN UINT unIndex) const
  277. {
  278. Assert (this);
  279. if (!m_pData)
  280. {
  281. return NULL;
  282. }
  283. return &m_pData->RefBySoftware[unIndex];
  284. }
  285. HRESULT
  286. CComponentReferences::HrEnsureAllocated ()
  287. {
  288. Assert (this);
  289. if (m_pData)
  290. {
  291. return S_OK;
  292. }
  293. HRESULT hr;
  294. hr = E_OUTOFMEMORY;
  295. m_pData = new COMPONENT_REFERENCE_DATA;
  296. if (m_pData)
  297. {
  298. ZeroMemory (m_pData, sizeof(COMPONENT_REFERENCE_DATA));
  299. hr = S_OK;
  300. }
  301. TraceHr (ttidError, FAL, hr, FALSE,
  302. "CComponentReferences::HrEnsureAllocated");
  303. return hr;
  304. }
  305. HRESULT
  306. CComponentReferences::HrAddReferenceByUser ()
  307. {
  308. HRESULT hr;
  309. Assert (this);
  310. hr = HrEnsureAllocated ();
  311. if (S_OK == hr)
  312. {
  313. m_pData->fRefByUser = TRUE;
  314. }
  315. TraceHr (ttidError, FAL, hr, FALSE,
  316. "CComponentReferences::AddReferenceByUser");
  317. return hr;
  318. }
  319. HRESULT
  320. CComponentReferences::HrAddReferenceByComponent (
  321. IN const CComponent* pComponent)
  322. {
  323. HRESULT hr;
  324. Assert (this);
  325. Assert (pComponent);
  326. hr = HrEnsureAllocated ();
  327. if (S_OK == hr)
  328. {
  329. // If someone wants to add a reference by the same component
  330. // multiple times, we'll allow it. The component only goes in the
  331. // list once.
  332. //
  333. hr = m_pData->RefByComponents.HrInsertComponent (
  334. pComponent, INS_IGNORE_IF_DUP | INS_NON_SORTED);
  335. }
  336. TraceHr (ttidError, FAL, hr, FALSE,
  337. "CComponentReferences::HrAddReferenceByComponent");
  338. return hr;
  339. }
  340. HRESULT
  341. CComponentReferences::HrAddReferenceByOboToken (
  342. IN const OBO_TOKEN* pOboToken)
  343. {
  344. Assert (pOboToken);
  345. HRESULT hr;
  346. CComponent* pComponent;
  347. PWSTR pszKey;
  348. switch (pOboToken->Type)
  349. {
  350. case OBO_USER:
  351. hr = HrAddReferenceByUser ();
  352. break;
  353. case OBO_COMPONENT:
  354. pComponent = PComponentFromComInterface (pOboToken->pncc);
  355. hr = HrAddReferenceByComponent (pComponent);
  356. break;
  357. case OBO_SOFTWARE:
  358. // Register the display name of the obo token.
  359. //
  360. hr = HrGetSoftwareOboTokenKey (pOboToken, TRUE, &pszKey);
  361. if (S_OK == hr)
  362. {
  363. hr = HrAddReferenceBySoftware (pszKey);
  364. MemFree (pszKey);
  365. }
  366. break;
  367. default:
  368. AssertSz (FALSE, "Invalid obo token");
  369. }
  370. TraceHr (ttidError, FAL, hr, FALSE,
  371. "CComponentReferences::HrAddReferenceByOboToken");
  372. return hr;
  373. }
  374. HRESULT
  375. CComponentReferences::HrAddReferenceBySoftware (
  376. IN PCWSTR pszKey)
  377. {
  378. HRESULT hr;
  379. Assert (this);
  380. Assert (pszKey && *pszKey);
  381. hr = HrEnsureAllocated ();
  382. if (S_OK == hr)
  383. {
  384. // If the key is not in the list, add it.
  385. //
  386. if (find (m_pData->RefBySoftware.begin(),
  387. m_pData->RefBySoftware.end(), pszKey) ==
  388. m_pData->RefBySoftware.end())
  389. {
  390. NC_TRY
  391. {
  392. m_pData->RefBySoftware.push_back (pszKey);
  393. Assert (S_OK == hr);
  394. }
  395. NC_CATCH_ALL
  396. {
  397. hr = E_OUTOFMEMORY;
  398. }
  399. }
  400. }
  401. TraceHr (ttidError, FAL, hr, FALSE,
  402. "CComponentReferences::HrAddReferenceBySoftware");
  403. return hr;
  404. }
  405. VOID
  406. CComponentReferences::RemoveAllReferences()
  407. {
  408. Assert (this);
  409. if (m_pData)
  410. {
  411. m_pData->fRefByUser = FALSE;
  412. m_pData->RefByComponents.Clear();
  413. m_pData->RefBySoftware.clear();
  414. }
  415. }
  416. HRESULT
  417. CComponentReferences::HrRemoveReferenceByOboToken (
  418. IN const OBO_TOKEN* pOboToken)
  419. {
  420. Assert (pOboToken);
  421. HRESULT hr;
  422. CComponent* pComponent;
  423. PWSTR pszKey;
  424. if (!m_pData)
  425. {
  426. return S_OK;
  427. }
  428. hr = S_OK;
  429. switch (pOboToken->Type)
  430. {
  431. case OBO_USER:
  432. // Don't allow the user's reference to be removed until all
  433. // other references are. This is to prevent the case where
  434. // the user wants to remove IPX, but it is still referenced by
  435. // SAP. If we remove the user's reference to IPX, then we will
  436. // report that it was not removed. If the user then removes
  437. // SAP, both SAP and IPX will be removed. While this will
  438. // certainly work, to end users, they feel that if we tell them
  439. // we can't remove IPX because it is still referenced, then they
  440. // believe we have left IPX untouched and they should first remove
  441. // SAP and then come back and remove IPX.
  442. //
  443. if (m_pData->RefByComponents.empty() &&
  444. m_pData->RefBySoftware.empty())
  445. {
  446. m_pData->fRefByUser = FALSE;
  447. }
  448. break;
  449. case OBO_COMPONENT:
  450. pComponent = PComponentFromComInterface (pOboToken->pncc);
  451. m_pData->RefByComponents.RemoveComponent(pComponent);
  452. break;
  453. case OBO_SOFTWARE:
  454. // Register the display name of the obo token.
  455. //
  456. hr = HrGetSoftwareOboTokenKey (pOboToken, TRUE, &pszKey);
  457. if (S_OK == hr)
  458. {
  459. vector<CWideString>::iterator iter;
  460. iter = find (m_pData->RefBySoftware.begin(),
  461. m_pData->RefBySoftware.end(), pszKey);
  462. Assert (m_pData->RefBySoftware.end() != iter);
  463. m_pData->RefBySoftware.erase (iter);
  464. Assert (m_pData->RefBySoftware.end() ==
  465. find (m_pData->RefBySoftware.begin(),
  466. m_pData->RefBySoftware.end(), pszKey));
  467. MemFree (pszKey);
  468. }
  469. break;
  470. default:
  471. AssertSz (FALSE, "Invalid obo token");
  472. }
  473. TraceHr (ttidError, FAL, hr, FALSE,
  474. "CComponentReferences::HrRemoveReferenceByOboToken");
  475. return hr;
  476. }