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.

921 lines
30 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////
  2. // TuningSpaceContainer.cpp : Implementation of CSystemTuningSpaces
  3. // Copyright (c) Microsoft Corporation 1999-2000.
  4. #include "stdafx.h"
  5. #include "TuningSpaceContainer.h"
  6. #include "rgsbag.h"
  7. #include "ATSCTS.h"
  8. #include "AnalogTVTS.h"
  9. #include "AuxiliaryInTs.h"
  10. #include "AnalogRadioTS.h"
  11. #include "dvbts.h"
  12. #include "dvbsts.h"
  13. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_SystemTuningSpaces, CSystemTuningSpaces)
  14. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_ATSCTuningSpace, CATSCTS)
  15. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_AnalogTVTuningSpace, CAnalogTVTS)
  16. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_AuxInTuningSpace, CAuxInTS)
  17. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_AnalogRadioTuningSpace, CAnalogRadioTS)
  18. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_DVBTuningSpace, CDVBTS)
  19. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_DVBSTuningSpace, CDVBSTS)
  20. #define MAX_COUNT_NAME OLESTR("Max Count")
  21. namespace BDATuningModel {
  22. typedef CComQIPtr<ITuningSpaceContainer> PQTuningSpaceContainer;
  23. class CAutoMutex {
  24. public:
  25. const static int MAX_MUTEX_WAIT = 5000;
  26. CAutoMutex(HANDLE hMutex) throw(ComException) : m_hMutex(hMutex) {
  27. if (WaitForSingleObject(m_hMutex, MAX_MUTEX_WAIT) != WAIT_OBJECT_0)
  28. THROWCOM(E_FAIL);
  29. }
  30. ~CAutoMutex() throw(ComException) {
  31. if (!ReleaseMutex(m_hMutex))
  32. THROWCOM(E_FAIL);
  33. }
  34. private:
  35. HANDLE m_hMutex;
  36. };
  37. // to avoid deadlock, always grab the objects critsec via ATL_LOCK before
  38. // grabbing the registry section mutex.
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CSystemTuningSpaces
  41. HRESULT
  42. CSystemTuningSpaces::FinalConstruct(void)
  43. {
  44. // set up to serialize access to this point in the registry
  45. CString cs;
  46. cs.LoadString(IDS_MUTNAME);
  47. m_hMutex = CreateMutex(NULL, FALSE, cs);
  48. if (!m_hMutex)
  49. {
  50. return Error(IDS_E_NOMUTEX, __uuidof(ITuningSpaceContainer), HRESULT_FROM_WIN32(GetLastError()));
  51. }
  52. try {
  53. // wait for exclusive access
  54. CAutoMutex mutex(m_hMutex);
  55. // this must only be done once
  56. _ASSERT(!m_pFactory);
  57. // get the property bag class factory
  58. HRESULT hr = m_pFactory.CoCreateInstance(__uuidof(CreatePropBagOnRegKey));
  59. if (FAILED(hr))
  60. {
  61. return Error(IDS_E_NOPROPBAGFACTORY, __uuidof(ITuningSpaceContainer), hr);
  62. }
  63. hr = OpenRootKeyAndBag(KEY_READ);
  64. if (FAILED(hr)) {
  65. return Error(IDS_E_NOREGACCESS, __uuidof(ITuningSpaceContainer), hr);
  66. }
  67. PQPropertyBag pb(m_pTSBag);
  68. if (!pb) {
  69. return E_UNEXPECTED;
  70. }
  71. // discover the maximum possible number of tuning spaces that currently exist
  72. ULONG cTSPropCount;
  73. hr = m_pTSBag->CountProperties(&cTSPropCount);
  74. if (FAILED(hr))
  75. {
  76. return Error(IDS_E_CANNOTQUERYKEY, __uuidof(ITuningSpaceContainer), hr);
  77. }
  78. // allocate space to hold the tuning space object information entries
  79. PROPBAG2 *rgPROPBAG2 = new PROPBAG2[cTSPropCount];
  80. if (!rgPROPBAG2)
  81. {
  82. return Error(IDS_E_OUTOFMEMORY, __uuidof(ITuningSpaceContainer), E_OUTOFMEMORY);
  83. }
  84. ULONG cpb2Lim;
  85. // get all the property info structs at once
  86. hr = m_pTSBag->GetPropertyInfo(0, cTSPropCount, rgPROPBAG2, &cpb2Lim);
  87. if (FAILED(hr))
  88. {
  89. return Error(IDS_E_CANNOTQUERYKEY, __uuidof(ITuningSpaceContainer), hr);
  90. }
  91. _ASSERT(cTSPropCount == cpb2Lim);
  92. HRESULT hrc = NOERROR;
  93. // go through the list of properties
  94. for (ULONG ipb2 = 0; ipb2 < cpb2Lim; ++ipb2)
  95. {
  96. // only deal with ones that represent sub-objects (keys)
  97. if (rgPROPBAG2[ipb2].vt == VT_UNKNOWN)
  98. {
  99. USES_CONVERSION;
  100. LPTSTR pstrName = OLE2T(rgPROPBAG2[ipb2].pstrName);
  101. TCHAR* pchStop;
  102. // check for a valid tuning space identifier
  103. ULONG idx = _tcstoul(pstrName, &pchStop, 10);
  104. if (idx != 0 && idx != ULONG_MAX && *pchStop == 0)
  105. {
  106. CComVariant var;
  107. // read the property from the bag (instantiating the tuning space object)
  108. HRESULT hr2;
  109. hr = m_pTSBag->Read(1, &rgPROPBAG2[ipb2], NULL, &var, &hr2);
  110. if (FAILED(hr)) {
  111. // even if the read fails, we should keep going.
  112. // a) this is the easiest way to prevent memory leaks from rgPROPBAG2
  113. // b) a bad 3rd party uninstall could leave us with tuning space data
  114. // but no tuning space class to instantiate for that data. we shouldn't
  115. // allow this to prevent use of other tuning spaces.
  116. hrc = hr;
  117. } else {
  118. _ASSERT(var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH);
  119. PQTuningSpace pTS(((var.vt == VT_UNKNOWN) ? var.punkVal : var.pdispVal));
  120. CComBSTR UniqueName(GetUniqueName(pTS));
  121. if (!UniqueName.Length()) {
  122. // return Error(IDS_E_NOUNIQUENAME, __uuidof(ITuningSpace), E_UNEXPECTED);
  123. // seanmcd 01/04/04 don't allow a corrupt tuning space to prevent
  124. // use of the rest of them. treat this as a read failure as per the above
  125. // comment
  126. // but remove it from the collection otherwise we've got a name/idx
  127. // cache inconsistency problem
  128. hrc = hr = E_UNEXPECTED; // indicate error to delete corrupt TS below
  129. } else {
  130. m_mapTuningSpaces[idx] = var;
  131. m_mapTuningSpaceNames[UniqueName] = idx;
  132. }
  133. #if 0
  134. // the following code has been tested and works, but i don't want to
  135. // turn it on because stress testing can cause false registry
  136. // read failures that resolve themselves later when the system isn't under
  137. // stress and i don't want to risk deleting a good tuning space just
  138. // because of a bogus read error.
  139. if (FAILED(hr)) {
  140. // delete the corrupt TS
  141. CComVariant var2;
  142. var2.vt = VT_UNKNOWN;
  143. var2.punkVal = NULL;
  144. // can't do anything about a failure so ignore it
  145. m_pTSBag->Write(1, &rgPROPBAG2[ipb2], &var2);
  146. }
  147. #endif
  148. }
  149. }
  150. }
  151. // free space allocated within rgPROPBAG2 by GetPropertyInfo
  152. CoTaskMemFree(rgPROPBAG2[ipb2].pstrName);
  153. }
  154. delete [] rgPROPBAG2;
  155. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  156. CComVariant v;
  157. v.vt = VT_UI4;
  158. hr = pb->Read(MAX_COUNT_NAME, &v, NULL);
  159. if (SUCCEEDED(hr)) {
  160. if (v.vt != VT_UI4) {
  161. hr = ::VariantChangeType(&v, &v, 0, VT_UI4);
  162. if (FAILED(hr)) {
  163. return E_UNEXPECTED;
  164. }
  165. }
  166. m_MaxCount = max(v.lVal, m_mapTuningSpaces.size());
  167. if (m_MaxCount != v.lVal) {
  168. //someone has added stuff to the registry by hand, by defn this is secure
  169. // so just update max_count to be consistent
  170. hr = put_MaxCount(m_MaxCount);
  171. if (FAILED(hr)) {
  172. return E_UNEXPECTED;
  173. }
  174. }
  175. } else {
  176. m_MaxCount = max(DEFAULT_MAX_COUNT, m_mapTuningSpaces.size());
  177. }
  178. #if 0
  179. // we'd like to return some indicator that not all of the tuning spaces we're successfully
  180. // read. but ATL's base CreateInstance method has a check that deletes the object if
  181. // the return code != S_OK which S_FALSE triggers. this results in a successful return code
  182. // with a NULL object pointer being returned which crashes clients(specifically the network
  183. // provider).
  184. if (FAILED(hrc)) {
  185. return Error(IDS_S_INCOMPLETE_LOAD, __uuidof(ITuningSpace), S_FALSE);
  186. }
  187. #endif
  188. return NOERROR;
  189. } CATCHCOM();
  190. }
  191. void CSystemTuningSpaces::FinalRelease()
  192. {
  193. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  194. if (m_hMutex)
  195. CloseHandle(m_hMutex);
  196. }
  197. STDMETHODIMP CSystemTuningSpaces::InterfaceSupportsErrorInfo(REFIID riid)
  198. {
  199. static const IID* arr[] =
  200. {
  201. &IID_ITuningSpaceContainer
  202. };
  203. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  204. {
  205. if (InlineIsEqualGUID(*arr[i],riid))
  206. return S_OK;
  207. }
  208. return S_FALSE;
  209. }
  210. /////////////////////////////////////////////////////////////////////////////////////
  211. HRESULT CSystemTuningSpaces::OpenRootKeyAndBag(REGSAM DesiredAccess) {
  212. CString cs;
  213. cs.LoadString(IDS_TSREGKEY);
  214. // make sure our entry exists
  215. LONG lRes = m_RootKey.Create(HKEY_LOCAL_MACHINE, cs, NULL, REG_OPTION_NON_VOLATILE, DesiredAccess);
  216. if (lRes != ERROR_SUCCESS) {
  217. return HRESULT_FROM_WIN32(lRes);
  218. }
  219. m_CurrentAccess = DesiredAccess;
  220. // create a property bag for this portion of the registry
  221. HRESULT hr = m_pFactory->Create
  222. ( m_RootKey, 0,
  223. 0,
  224. m_CurrentAccess,
  225. __uuidof(IPropertyBag2),
  226. reinterpret_cast<void **>(&m_pTSBag)
  227. );
  228. if (FAILED(hr))
  229. {
  230. return Error(IDS_E_CANNOTCREATEPROPBAG, __uuidof(ITuningSpaceContainer), hr);
  231. }
  232. return NOERROR;
  233. }
  234. HRESULT CSystemTuningSpaces::ChangeAccess(REGSAM NewAccess) {
  235. if (m_CurrentAccess == NewAccess) {
  236. return NOERROR;
  237. }
  238. m_RootKey.Close();
  239. m_pTSBag.Release();
  240. HRESULT hr = OpenRootKeyAndBag(NewAccess);
  241. if (FAILED(hr)) {
  242. return Error(IDS_E_NOREGACCESS, __uuidof(ITuningSpaceContainer), hr);
  243. }
  244. return NOERROR;
  245. }
  246. CComBSTR CSystemTuningSpaces::GetUniqueName(ITuningSpace* pTS) {
  247. // don't assert map size equality here. this function is used to create the name map and will
  248. // always fail during finalconstrcut()
  249. // _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  250. CComBSTR un;
  251. HRESULT hr = pTS->get_UniqueName(&un);
  252. if (FAILED(hr)) {
  253. THROWCOM(hr);
  254. }
  255. return un;
  256. }
  257. ULONG CSystemTuningSpaces::GetID(CComBSTR& un) {
  258. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  259. TuningSpaceNames_t::iterator i = m_mapTuningSpaceNames.find(un);
  260. if (i == m_mapTuningSpaceNames.end()) {
  261. return 0;
  262. }
  263. return (*i).second;
  264. }
  265. HRESULT CSystemTuningSpaces::DeleteID(ULONG id) {
  266. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  267. HRESULT hr = ChangeAccess(KEY_READ | KEY_WRITE);
  268. if (FAILED(hr)) {
  269. return hr;
  270. }
  271. OLECHAR idstr[66];
  272. _ltow(id, idstr, 10);
  273. VARIANT v;
  274. v.vt = VT_EMPTY;
  275. PQPropertyBag p(m_pTSBag);
  276. if (!p) {
  277. return Error(IDS_E_NOREGACCESS, __uuidof(IPropertyBag), E_UNEXPECTED);
  278. }
  279. USES_CONVERSION;
  280. hr = p->Write(idstr, &v);
  281. if (FAILED(hr)) {
  282. return Error(IDS_E_NOREGACCESS, __uuidof(ITuningSpaceContainer), E_UNEXPECTED);
  283. }
  284. return NOERROR;
  285. }
  286. HRESULT CSystemTuningSpaces::Add(CComBSTR& UniqueName, long PreferredID, PQTuningSpace pTS, VARIANT *pvarIndex) {
  287. try {
  288. CAutoMutex mutex(m_hMutex);
  289. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  290. int newcount = m_mapTuningSpaces.size() + 1;
  291. if (!PreferredID || m_mapTuningSpaces.find(PreferredID) == m_mapTuningSpaces.end()) {
  292. // verify no unique name conflict
  293. TuningSpaceNames_t::iterator in;
  294. in = m_mapTuningSpaceNames.find(UniqueName);
  295. if (in != m_mapTuningSpaceNames.end()) {
  296. return Error(IDS_E_DUPLICATETS, __uuidof(ITuningSpace), HRESULT_FROM_WIN32(ERROR_DUP_NAME));
  297. }
  298. // hunt for first available unused id
  299. // start with 1, id 0 is invalid for a tuning space
  300. for (PreferredID = 1;
  301. m_mapTuningSpaces.find(PreferredID) != m_mapTuningSpaces.end();
  302. ++PreferredID) {
  303. }
  304. } else {
  305. // this is the case for complete replacement via idx.
  306. // delete existing data for this id in preparation for overwriting it.
  307. // they may also be changing the unique name at this point.
  308. HRESULT hr = DeleteID(PreferredID);
  309. if (FAILED(hr)){
  310. return hr;
  311. }
  312. newcount--;
  313. }
  314. if (newcount > m_MaxCount) {
  315. return Error(IDS_E_MAXCOUNTEXCEEDED, __uuidof(ITuningSpaceContainer), STG_E_MEDIUMFULL);
  316. }
  317. HRESULT hr = ChangeAccess(KEY_READ | KEY_WRITE);
  318. if (FAILED(hr)) {
  319. return hr;
  320. }
  321. OLECHAR idstr[66];
  322. _ltow(PreferredID, idstr, 10);
  323. PQPropertyBag p(m_pTSBag);
  324. if (!p) {
  325. return Error(IDS_E_NOREGACCESS, __uuidof(IPropertyBag), E_UNEXPECTED);
  326. }
  327. USES_CONVERSION;
  328. VARIANT v;
  329. v.vt = VT_UNKNOWN;
  330. v.punkVal = pTS;
  331. hr = p->Write(idstr, &v);
  332. if (FAILED(hr)) {
  333. return Error(IDS_E_NOREGACCESS, __uuidof(ITuningSpaceContainer), hr);
  334. }
  335. PQTuningSpace newTS;
  336. hr = pTS->Clone(&newTS);
  337. if (FAILED(hr)) {
  338. return hr;
  339. }
  340. m_mapTuningSpaces[PreferredID] = newTS;
  341. m_mapTuningSpaceNames[UniqueName] = PreferredID;
  342. if (pvarIndex) {
  343. VARTYPE savevt = pvarIndex->vt;
  344. VariantClear(pvarIndex);
  345. switch(savevt) {
  346. case VT_BSTR:
  347. pvarIndex->vt = VT_BSTR;
  348. return newTS->get_UniqueName(&pvarIndex->bstrVal);
  349. default:
  350. pvarIndex->vt = VT_I4;
  351. pvarIndex->ulVal = PreferredID;
  352. return NOERROR;
  353. }
  354. }
  355. return NOERROR;
  356. } CATCHCOM();
  357. }
  358. HRESULT CSystemTuningSpaces::Find(TuningSpaceContainer_t::iterator &its, CComBSTR& UniqueName, TuningSpaceNames_t::iterator &itn) {
  359. ATL_LOCK();
  360. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  361. if (its == m_mapTuningSpaces.end()) {
  362. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpace), E_FAIL);
  363. }
  364. _ASSERT(((*its).second.vt == VT_UNKNOWN) || ((*its).second.vt == VT_DISPATCH));
  365. PQTuningSpace pTS((*its).second.punkVal);
  366. if (!pTS) {
  367. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpaceContainer), E_UNEXPECTED);
  368. }
  369. UniqueName = GetUniqueName(pTS);
  370. if (!UniqueName.Length()) {
  371. return Error(IDS_E_NOUNIQUENAME, __uuidof(ITuningSpace), E_UNEXPECTED);
  372. }
  373. itn = m_mapTuningSpaceNames.find(UniqueName);
  374. _ASSERT(itn != m_mapTuningSpaceNames.end()); // cache inconsistency, in container but not in names
  375. return NOERROR;
  376. }
  377. HRESULT CSystemTuningSpaces::Find(VARIANT varIndex, long& ID, TuningSpaceContainer_t::iterator &its, CComBSTR& UniqueName, TuningSpaceNames_t::iterator &itn) {
  378. ATL_LOCK();
  379. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  380. HRESULT hr = S_OK;
  381. VARIANT varTmp;
  382. its = m_mapTuningSpaces.end();
  383. itn = m_mapTuningSpaceNames.end();
  384. PQTuningSpace pTuningSpace;
  385. VariantInit(&varTmp);
  386. // Try finding a tuning space by local system ID
  387. hr = VariantChangeType(&varTmp, &varIndex, 0, VT_I4);
  388. if (!FAILED(hr))
  389. {
  390. _ASSERT(varTmp.vt == VT_I4);
  391. ID = V_I4(&varTmp);
  392. its = m_mapTuningSpaces.find(ID);
  393. } else {
  394. // Try finding a tuning space by name
  395. hr = VariantChangeType(&varTmp, &varIndex, 0, VT_BSTR);
  396. if (FAILED(hr))
  397. {
  398. // we can only get here if both VariantChangeType calls failed
  399. return Error(IDS_E_TYPEMISMATCH, __uuidof(ITuningSpaceContainer), DISP_E_TYPEMISMATCH);
  400. }
  401. _ASSERT(varTmp.vt == VT_BSTR);
  402. UniqueName = V_BSTR(&varTmp);
  403. itn = m_mapTuningSpaceNames.find(UniqueName);
  404. if (itn != m_mapTuningSpaceNames.end()) {
  405. ID = (*itn).second;
  406. its = m_mapTuningSpaces.find(ID);
  407. }
  408. }
  409. if (its == m_mapTuningSpaces.end()) {
  410. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpaceContainer), E_FAIL);
  411. }
  412. _ASSERT(((*its).second.vt == VT_UNKNOWN) || ((*its).second.vt == VT_DISPATCH));
  413. return NOERROR;
  414. }
  415. //////////////////////////////////////////////////////////////////////////////////////
  416. // ITuningSpaceContainer
  417. //////////////////////////////////////////////////////////////////////////////////////
  418. STDMETHODIMP CSystemTuningSpaces::get_Item(/*[in]*/ VARIANT varIndex, /*[out, retval]*/ ITuningSpace **ppTuningSpace) {
  419. if (!ppTuningSpace) {
  420. return E_POINTER;
  421. }
  422. try {
  423. ATL_LOCK();
  424. TuningSpaceContainer_t::iterator its = m_mapTuningSpaces.end();
  425. TuningSpaceNames_t::iterator itn = m_mapTuningSpaceNames.end();
  426. long id;
  427. CComBSTR un;
  428. HRESULT hr = Find(varIndex, id, its, un, itn);
  429. if (FAILED(hr) || its == m_mapTuningSpaces.end()) {
  430. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpaceContainer), E_INVALIDARG);
  431. }
  432. _ASSERT(((*its).second.vt == VT_UNKNOWN) || ((*its).second.vt == VT_DISPATCH));
  433. PQTuningSpace pTS((*its).second.punkVal);
  434. if (!pTS) {
  435. return Error(IDS_E_NOINTERFACE, __uuidof(ITuningSpace), E_NOINTERFACE);
  436. }
  437. PQTuningSpace pTSNew;
  438. hr = pTS->Clone(&pTSNew);
  439. if (FAILED(hr)) {
  440. return hr;
  441. }
  442. *ppTuningSpace = pTSNew.Detach();
  443. return NOERROR;
  444. } catch(...) {
  445. return E_UNEXPECTED;
  446. }
  447. }
  448. STDMETHODIMP CSystemTuningSpaces::put_Item(VARIANT varIndex, ITuningSpace *pTS)
  449. {
  450. if (!pTS) {
  451. return E_POINTER;
  452. }
  453. try {
  454. // wait for exclusive access
  455. CAutoMutex mutex(m_hMutex);
  456. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  457. HRESULT hr = ChangeAccess(KEY_READ | KEY_WRITE);
  458. if (FAILED(hr)) {
  459. return hr;
  460. }
  461. long id;
  462. CComBSTR idxun;
  463. TuningSpaceContainer_t::iterator its;
  464. TuningSpaceNames_t::iterator itn;
  465. hr = Find(varIndex, id, its, idxun, itn);
  466. if (FAILED(hr) || its == m_mapTuningSpaces.end()) {
  467. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpaceContainer), E_INVALIDARG);
  468. }
  469. _ASSERT(((*its).second.vt == VT_UNKNOWN) || ((*its).second.vt == VT_DISPATCH));
  470. CComBSTR un2(GetUniqueName(pTS));
  471. if (!un2.Length()) {
  472. // no uniquename prop set in ts
  473. return Error(IDS_E_NOUNIQUENAME, __uuidof(ITuningSpace), E_UNEXPECTED);
  474. }
  475. if (itn != m_mapTuningSpaceNames.end() && idxun != un2) {
  476. // unique name prop in ts doesn't match string specified in varindex
  477. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpace), E_INVALIDARG);
  478. }
  479. return Add(un2, id, pTS, NULL);
  480. } CATCHCOM();
  481. }
  482. STDMETHODIMP CSystemTuningSpaces::Add(ITuningSpace *pTuningSpace, VARIANT *pvarIndex)
  483. {
  484. try {
  485. // wait for exclusive access
  486. CAutoMutex mutex(m_hMutex);
  487. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  488. HRESULT hr = ChangeAccess(KEY_READ | KEY_WRITE);
  489. if (FAILED(hr)) {
  490. return Error(IDS_E_NOREGACCESS, __uuidof(ITuningSpaceContainer), hr);
  491. }
  492. if (!pTuningSpace) {
  493. return E_POINTER;
  494. }
  495. VARIANT vartmp;
  496. vartmp.vt = VT_I4;
  497. vartmp.ulVal = 0;
  498. if (pvarIndex && pvarIndex->vt != VT_I4) {
  499. hr = VariantChangeType(&vartmp, pvarIndex, 0, VT_I4);
  500. if (FAILED(hr)) {
  501. vartmp.vt = VT_I4;
  502. vartmp.ulVal = 0;
  503. }
  504. }
  505. CComBSTR un(GetUniqueName(pTuningSpace));
  506. if (!un.Length()) {
  507. return Error(IDS_E_NOUNIQUENAME, __uuidof(ITuningSpace), E_FAIL);
  508. }
  509. return Add(un, vartmp.ulVal, pTuningSpace, pvarIndex);
  510. } CATCHCOM();
  511. }
  512. STDMETHODIMP CSystemTuningSpaces::Remove(VARIANT varIndex)
  513. {
  514. try {
  515. // wait for exclusive access
  516. CAutoMutex mutex(m_hMutex);
  517. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  518. HRESULT hr = ChangeAccess(KEY_READ | KEY_WRITE);
  519. if (FAILED(hr)) {
  520. return hr;
  521. }
  522. TuningSpaceContainer_t::iterator its = m_mapTuningSpaces.end();
  523. TuningSpaceNames_t::iterator itn = m_mapTuningSpaceNames.end();
  524. long id;
  525. CComBSTR un;
  526. hr = Find(varIndex, id, its, un, itn);
  527. if (FAILED(hr)) {
  528. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpaceContainer), E_INVALIDARG);
  529. }
  530. if (itn == m_mapTuningSpaceNames.end()) {
  531. ASSERT(its != m_mapTuningSpaces.end()); // otherwise find above should have returned failure
  532. hr = Find(its, un, itn);
  533. if (FAILED(hr) || itn == m_mapTuningSpaceNames.end()) {
  534. // found its but not itn, must have inconsistent cache
  535. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpaceContainer), E_UNEXPECTED);
  536. }
  537. }
  538. m_mapTuningSpaces.erase(its);
  539. m_mapTuningSpaceNames.erase(itn);
  540. return DeleteID(id);
  541. } CATCHCOM();
  542. }
  543. STDMETHODIMP CSystemTuningSpaces::TuningSpacesForCLSID(BSTR bstrSpace, ITuningSpaces **ppTuningSpaces)
  544. {
  545. try {
  546. return _TuningSpacesForCLSID(GUID2(bstrSpace), ppTuningSpaces);
  547. } catch (ComException &e) {
  548. return e;
  549. } catch (...) {
  550. return E_UNEXPECTED;
  551. }
  552. }
  553. STDMETHODIMP CSystemTuningSpaces::_TuningSpacesForCLSID(REFCLSID clsidSpace, ITuningSpaces **ppTuningSpaces)
  554. {
  555. if (!ppTuningSpaces) {
  556. return E_POINTER;
  557. }
  558. try {
  559. ATL_LOCK();
  560. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  561. CTuningSpaces* pTSCollection = new CTuningSpaces;
  562. for (TuningSpaceContainer_t::iterator i = m_mapTuningSpaces.begin(); i != m_mapTuningSpaces.end(); ++i) {
  563. CComVariant v((*i).second);
  564. if (v.vt != VT_UNKNOWN && v.vt != VT_DISPATCH) {
  565. return E_UNEXPECTED; //corrupt in-memory collection
  566. }
  567. PQPersist pTS(v.punkVal);
  568. if (!pTS) {
  569. delete pTSCollection;
  570. return E_UNEXPECTED; // corrupt in-memory collection;
  571. }
  572. GUID2 g;
  573. HRESULT hr = pTS->GetClassID(&g);
  574. if (FAILED(hr)) {
  575. delete pTSCollection;
  576. return E_UNEXPECTED;
  577. }
  578. if (g == clsidSpace) {
  579. PQTuningSpace newts;
  580. hr = PQTuningSpace(pTS)->Clone(&newts);
  581. if (FAILED(hr)) {
  582. delete pTSCollection;
  583. return hr;
  584. }
  585. pTSCollection->m_mapTuningSpaces[(*i).first] = CComVariant(newts);
  586. }
  587. }
  588. *ppTuningSpaces = pTSCollection;
  589. (*ppTuningSpaces)->AddRef();
  590. return NOERROR;
  591. } catch(...) {
  592. return E_UNEXPECTED;
  593. }
  594. }
  595. STDMETHODIMP CSystemTuningSpaces::TuningSpacesForName(BSTR bstrName, ITuningSpaces **ppTuningSpaces)
  596. {
  597. if (!ppTuningSpaces) {
  598. return E_POINTER;
  599. }
  600. try {
  601. ATL_LOCK();
  602. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  603. PQRegExp pRE;
  604. HRESULT hr;
  605. if (!m_cookieRegExp) {
  606. // at the time this code was written the only regex library that was readily available
  607. // was the one in the vbscript engine. therefore we create and access this through
  608. // com. however, this is an apartment model object this we have to create it
  609. // on a background apartment thread so we can always marshall over and access no matter
  610. // what thread we're on.
  611. // there is now a good c++ regex in the http://toolbox and at some point we should probably
  612. // check it for thread safety and convert.
  613. m_pRET = new CRegExThread();
  614. if (!m_pRET) {
  615. return E_OUTOFMEMORY;
  616. }
  617. if (!m_pRET->Create()) {
  618. return E_UNEXPECTED;
  619. }
  620. hr = m_pRET->CallWorker(CRegExThread::RETHREAD_CREATEREGEX);
  621. if (FAILED(hr)) {
  622. return hr;
  623. }
  624. m_cookieRegExp = m_pRET->GetCookie();
  625. if (!m_cookieRegExp) {
  626. return E_UNEXPECTED;
  627. }
  628. }
  629. if (!m_pGIT) {
  630. hr = m_pGIT.CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0, CLSCTX_INPROC_SERVER);
  631. if (FAILED(hr)) {
  632. return hr;
  633. }
  634. }
  635. hr = m_pGIT->GetInterfaceFromGlobal(m_cookieRegExp, __uuidof(IRegExp), reinterpret_cast<LPVOID *>(&pRE));
  636. if (FAILED(hr)) {
  637. return hr;
  638. }
  639. hr = pRE->put_Pattern(bstrName);
  640. if (FAILED(hr)) {
  641. return hr;
  642. }
  643. CTuningSpaces* pTSCollection = new CTuningSpaces;
  644. for (TuningSpaceContainer_t::iterator i = m_mapTuningSpaces.begin(); i != m_mapTuningSpaces.end(); ++i) {
  645. if ((*i).second.vt != VT_UNKNOWN && (*i).second.vt != VT_DISPATCH) {
  646. return E_UNEXPECTED; //corrupt in-memory collection
  647. }
  648. PQTuningSpace pTS((*i).second.punkVal);
  649. CComBSTR name;
  650. hr = pTS->get_FriendlyName(&name);
  651. if (FAILED(hr)) {
  652. return E_UNEXPECTED;
  653. }
  654. PQTuningSpace newTS;
  655. VARIANT_BOOL bMatch = VARIANT_FALSE;
  656. hr = pRE->Test(name, &bMatch);
  657. if (FAILED(hr) || bMatch != VARIANT_TRUE) {
  658. hr = pTS->get_UniqueName(&name);
  659. if (FAILED(hr)) {
  660. return E_UNEXPECTED;
  661. }
  662. hr = pRE->Test(name, &bMatch);
  663. if (FAILED(hr) || bMatch != VARIANT_TRUE) {
  664. continue;
  665. }
  666. }
  667. hr = pTS->Clone(&newTS);
  668. if (FAILED(hr)) {
  669. return hr;
  670. }
  671. pTSCollection->m_mapTuningSpaces[(*i).first] = newTS;
  672. }
  673. *ppTuningSpaces = pTSCollection;
  674. (*ppTuningSpaces)->AddRef();
  675. return NOERROR;
  676. } catch(...) {
  677. return E_UNEXPECTED;
  678. }
  679. }
  680. STDMETHODIMP CSystemTuningSpaces::get_MaxCount(LONG *plVal)
  681. {
  682. if (!plVal) {
  683. return E_POINTER;
  684. }
  685. try {
  686. ATL_LOCK();
  687. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  688. *plVal = m_MaxCount;
  689. return NOERROR;
  690. } catch(...) {
  691. return E_POINTER;
  692. }
  693. }
  694. STDMETHODIMP CSystemTuningSpaces::put_MaxCount(LONG lVal)
  695. {
  696. try {
  697. if (lVal < 0) {
  698. return E_INVALIDARG;
  699. }
  700. CAutoMutex mutex(m_hMutex);
  701. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  702. HRESULT hr = ChangeAccess(KEY_READ | KEY_WRITE);
  703. if (FAILED(hr)) {
  704. return hr;
  705. }
  706. ULONG count = max(lVal, m_mapTuningSpaces.size());
  707. CComVariant v;
  708. v.vt = VT_UI4;
  709. v.lVal = count;
  710. PQPropertyBag pb(m_pTSBag);
  711. if (!pb) {
  712. return E_UNEXPECTED;
  713. }
  714. hr = pb->Write(MAX_COUNT_NAME, &v);
  715. if (FAILED(hr)) {
  716. return hr;
  717. }
  718. m_MaxCount = count;
  719. if (m_MaxCount != lVal) {
  720. return S_FALSE;
  721. }
  722. return NOERROR;
  723. } CATCHCOM();
  724. }
  725. STDMETHODIMP CSystemTuningSpaces::FindID(ITuningSpace *pTS, long* pID)
  726. {
  727. try {
  728. if (!pID || !pTS) {
  729. return E_POINTER;
  730. }
  731. ATL_LOCK();
  732. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  733. CComBSTR un(GetUniqueName(pTS));
  734. if (!un.Length()) {
  735. return Error(IDS_E_NOUNIQUENAME, __uuidof(ITuningSpace), E_UNEXPECTED);
  736. }
  737. *pID = GetID(un);
  738. if (!(*pID)) {
  739. return Error(IDS_E_NO_TS_MATCH, __uuidof(ITuningSpace), E_INVALIDARG);
  740. }
  741. return NOERROR;
  742. } catch (...) {
  743. return E_UNEXPECTED;
  744. }
  745. }
  746. HRESULT CSystemTuningSpaces::RegisterTuningSpaces(HINSTANCE hMod) {
  747. try {
  748. CAutoMutex mutex(m_hMutex);
  749. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  750. CString cs;
  751. cs.LoadString(IDS_RGSLIST_TYPE);
  752. HRSRC hRes = ::FindResource(hMod, MAKEINTRESOURCE(IDR_CANONICAL_TUNINGSPACE_LIST), (LPCTSTR)cs);
  753. if (!hRes) {
  754. return HRESULT_FROM_WIN32(::GetLastError());
  755. }
  756. HANDLE hData = ::LoadResource(hMod, hRes);
  757. if (!hData) {
  758. return HRESULT_FROM_WIN32(::GetLastError());
  759. }
  760. DWORD *p = reinterpret_cast<DWORD *>(::LockResource(hData));
  761. if (!p) {
  762. return HRESULT_FROM_WIN32(::GetLastError());
  763. }
  764. cs.LoadString(IDS_TUNINGSPACE_FRAGMENT_TYPE);
  765. for (DWORD idx = 1; idx <= p[0]; ++idx) {
  766. hRes = ::FindResource(hMod, MAKEINTRESOURCE(p[idx]), (LPCTSTR)cs);
  767. if (!hRes) {
  768. return HRESULT_FROM_WIN32(::GetLastError());
  769. }
  770. LPCSTR psz = reinterpret_cast<LPCSTR>(::LoadResource(hMod, hRes));
  771. if (!psz) {
  772. return HRESULT_FROM_WIN32(::GetLastError());
  773. }
  774. USES_CONVERSION;
  775. int cch;
  776. CRegObject cro; // init %mapping% macros here if desired
  777. PQPropertyBag rgsBag(new CRGSBag(A2CT(psz), cro, cch));
  778. if (!rgsBag) {
  779. return E_UNEXPECTED;
  780. }
  781. CString csName;
  782. csName.LoadString(IDS_TSKEYNAMEVAL);
  783. CComVariant tsval;
  784. HRESULT hr = rgsBag->Read(T2COLE(csName), &tsval, NULL);
  785. if (FAILED(hr)) {
  786. return E_FAIL; // bad script, no unique name property
  787. }
  788. if (tsval.vt != VT_UNKNOWN) {
  789. return DISP_E_TYPEMISMATCH;
  790. }
  791. PQTuningSpace pTS(tsval.punkVal);
  792. if (!pTS) {
  793. return DISP_E_TYPEMISMATCH;
  794. }
  795. CComVariant Varidx;
  796. Varidx.vt = VT_UI4;
  797. Varidx.ulVal = 0;
  798. hr = Add(pTS, &Varidx);
  799. // ignore existing ts w/ same unique name and move one
  800. if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME)) {
  801. return hr;
  802. }
  803. }
  804. return NOERROR;
  805. } CATCHCOM();
  806. }
  807. HRESULT CSystemTuningSpaces::UnregisterTuningSpaces() {
  808. try {
  809. CAutoMutex mutex(m_hMutex);
  810. _ASSERT(m_mapTuningSpaces.size() == m_mapTuningSpaceNames.size());
  811. // currently we delete all tuning spaces when we unreg
  812. // its possible that it would be better to just delete the canonical ones
  813. // that we created when we registered. on the other hand, that reg space
  814. // would leak forever if tv support is really being uninstalled. and, since
  815. // we're in the os we're unlikely to ever get unregistered anyway.
  816. HRESULT hr = OpenRootKeyAndBag(KEY_READ | KEY_WRITE);
  817. if (SUCCEEDED(hr)) {
  818. DWORD rc = m_RootKey.RecurseDeleteKey(_T(""));
  819. if (rc != ERROR_SUCCESS) {
  820. return E_FAIL;
  821. }
  822. }
  823. return NOERROR;
  824. } CATCHCOM();
  825. }
  826. HRESULT UnregisterTuningSpaces() {
  827. PQTuningSpaceContainer pst(CLSID_SystemTuningSpaces, NULL, CLSCTX_INPROC_SERVER);
  828. if (!pst) {
  829. return E_UNEXPECTED;
  830. }
  831. CSystemTuningSpaces *pc = static_cast<CSystemTuningSpaces *>(pst.p);
  832. return pc->UnregisterTuningSpaces();
  833. }
  834. HRESULT RegisterTuningSpaces(HINSTANCE hMod) {
  835. PQTuningSpaceContainer pst(CLSID_SystemTuningSpaces, NULL, CLSCTX_INPROC_SERVER);
  836. if (!pst) {
  837. return E_UNEXPECTED;
  838. }
  839. CSystemTuningSpaces *pc = static_cast<CSystemTuningSpaces *>(pst.p);
  840. return pc->RegisterTuningSpaces(hMod);
  841. }
  842. };
  843. // end of file - tuningspacecontainer.cpp