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.

1112 lines
22 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1997
  5. //
  6. // File: ctree.cxx
  7. //
  8. // Contents: Microsoft ADs IIS Provider Tree Object
  9. //
  10. // History: 25-Feb-97 SophiaC Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "iis.hxx"
  14. #pragma hdrstop
  15. // Class CIISTree
  16. DEFINE_IDispatch_Implementation(CIISTree)
  17. DEFINE_IADs_Implementation(CIISTree)
  18. CIISTree::CIISTree():
  19. _pAdminBase(NULL),
  20. _pSchema(NULL),
  21. _pPropertyCache(NULL)
  22. {
  23. VariantInit(&_vFilter);
  24. ENLIST_TRACKING(CIISTree);
  25. }
  26. /* #pragma INTRINSA suppress=all */
  27. HRESULT
  28. CIISTree::CreateServerObject(
  29. BSTR bstrADsPath,
  30. CCredentials& Credentials,
  31. DWORD dwObjectState,
  32. REFIID riid,
  33. void **ppvObj
  34. )
  35. {
  36. HRESULT hr = S_OK;
  37. LPWSTR pszADsParent = NULL;
  38. WCHAR szCommonName[MAX_PATH+MAX_PROVIDER_TOKEN_LENGTH];
  39. pszADsParent = AllocADsStr(bstrADsPath);
  40. if (!pszADsParent) {
  41. hr = E_OUTOFMEMORY;
  42. BAIL_ON_FAILURE(hr);
  43. }
  44. *pszADsParent = L'\0';
  45. //
  46. // Determine the parent and rdn name
  47. //
  48. hr = BuildADsParentPath(
  49. bstrADsPath,
  50. pszADsParent,
  51. szCommonName
  52. );
  53. //
  54. // call the helper function
  55. //
  56. hr = CIISTree::CreateServerObject(
  57. pszADsParent,
  58. szCommonName,
  59. L"user",
  60. Credentials,
  61. dwObjectState,
  62. riid,
  63. ppvObj
  64. );
  65. error:
  66. if (pszADsParent) {
  67. FreeADsStr(pszADsParent);
  68. }
  69. RRETURN(hr);
  70. }
  71. HRESULT
  72. CIISTree::CreateServerObject(
  73. BSTR Parent,
  74. BSTR CommonName,
  75. BSTR ClassName,
  76. CCredentials& Credentials,
  77. DWORD dwObjectState,
  78. REFIID riid,
  79. void **ppvObj
  80. )
  81. {
  82. CIISTree FAR * pTree = NULL;
  83. HRESULT hr = S_OK;
  84. hr = AllocateTree(Credentials, &pTree);
  85. BAIL_ON_FAILURE(hr);
  86. hr = pTree->InitializeCoreObject(
  87. Parent,
  88. CommonName,
  89. ClassName,
  90. L"",
  91. CLSID_IISTree,
  92. dwObjectState
  93. );
  94. BAIL_ON_FAILURE(hr);
  95. hr = pTree->_pPropertyCache->InitializePropertyCache( CommonName );
  96. BAIL_ON_FAILURE(hr);
  97. hr = pTree->QueryInterface(riid, ppvObj);
  98. BAIL_ON_FAILURE(hr);
  99. pTree->Release();
  100. RRETURN(hr);
  101. error:
  102. delete pTree;
  103. RRETURN(hr);
  104. }
  105. CIISTree::~CIISTree( )
  106. {
  107. VariantClear(&_vFilter);
  108. delete _pDispMgr;
  109. delete _pPropertyCache;
  110. }
  111. STDMETHODIMP
  112. CIISTree::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  113. {
  114. if (IsEqualIID(iid, IID_IUnknown))
  115. {
  116. *ppv = (IADs FAR *) this;
  117. }
  118. else if (IsEqualIID(iid, IID_IADsContainer))
  119. {
  120. *ppv = (IADsContainer FAR *) this;
  121. }
  122. else if (IsEqualIID(iid, IID_IADs))
  123. {
  124. *ppv = (IADs FAR *) this;
  125. }
  126. else if (IsEqualIID(iid, IID_IDispatch))
  127. {
  128. *ppv = (IADs FAR *) this;
  129. }
  130. else
  131. {
  132. *ppv = NULL;
  133. return E_NOINTERFACE;
  134. }
  135. AddRef();
  136. return NOERROR;
  137. }
  138. HRESULT
  139. CIISTree::SetInfo()
  140. {
  141. HRESULT hr = S_OK;
  142. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  143. hr = IISCreateObject();
  144. BAIL_ON_FAILURE(hr);
  145. //
  146. // If the create succeded, set the object type to bound
  147. //
  148. SetObjectState(ADS_OBJECT_BOUND);
  149. }else {
  150. hr = IISSetObject();
  151. BAIL_ON_FAILURE(hr);
  152. }
  153. error:
  154. RRETURN(hr);
  155. }
  156. HRESULT
  157. CIISTree::IISSetObject()
  158. {
  159. DWORD dwStatus = 0L;
  160. LPWSTR pszIISPathName = NULL;
  161. HRESULT hr = S_OK;
  162. hr = BuildIISPathFromADsPath(
  163. _ADsPath,
  164. &pszIISPathName
  165. );
  166. BAIL_ON_FAILURE(hr);
  167. //
  168. // Add Set functionality: sophiac
  169. //
  170. error:
  171. if (pszIISPathName) {
  172. FreeADsStr(pszIISPathName);
  173. }
  174. RRETURN(hr);
  175. }
  176. HRESULT
  177. CIISTree::IISCreateObject()
  178. {
  179. DWORD dwStatus = 0L;
  180. LPWSTR pszIISParentName = NULL;
  181. HRESULT hr = S_OK;
  182. hr = BuildIISPathFromADsPath(
  183. _Parent,
  184. &pszIISParentName
  185. );
  186. BAIL_ON_FAILURE(hr);
  187. //
  188. // Add Create functionality: sophiac
  189. //
  190. error:
  191. if (pszIISParentName) {
  192. FreeADsStr(pszIISParentName);
  193. }
  194. RRETURN(hr);
  195. }
  196. HRESULT
  197. CIISTree::GetInfo()
  198. {
  199. RRETURN(GetInfo(TRUE));
  200. }
  201. HRESULT
  202. CIISTree::GetInfo(
  203. BOOL fExplicit
  204. )
  205. {
  206. DWORD dwStatus = 0L;
  207. HANDLE hObject = NULL;
  208. LPWSTR pszIISPathName = NULL;
  209. HRESULT hr;
  210. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  211. hr = E_ADS_OBJECT_UNBOUND;
  212. BAIL_ON_FAILURE(hr);
  213. }
  214. hr = BuildIISPathFromADsPath(
  215. _ADsPath,
  216. &pszIISPathName
  217. );
  218. BAIL_ON_FAILURE(hr);
  219. //
  220. // Add get functionality : sophiac
  221. //
  222. error:
  223. if (pszIISPathName) {
  224. FreeADsStr(pszIISPathName);
  225. }
  226. RRETURN(hr);
  227. }
  228. /* IADsContainer methods */
  229. STDMETHODIMP
  230. CIISTree::get_Count(long FAR* retval)
  231. {
  232. RRETURN(E_NOTIMPL);
  233. }
  234. STDMETHODIMP
  235. CIISTree::get_Filter(THIS_ VARIANT FAR* pVar)
  236. {
  237. VariantInit(pVar);
  238. RRETURN(VariantCopy(pVar, &_vFilter));
  239. }
  240. STDMETHODIMP
  241. CIISTree::put_Filter(THIS_ VARIANT Var)
  242. {
  243. RRETURN(VariantCopy(&_vFilter, &Var));
  244. }
  245. STDMETHODIMP
  246. CIISTree::put_Hints(THIS_ VARIANT Var)
  247. {
  248. RRETURN( E_NOTIMPL);
  249. }
  250. STDMETHODIMP
  251. CIISTree::get_Hints(THIS_ VARIANT FAR* pVar)
  252. {
  253. RRETURN(E_NOTIMPL);
  254. }
  255. STDMETHODIMP
  256. CIISTree::GetObject(
  257. BSTR ClassName,
  258. BSTR RelativeName,
  259. IDispatch * FAR* ppObject
  260. )
  261. {
  262. HRESULT hr = S_OK;
  263. hr = ::RelativeGetObject(
  264. _ADsPath,
  265. ClassName,
  266. RelativeName,
  267. _Credentials,
  268. ppObject,
  269. FALSE
  270. );
  271. RRETURN(hr);
  272. }
  273. STDMETHODIMP
  274. CIISTree::get__NewEnum(
  275. THIS_ IUnknown * FAR* retval
  276. )
  277. {
  278. HRESULT hr;
  279. IUnknown FAR* punkEnum=NULL;
  280. IEnumVARIANT * penum = NULL;
  281. *retval = NULL;
  282. hr = CIISTreeEnum::Create(
  283. (CIISTreeEnum **)&penum,
  284. _ADsPath,
  285. _vFilter,
  286. _Credentials
  287. );
  288. BAIL_ON_FAILURE(hr);
  289. hr = penum->QueryInterface(
  290. IID_IUnknown,
  291. (VOID FAR* FAR*)retval
  292. );
  293. BAIL_ON_FAILURE(hr);
  294. if (penum) {
  295. penum->Release();
  296. }
  297. RRETURN(NOERROR);
  298. error:
  299. if (penum) {
  300. delete penum;
  301. }
  302. RRETURN(hr);
  303. }
  304. STDMETHODIMP
  305. CIISTree::Create(
  306. THIS_ BSTR ClassName,
  307. BSTR RelativeName,
  308. IDispatch * FAR* ppObject
  309. )
  310. {
  311. HRESULT hr = S_OK;
  312. IADs * pADs = NULL;
  313. VARIANT var;
  314. DWORD dwSyntaxId = 0;
  315. OBJECTINFO ObjectInfo;
  316. POBJECTINFO pObjectInfo = &ObjectInfo;
  317. //
  318. // Validate if this class really exists in the schema
  319. // and validate that this object can be created in this
  320. // container
  321. //
  322. CLexer Lexer(_ADsPath);
  323. BAIL_ON_FAILURE(hr);
  324. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  325. hr = ADsObject(&Lexer, pObjectInfo);
  326. BAIL_ON_FAILURE(hr);
  327. hr = InitServerInfo(pObjectInfo->TreeName, &_pAdminBase, &_pSchema);
  328. BAIL_ON_FAILURE(hr);
  329. hr = _pSchema->ValidateClassName(ClassName);
  330. BAIL_ON_FAILURE(hr);
  331. hr = CIISGenObject::CreateGenericObject(
  332. _ADsPath,
  333. RelativeName,
  334. ClassName,
  335. _Credentials,
  336. ADS_OBJECT_UNBOUND,
  337. IID_IDispatch,
  338. (void **)ppObject
  339. );
  340. BAIL_ON_FAILURE(hr);
  341. RRETURN(hr);
  342. error:
  343. RRETURN(hr);
  344. }
  345. STDMETHODIMP
  346. CIISTree::Delete(
  347. THIS_ BSTR bstrClassName,
  348. BSTR bstrRelativeName
  349. )
  350. {
  351. LPWSTR pszIISPathName = NULL;
  352. HRESULT hr = S_OK;
  353. hr = BuildIISPathFromADsPath(
  354. _ADsPath,
  355. &pszIISPathName
  356. );
  357. BAIL_ON_FAILURE(hr);
  358. //
  359. //
  360. // Add delete functionality : sophiac
  361. //
  362. error:
  363. if (pszIISPathName) {
  364. FreeADsStr(pszIISPathName);
  365. }
  366. RRETURN(hr);
  367. }
  368. STDMETHODIMP
  369. CIISTree::CopyHere(
  370. THIS_ BSTR SourceName,
  371. BSTR NewName,
  372. IDispatch * FAR* ppObject
  373. )
  374. {
  375. RRETURN(E_NOTIMPL);
  376. }
  377. STDMETHODIMP
  378. CIISTree::MoveHere(
  379. THIS_ BSTR SourceName,
  380. BSTR NewName,
  381. IDispatch * FAR* ppObject
  382. )
  383. {
  384. RRETURN(E_NOTIMPL);
  385. }
  386. HRESULT
  387. CIISTree::AllocateTree(
  388. CCredentials& Credentials,
  389. CIISTree ** ppTree
  390. )
  391. {
  392. CIISTree FAR * pTree = NULL;
  393. CAggregatorDispMgr FAR * pDispMgr = NULL;
  394. CPropertyCache FAR * pPropertyCache = NULL;
  395. HRESULT hr = S_OK;
  396. pTree = new CIISTree();
  397. if (pTree == NULL) {
  398. hr = E_OUTOFMEMORY;
  399. }
  400. BAIL_ON_FAILURE(hr);
  401. pDispMgr = new CAggregatorDispMgr;
  402. if (pDispMgr == NULL) {
  403. hr = E_OUTOFMEMORY;
  404. }
  405. BAIL_ON_FAILURE(hr);
  406. hr = pDispMgr->LoadTypeInfoEntry(
  407. LIBID_ADs,
  408. IID_IADs,
  409. (IADs *)pTree,
  410. DISPID_REGULAR
  411. );
  412. BAIL_ON_FAILURE(hr);
  413. hr = pDispMgr->LoadTypeInfoEntry(
  414. LIBID_ADs,
  415. IID_IADsContainer,
  416. (IADsContainer *)pTree,
  417. DISPID_NEWENUM
  418. );
  419. BAIL_ON_FAILURE(hr);
  420. hr = CPropertyCache::createpropertycache(
  421. (CCoreADsObject FAR *)pTree,
  422. &pPropertyCache
  423. );
  424. BAIL_ON_FAILURE(hr);
  425. pTree->_Credentials = Credentials;
  426. pTree->_pPropertyCache = pPropertyCache;
  427. pTree->_pDispMgr = pDispMgr;
  428. *ppTree = pTree;
  429. RRETURN(hr);
  430. error:
  431. delete pDispMgr;
  432. RRETURN(hr);
  433. }
  434. /* INTRINSA suppress=null_pointers, uninitialized */
  435. STDMETHODIMP
  436. CIISTree::Get(
  437. THIS_ BSTR bstrName,
  438. VARIANT FAR* pvProp
  439. )
  440. {
  441. HRESULT hr = S_OK;
  442. DWORD dwSyntaxId;
  443. DWORD dwSyntax;
  444. DWORD dwNumValues = 0;
  445. LPIISOBJECT pIISSrcObjects = NULL;
  446. WCHAR wchName[MAX_PATH];
  447. //
  448. // check if property is a supported property
  449. //
  450. hr = _pSchema->LookupSyntaxID(bstrName, &dwSyntax);
  451. BAIL_ON_FAILURE(hr);
  452. //
  453. // check if property is BITMASK type;
  454. // if BITMASK type, get corresponding DWORD flag property
  455. //
  456. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) {
  457. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  458. BAIL_ON_FAILURE(hr);
  459. }
  460. //
  461. // retrieve data object from cache; if one exists
  462. //
  463. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY)
  464. {
  465. hr = _pPropertyCache->getproperty(
  466. wchName,
  467. &dwSyntaxId,
  468. &dwNumValues,
  469. &pIISSrcObjects
  470. );
  471. }
  472. else
  473. {
  474. hr = _pPropertyCache->getproperty(
  475. bstrName,
  476. &dwSyntaxId,
  477. &dwNumValues,
  478. &pIISSrcObjects
  479. );
  480. }
  481. BAIL_ON_FAILURE(hr);
  482. //
  483. // reset it to its syntax id if BITMASK type
  484. //
  485. pIISSrcObjects->IISType = dwSyntax;
  486. //
  487. // translate the IIS objects to variants
  488. //
  489. if (dwNumValues == 1) {
  490. hr = IISTypeToVarTypeCopy(
  491. _pSchema,
  492. bstrName,
  493. pIISSrcObjects,
  494. pvProp,
  495. FALSE
  496. );
  497. }else {
  498. hr = IISTypeToVarTypeCopyConstruct(
  499. _pSchema,
  500. bstrName,
  501. pIISSrcObjects,
  502. dwNumValues,
  503. pvProp,
  504. FALSE
  505. );
  506. }
  507. BAIL_ON_FAILURE(hr);
  508. error:
  509. if (pIISSrcObjects) {
  510. IISTypeFreeIISObjects(
  511. pIISSrcObjects,
  512. dwNumValues
  513. );
  514. }
  515. RRETURN(hr);
  516. }
  517. /* INTRINSA suppress=null_pointers, uninitialized */
  518. STDMETHODIMP
  519. CIISTree::GetEx(
  520. THIS_ BSTR bstrName,
  521. VARIANT FAR* pvProp
  522. )
  523. {
  524. HRESULT hr = S_OK;
  525. DWORD dwSyntaxId;
  526. DWORD dwSyntax;
  527. DWORD dwNumValues = 0;
  528. LPIISOBJECT pIISSrcObjects = NULL;
  529. WCHAR wchName[MAX_PATH];
  530. //
  531. // check if property is a supported property
  532. //
  533. hr = _pSchema->LookupSyntaxID(bstrName, &dwSyntax);
  534. BAIL_ON_FAILURE(hr);
  535. //
  536. // check if property is BITMASK type;
  537. // if BITMASK type, get corresponding DWORD flag property
  538. //
  539. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) {
  540. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  541. BAIL_ON_FAILURE(hr);
  542. }
  543. //
  544. // retrieve data object from cache; if one exists
  545. //
  546. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY)
  547. {
  548. hr = _pPropertyCache->getproperty(
  549. wchName,
  550. &dwSyntaxId,
  551. &dwNumValues,
  552. &pIISSrcObjects
  553. );
  554. }
  555. else
  556. {
  557. hr = _pPropertyCache->getproperty(
  558. bstrName,
  559. &dwSyntaxId,
  560. &dwNumValues,
  561. &pIISSrcObjects
  562. );
  563. }
  564. BAIL_ON_FAILURE(hr);
  565. //
  566. // reset it to its syntax id if BITMASK type
  567. //
  568. pIISSrcObjects->IISType = dwSyntax;
  569. //
  570. // translate the IIS objects to variants
  571. //
  572. hr = IISTypeToVarTypeCopyConstruct(
  573. _pSchema,
  574. bstrName,
  575. pIISSrcObjects,
  576. dwNumValues,
  577. pvProp,
  578. TRUE
  579. );
  580. BAIL_ON_FAILURE(hr);
  581. error:
  582. if (pIISSrcObjects) {
  583. IISTypeFreeIISObjects(
  584. pIISSrcObjects,
  585. dwNumValues
  586. );
  587. }
  588. RRETURN(hr);
  589. }
  590. STDMETHODIMP
  591. CIISTree::Put(
  592. THIS_ BSTR bstrName,
  593. VARIANT vProp
  594. )
  595. {
  596. HRESULT hr = S_OK;
  597. DWORD dwSyntaxId = 0;
  598. DWORD dwIndex = 0;
  599. LPIISOBJECT pIISDestObjects = NULL;
  600. DWORD dwNumValues = 0;
  601. VARIANT * pVarArray = NULL;
  602. VARIANT * pvProp = NULL;
  603. WCHAR wchName[MAX_PATH];
  604. //
  605. // Issue: How do we handle multi-valued support
  606. //
  607. if ((V_VT(&vProp) & VT_VARIANT) && V_ISARRAY(&vProp)) {
  608. if(V_ISBYREF(&vProp)) {
  609. hr = ConvertByRefSafeArrayToVariantArray(
  610. vProp,
  611. &pVarArray,
  612. &dwNumValues
  613. );
  614. BAIL_ON_FAILURE(hr);
  615. pvProp = pVarArray;
  616. }
  617. else {
  618. hr = ConvertSafeArrayToVariantArray(
  619. vProp,
  620. &pVarArray,
  621. &dwNumValues
  622. );
  623. BAIL_ON_FAILURE(hr);
  624. pvProp = pVarArray;
  625. }
  626. }
  627. else {
  628. dwNumValues = 1;
  629. pvProp = &vProp;
  630. }
  631. //
  632. // Check if this is a legal property and it syntax ID
  633. //
  634. hr = _pSchema->LookupSyntaxID( bstrName, &dwSyntaxId);
  635. BAIL_ON_FAILURE(hr);
  636. //
  637. // check if the variant maps to the syntax of this property
  638. //
  639. hr = VarTypeToIISTypeCopyConstruct(
  640. dwSyntaxId,
  641. pvProp,
  642. dwNumValues,
  643. &pIISDestObjects,
  644. FALSE
  645. );
  646. BAIL_ON_FAILURE(hr);
  647. //
  648. // check if property is BITMASK type;
  649. // if BITMASK type, get corresponding DWORD flag property
  650. //
  651. if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) {
  652. VARIANT vGetProp;
  653. DWORD dwMask;
  654. DWORD dwFlagValue;
  655. hr = _pSchema->LookupBitMask(bstrName, &dwMask);
  656. BAIL_ON_FAILURE(hr);
  657. //
  658. // get its corresponding DWORD flag value
  659. //
  660. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  661. BAIL_ON_FAILURE(hr);
  662. VariantInit(&vGetProp);
  663. hr = Get(wchName, &vGetProp);
  664. BAIL_ON_FAILURE(hr);
  665. dwFlagValue = V_I4(&vGetProp);
  666. if (pIISDestObjects->IISValue.value_1.dwDWORD) {
  667. dwFlagValue |= dwMask;
  668. }
  669. else {
  670. dwFlagValue &= ~dwMask;
  671. }
  672. pIISDestObjects->IISValue.value_1.dwDWORD = dwFlagValue;
  673. pIISDestObjects->IISType = IIS_SYNTAX_ID_DWORD;
  674. bstrName = wchName;
  675. }
  676. if (dwSyntaxId == IIS_SYNTAX_ID_BINARY)
  677. {
  678. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  679. BAIL_ON_FAILURE(hr);
  680. bstrName = wchName;
  681. }
  682. //
  683. // Find this property in the cache
  684. //
  685. hr = _pPropertyCache->findproperty(
  686. bstrName,
  687. &dwIndex
  688. );
  689. //
  690. // If this property does not exist in the
  691. // cache, add this property into the cache.
  692. //
  693. if (FAILED(hr)) {
  694. hr = _pPropertyCache->addproperty(
  695. bstrName,
  696. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  697. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  698. dwNumValues,
  699. pIISDestObjects
  700. );
  701. //
  702. // If the operation fails for some reason
  703. // move on to the next property
  704. //
  705. BAIL_ON_FAILURE(hr);
  706. }
  707. //
  708. // Now update the property in the cache
  709. //
  710. hr = _pPropertyCache->putproperty(
  711. bstrName,
  712. CACHE_PROPERTY_MODIFIED,
  713. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  714. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  715. dwNumValues,
  716. pIISDestObjects
  717. );
  718. BAIL_ON_FAILURE(hr);
  719. error:
  720. if (pIISDestObjects) {
  721. IISTypeFreeIISObjects(
  722. pIISDestObjects,
  723. dwNumValues
  724. );
  725. }
  726. if (pVarArray) {
  727. DWORD i = 0;
  728. for (i = 0; i < dwNumValues; i++) {
  729. VariantClear(pVarArray + i);
  730. }
  731. FreeADsMem(pVarArray);
  732. }
  733. RRETURN(hr);
  734. }
  735. STDMETHODIMP
  736. CIISTree::PutEx(
  737. THIS_ long lnControlCode,
  738. BSTR bstrName,
  739. VARIANT vProp
  740. )
  741. {
  742. HRESULT hr = S_OK;
  743. DWORD dwSyntaxId = 0;
  744. DWORD dwIndex = 0;
  745. LPIISOBJECT pIISDestObjects = NULL;
  746. DWORD dwNumValues = 0;
  747. DWORD dwFlags = 0;
  748. VARIANT * pVarArray = NULL;
  749. VARIANT * pvProp = NULL;
  750. WCHAR wchName[MAX_PATH];
  751. switch (lnControlCode) {
  752. case ADS_PROPERTY_CLEAR:
  753. dwFlags = CACHE_PROPERTY_CLEARED;
  754. pIISDestObjects = NULL;
  755. dwNumValues = 0;
  756. break;
  757. case ADS_PROPERTY_UPDATE:
  758. dwFlags = CACHE_PROPERTY_MODIFIED;
  759. //
  760. // Now begin the rest of the processing
  761. //
  762. if ((V_VT(&vProp) & VT_VARIANT) && V_ISARRAY(&vProp)) {
  763. if (V_ISBYREF(&vProp)) {
  764. hr = ConvertByRefSafeArrayToVariantArray(
  765. vProp,
  766. &pVarArray,
  767. &dwNumValues
  768. );
  769. BAIL_ON_FAILURE(hr);
  770. }
  771. else {
  772. hr = ConvertSafeArrayToVariantArray(
  773. vProp,
  774. &pVarArray,
  775. &dwNumValues
  776. );
  777. BAIL_ON_FAILURE(hr);
  778. }
  779. pvProp = pVarArray;
  780. }else {
  781. hr = E_FAIL;
  782. BAIL_ON_FAILURE(hr);
  783. }
  784. //
  785. // check if the variant maps to the syntax of this property
  786. //
  787. hr = VarTypeToIISTypeCopyConstruct(
  788. dwSyntaxId,
  789. pvProp,
  790. dwNumValues,
  791. &pIISDestObjects,
  792. TRUE
  793. );
  794. BAIL_ON_FAILURE(hr);
  795. break;
  796. default:
  797. RRETURN(hr = E_ADS_BAD_PARAMETER);
  798. }
  799. //
  800. // check if property is BITMASK type;
  801. // if BITMASK type, get corresponding DWORD flag property
  802. //
  803. if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) {
  804. VARIANT vGetProp;
  805. DWORD dwMask;
  806. DWORD dwFlagValue;
  807. hr = _pSchema->LookupBitMask(bstrName, &dwMask);
  808. BAIL_ON_FAILURE(hr);
  809. //
  810. // get its corresponding DWORD flag value
  811. //
  812. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  813. BAIL_ON_FAILURE(hr);
  814. VariantInit(&vGetProp);
  815. hr = Get(wchName, &vGetProp);
  816. BAIL_ON_FAILURE(hr);
  817. dwFlagValue = V_I4(&vGetProp);
  818. if (pIISDestObjects->IISValue.value_1.dwDWORD) {
  819. dwFlagValue |= dwMask;
  820. }
  821. else {
  822. dwFlagValue &= ~dwMask;
  823. }
  824. pIISDestObjects->IISValue.value_1.dwDWORD = dwFlagValue;
  825. pIISDestObjects->IISType = IIS_SYNTAX_ID_DWORD;
  826. bstrName = wchName;
  827. }
  828. if (dwSyntaxId == IIS_SYNTAX_ID_BINARY)
  829. {
  830. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  831. BAIL_ON_FAILURE(hr);
  832. bstrName = wchName;
  833. }
  834. //
  835. // Find this property in the cache
  836. //
  837. hr = _pPropertyCache->findproperty(
  838. bstrName,
  839. &dwIndex
  840. );
  841. //
  842. // If this property does not exist in the
  843. // cache, add this property into the cache.
  844. //
  845. if (FAILED(hr)) {
  846. hr = _pPropertyCache->addproperty(
  847. bstrName,
  848. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  849. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  850. dwNumValues,
  851. pIISDestObjects
  852. );
  853. //
  854. // If the operation fails for some reason
  855. // move on to the next property
  856. //
  857. BAIL_ON_FAILURE(hr);
  858. }
  859. //
  860. // Now update the property in the cache
  861. //
  862. hr = _pPropertyCache->putproperty(
  863. bstrName,
  864. dwFlags,
  865. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  866. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  867. dwNumValues,
  868. pIISDestObjects
  869. );
  870. BAIL_ON_FAILURE(hr);
  871. error:
  872. if (pIISDestObjects) {
  873. IISTypeFreeIISObjects(
  874. pIISDestObjects,
  875. dwNumValues
  876. );
  877. }
  878. if (pVarArray) {
  879. DWORD i = 0;
  880. for (i = 0; i < dwNumValues; i++) {
  881. VariantClear(pVarArray + i);
  882. }
  883. FreeADsMem(pVarArray);
  884. }
  885. RRETURN(hr);
  886. }