Leaked source code of windows server 2003
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.

561 lines
14 KiB

  1. // PPPBag.cpp : Implementation of CPropertyPagePropertyBag
  2. #include "stdafx.h"
  3. #include "WizChain.h"
  4. #include "PPPBag.h"
  5. #include "PropItem.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. // CPropertyPagePropertyBag
  8. STDMETHODIMP CPropertyPagePropertyBag::GetProperty( BSTR szGUID, VARIANT* pvar, PPPBAG_TYPE* pdwFlags, BOOL* pbIsOwner )
  9. {
  10. if ( !szGUID || !pvar || !pdwFlags || !pbIsOwner ) return E_POINTER;
  11. CLSID clsid;
  12. HRESULT hr = S_OK;
  13. RPC_STATUS rpcs = UuidFromString( (LPOLESTR)szGUID, &clsid );
  14. if( RPC_S_OK != rpcs )
  15. {
  16. return HRESULT_FROM_WIN32(rpcs);
  17. }
  18. VariantInit( pvar );
  19. *pdwFlags = PPPBAG_TYPE_UNINITIALIZED;
  20. // no need to make sure szGUID is a valid guid
  21. // since it won't be in the map
  22. std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter;
  23. mapiter = m_map.find( szGUID );
  24. if( mapiter != m_map.end() )
  25. {
  26. CBagEntry * pBE = mapiter->second;
  27. if( pBE )
  28. {
  29. if( SUCCEEDED(VariantCopy( pvar, pBE->GetVariant() )) )
  30. {
  31. *pdwFlags = pBE->GetFlags( );
  32. *pbIsOwner = (pBE->GetOwner( ) == m_dwOwner);
  33. return S_OK;
  34. }
  35. else
  36. {
  37. return E_FAIL;
  38. }
  39. }
  40. }
  41. return E_INVALIDARG;
  42. }
  43. // a couple of helper functions
  44. HRESULT HelperDelete(std::map<BSTR, CBagEntry*, CBSTR_Less>& map, BSTR szGUID, DWORD dwOwner );
  45. HRESULT HelperAdd (std::map<BSTR, CBagEntry*, CBSTR_Less>& map, BSTR szGUID, CBagEntry* pBE);
  46. STDMETHODIMP CPropertyPagePropertyBag::SetProperty( BSTR szGUID, VARIANT* pvar, PPPBAG_TYPE dwFlags )
  47. {
  48. // validate parameters
  49. if( !szGUID || !pvar ) return E_POINTER;
  50. CLSID clsid;
  51. RPC_STATUS rpcs = UuidFromString( (LPOLESTR)szGUID, &clsid );
  52. if( RPC_S_OK != rpcs )
  53. {
  54. return HRESULT_FROM_WIN32(rpcs);
  55. }
  56. switch( dwFlags )
  57. {
  58. case PPPBAG_TYPE_READWRITE:
  59. case PPPBAG_TYPE_READONLY:
  60. case PPPBAG_TYPE_ADDITIVE:
  61. case PPPBAG_TYPE_DELETION:
  62. {
  63. break;
  64. }
  65. default:
  66. {
  67. return E_INVALIDARG;
  68. }
  69. }
  70. if( m_bReadOnly != FALSE )
  71. {
  72. return E_UNEXPECTED;
  73. }
  74. switch( dwFlags )
  75. {
  76. case PPPBAG_TYPE_DELETION:
  77. {
  78. return HelperDelete( m_map, szGUID, m_dwOwner );
  79. }
  80. case PPPBAG_TYPE_READWRITE:
  81. {
  82. // anyone can write to one of these
  83. HelperDelete( m_map, szGUID, m_dwOwner );
  84. CBagEntry* pBagEntry = new CBagEntry( pvar, dwFlags, m_dwOwner );
  85. if( !pBagEntry ) return E_OUTOFMEMORY;
  86. return HelperAdd( m_map, szGUID, pBagEntry );
  87. }
  88. case PPPBAG_TYPE_READONLY:
  89. {
  90. // only allow owner to write to this kind of entry
  91. HRESULT hr = HelperDelete( m_map, szGUID, m_dwOwner );
  92. if( hr == S_OK )
  93. {
  94. CBagEntry* pBagEntry = new CBagEntry( pvar, dwFlags, m_dwOwner );
  95. if( !pBagEntry ) return E_OUTOFMEMORY;
  96. hr = HelperAdd( m_map, szGUID, pBagEntry );
  97. }
  98. return hr;
  99. }
  100. case PPPBAG_TYPE_ADDITIVE:
  101. {
  102. // TODO: add code so that additive properties work correctly
  103. return E_NOTIMPL;
  104. }
  105. }
  106. return S_OK;
  107. }
  108. HRESULT HelperDelete( std::map<BSTR, CBagEntry*, CBSTR_Less> & map, BSTR szGUID, DWORD dwOwner )
  109. {
  110. std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter;
  111. mapiter = map.find( szGUID );
  112. if( mapiter != map.end( ) )
  113. {
  114. CBagEntry * pBE = mapiter->second;
  115. if( pBE )
  116. {
  117. if( pBE->GetFlags( ) == PPPBAG_TYPE_READONLY )
  118. {
  119. if( pBE->GetOwner( ) != dwOwner ) // component's trying to delete
  120. {
  121. return E_UNEXPECTED; // an entry that doesn't belong to it
  122. }
  123. }
  124. }
  125. SysFreeString( mapiter->first );
  126. delete mapiter->second;
  127. map.erase( mapiter );
  128. }
  129. return S_OK;
  130. }
  131. HRESULT HelperAdd( std::map<BSTR, CBagEntry*, CBSTR_Less>& map, BSTR szGUID, CBagEntry* pBE )
  132. {
  133. std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter = map.find( szGUID );
  134. if( mapiter != map.end() )
  135. {
  136. assert( 0 && "this should have been deleted by now!" );
  137. SysFreeString( mapiter->first );
  138. delete mapiter->second;
  139. map.erase( mapiter );
  140. }
  141. BSTR bstr = SysAllocString( (LPOLESTR)szGUID );
  142. if( !bstr )
  143. {
  144. return E_OUTOFMEMORY;
  145. }
  146. map[bstr] = pBE;
  147. return S_OK;
  148. }
  149. HRESULT CPropertyPagePropertyBag::Enumerate( long index, BSTR* pbstr, VARIANT* pvar, PPPBAG_TYPE* pdwFlags, BOOL* pbIsOwner, BOOL* pbInRange )
  150. {
  151. if( !pbstr || !pvar|| !pdwFlags || !pbIsOwner || !pbInRange ) return E_POINTER;
  152. if( index >= 0 )
  153. {
  154. long i = 0;
  155. std::map<BSTR, CBagEntry *, CBSTR_Less>::iterator mapiter = m_map.begin( );
  156. while( mapiter != m_map.end() )
  157. {
  158. if( i == index )
  159. {
  160. *pbstr = SysAllocString( mapiter->first );
  161. CBagEntry* pBE = mapiter->second;
  162. assert( pBE != NULL );
  163. if( SUCCEEDED(VariantCopy( pvar, pBE->GetVariant() )) )
  164. {
  165. *pdwFlags = pBE->GetFlags();
  166. *pbIsOwner = (pBE->GetOwner() == m_dwOwner);
  167. *pbInRange = TRUE;
  168. return S_OK;
  169. }
  170. return E_FAIL;
  171. }
  172. mapiter++;
  173. i++;
  174. }
  175. }
  176. // out of range
  177. *pdwFlags = PPPBAG_TYPE_UNINITIALIZED;
  178. *pbInRange = FALSE;
  179. return S_FALSE;
  180. }
  181. // helper
  182. IDispatch* CreateItem( BSTR bstrGuid, VARIANT* var, PPPBAG_TYPE dwFlags )
  183. {
  184. // create the item and initialize it
  185. CComObject<CPropertyItem>* pPI = NULL;
  186. CComObject<CPropertyItem>::CreateInstance( &pPI );
  187. if( !pPI ) return NULL;
  188. pPI->Initialize( bstrGuid, var, dwFlags ); // Initialize the Property Item
  189. // return back an IDispatch *
  190. IDispatch* pDisp = NULL;
  191. pPI->AddRef( );
  192. pPI->QueryInterface( IID_IDispatch, (void**)&pDisp ); // can't fail
  193. pPI->Release( );
  194. assert( pDisp != NULL );
  195. return pDisp;
  196. }
  197. class CEnumVariant : public IEnumVARIANT
  198. {
  199. private:
  200. ULONG m_refs;
  201. ULONG m_index;
  202. CPropertyPagePropertyBag* m_pPPPBag; // addref'd !
  203. CEnumVariant( CPropertyPagePropertyBag* pPPPBag )
  204. {
  205. assert( pPPPBag != NULL );
  206. m_refs = 0;
  207. m_index = 0;
  208. m_pPPPBag = pPPPBag;
  209. m_pPPPBag->AddRef();
  210. }
  211. ~CEnumVariant ()
  212. {
  213. m_pPPPBag->Release();
  214. }
  215. public:
  216. static IEnumVARIANT* CreateInstance( CPropertyPagePropertyBag* pPPPBag )
  217. {
  218. assert( pPPPBag != NULL );
  219. CEnumVariant* pCEV = new CEnumVariant( pPPPBag );
  220. if( !pCEV )
  221. {
  222. return NULL;
  223. }
  224. IEnumVARIANT* pIEV = NULL;
  225. pCEV->AddRef( );
  226. pCEV->QueryInterface( IID_IEnumVARIANT, (void**)&pIEV );
  227. pCEV->Release( );
  228. return pIEV;
  229. }
  230. // IUnknown
  231. virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppvObject )
  232. {
  233. HRESULT hr = S_OK;
  234. if ((riid == IID_IUnknown) ||
  235. (riid == IID_IEnumVARIANT) )
  236. {
  237. AddRef();
  238. *ppvObject = (void*)this;
  239. }
  240. else
  241. {
  242. hr = E_NOINTERFACE;
  243. }
  244. return hr;
  245. }
  246. virtual ULONG STDMETHODCALLTYPE AddRef( )
  247. {
  248. InterlockedIncrement( (PLONG)&m_refs );
  249. return m_refs;
  250. }
  251. virtual ULONG STDMETHODCALLTYPE Release( )
  252. {
  253. InterlockedDecrement( (PLONG)&m_refs );
  254. ULONG l = m_refs;
  255. if( m_refs == 0 )
  256. {
  257. delete this;
  258. }
  259. return l;
  260. }
  261. // IEnumVARIANT
  262. virtual HRESULT STDMETHODCALLTYPE Next( /*[in]*/ ULONG celt, /*[out, size_is(celt), length_is(*pCeltFetched)]*/ VARIANT* rgVar, /*[out]*/ ULONG* pCeltFetched )
  263. {
  264. // clear stuff being passed in (just in case)
  265. if( pCeltFetched )
  266. {
  267. *pCeltFetched = 0;
  268. }
  269. for( ULONG i = 0; i < celt; i++ )
  270. {
  271. VariantInit( &rgVar[i] );
  272. }
  273. // get the next celt elements
  274. for( i = 0; i < celt; i++ )
  275. {
  276. BSTR bstr = NULL;
  277. VARIANT var;
  278. VariantInit( &var );
  279. PPPBAG_TYPE dwFlags = PPPBAG_TYPE_UNINITIALIZED;
  280. BOOL bIsOwner = FALSE;
  281. BOOL bInRange = FALSE;
  282. m_pPPPBag->Enumerate( (long)m_index++, &bstr, &var, &dwFlags, &bIsOwner, &bInRange );
  283. if( bInRange == FALSE )
  284. {
  285. break;
  286. }
  287. IDispatch* pDisp = CreateItem( bstr, &var, dwFlags );
  288. VariantClear( &var );
  289. if( pDisp == NULL )
  290. {
  291. return E_OUTOFMEMORY;
  292. }
  293. rgVar[i].vt = VT_DISPATCH;
  294. rgVar[i].pdispVal = pDisp;
  295. }
  296. // fill out how many we're returning
  297. if( pCeltFetched )
  298. {
  299. *pCeltFetched = i;
  300. }
  301. return ( (i < celt) ? S_FALSE : S_OK);
  302. }
  303. virtual HRESULT STDMETHODCALLTYPE Skip( /*[in]*/ ULONG celt )
  304. {
  305. long count;
  306. m_pPPPBag->get_Count( &count );
  307. if( (celt + m_index) > (ULONG)count )
  308. {
  309. return S_FALSE;
  310. }
  311. m_index += celt;
  312. return S_OK;
  313. }
  314. virtual HRESULT STDMETHODCALLTYPE Reset( )
  315. {
  316. m_index = 0;
  317. return S_OK;
  318. }
  319. virtual HRESULT STDMETHODCALLTYPE Clone( /*[out]*/ IEnumVARIANT** ppEnum )
  320. {
  321. if( !(*ppEnum = CreateInstance( m_pPPPBag )) )
  322. {
  323. return E_OUTOFMEMORY;
  324. }
  325. return S_OK;
  326. }
  327. };
  328. // CPropertyCollection
  329. STDMETHODIMP CPropertyPagePropertyBag::get__NewEnum( IUnknown** pVal )
  330. {
  331. if( !pVal ) return E_POINTER;
  332. IEnumVARIANT* pEV = CEnumVariant::CreateInstance( this );
  333. if( !pEV ) return E_OUTOFMEMORY;
  334. HRESULT hr = pEV->QueryInterface( IID_IUnknown, (void**)pVal );
  335. pEV->Release();
  336. return hr;
  337. }
  338. STDMETHODIMP CPropertyPagePropertyBag::get_Item( VARIANT* pVar, IDispatch** pVal )
  339. {
  340. // handle both:
  341. // objFoo.Item(1), and
  342. // objFoo.Item("string");
  343. // validate parameters
  344. if( !pVar || !pVal ) return E_POINTER;
  345. *pVal = NULL;
  346. if( V_VT(pVar) == VT_BSTR )
  347. {
  348. BSTR bstrGuid = V_BSTR(pVar);
  349. CLSID clsid;
  350. HRESULT hr = S_OK;
  351. RPC_STATUS rpcs = UuidFromString( (LPOLESTR)bstrGuid, &clsid );
  352. if( RPC_S_OK != rpcs )
  353. {
  354. return HRESULT_FROM_WIN32(rpcs);
  355. }
  356. std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter;
  357. mapiter = m_map.find( bstrGuid );
  358. if( mapiter != m_map.end() )
  359. {
  360. CBagEntry* pBE = mapiter->second;
  361. if( pBE )
  362. {
  363. if( !(*pVal = CreateItem( bstrGuid, pBE->GetVariant(), pBE->GetFlags() )) )
  364. {
  365. return E_OUTOFMEMORY;
  366. }
  367. return S_OK;
  368. }
  369. }
  370. }
  371. else if ( (V_VT(pVar) == VT_I2) || (V_VT(pVar) == VT_I4) )
  372. {
  373. long index;
  374. if( V_VT(pVar) == VT_I4 )
  375. {
  376. index = V_I4(pVar);
  377. }
  378. else
  379. {
  380. index = V_I2(pVar);
  381. }
  382. BSTR bstr = NULL;
  383. VARIANT var;
  384. VariantInit (&var);
  385. PPPBAG_TYPE dwFlags = PPPBAG_TYPE_UNINITIALIZED;
  386. BOOL bIsOwner = FALSE;
  387. BOOL bInRange = FALSE;
  388. HRESULT hr = Enumerate( index, &bstr, &var, &dwFlags, &bIsOwner, &bInRange );
  389. if( SUCCEEDED(hr) && (bInRange == TRUE) )
  390. {
  391. if( !(*pVal = CreateItem( bstr, &var, dwFlags )) )
  392. {
  393. hr = E_OUTOFMEMORY;
  394. }
  395. }
  396. VariantClear ( &var );
  397. SysFreeString( bstr );
  398. return hr;
  399. }
  400. else
  401. {
  402. return E_UNEXPECTED; // not a valid variant type
  403. }
  404. return S_FALSE;
  405. }
  406. STDMETHODIMP CPropertyPagePropertyBag::get_Count( long *pVal )
  407. {
  408. if( !pVal ) return E_POINTER;
  409. // TODO: figure out how to use map.count method
  410. long i = 0;
  411. std::map<BSTR, CBagEntry*, CBSTR_Less>::iterator mapiter = m_map.begin();
  412. while( mapiter != m_map.end() )
  413. {
  414. mapiter++;
  415. i++;
  416. }
  417. *pVal = i;
  418. return S_OK;
  419. }
  420. STDMETHODIMP CPropertyPagePropertyBag::Add(BSTR bstrGuid, VARIANT *varValue, long iFlags, IPropertyItem **ppItem)
  421. {
  422. // validate parameters
  423. if( !bstrGuid || !varValue || !ppItem ) return E_POINTER;
  424. *ppItem = NULL;
  425. HRESULT hr = SetProperty( bstrGuid, varValue, (PPPBAG_TYPE)iFlags );
  426. if( hr == S_OK )
  427. {
  428. IDispatch* pDisp = CreateItem( bstrGuid, varValue, (PPPBAG_TYPE)iFlags );
  429. if( !pDisp )
  430. {
  431. hr = E_OUTOFMEMORY;
  432. }
  433. else
  434. {
  435. hr = pDisp->QueryInterface( IID_IPropertyItem, (void**)ppItem );
  436. pDisp->Release();
  437. }
  438. }
  439. return hr;
  440. }
  441. STDMETHODIMP CPropertyPagePropertyBag::Remove( BSTR bstrGuid )
  442. {
  443. if( !bstrGuid ) return E_POINTER;
  444. CLSID clsid;
  445. RPC_STATUS rpcs = UuidFromString( (LPOLESTR)bstrGuid, &clsid );
  446. if( RPC_S_OK != rpcs )
  447. {
  448. return HRESULT_FROM_WIN32(rpcs);
  449. }
  450. return HelperDelete( m_map, bstrGuid, m_dwOwner );
  451. }