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.

2415 lines
53 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: cdomain.cxx
  7. //
  8. // Contents: Microsoft ADs NDS Provider Generic Object
  9. //
  10. //
  11. // History: 01-30-95 krishnag Created.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "nds.hxx"
  15. #pragma hdrstop
  16. // Class CNDSGenObject
  17. DEFINE_IDispatch_Implementation(CNDSGenObject)
  18. DEFINE_IADs_Implementation(CNDSGenObject)
  19. CNDSGenObject::CNDSGenObject():
  20. _pPropertyCache(NULL)
  21. {
  22. _pOuterUnknown = NULL;
  23. _fIsAggregated = NULL;
  24. VariantInit(&_vFilter);
  25. InitSearchPrefs();
  26. ENLIST_TRACKING(CNDSGenObject);
  27. }
  28. HRESULT
  29. CNDSGenObject::CreateGenericObject(
  30. BSTR bstrADsPath,
  31. BSTR ClassName,
  32. CCredentials& Credentials,
  33. DWORD dwObjectState,
  34. REFIID riid,
  35. void **ppvObj
  36. )
  37. {
  38. HRESULT hr = S_OK;
  39. WCHAR szADsParent[MAX_PATH];
  40. WCHAR szCommonName[MAX_PATH];
  41. memset(szADsParent, 0, sizeof(szADsParent));
  42. memset(szCommonName, 0, sizeof(szCommonName));
  43. //
  44. // Determine the parent and rdn name
  45. //
  46. hr = BuildADsParentPath(
  47. bstrADsPath,
  48. szADsParent,
  49. szCommonName
  50. );
  51. //
  52. // call the helper function
  53. //
  54. hr = CNDSGenObject::CreateGenericObject(
  55. szADsParent,
  56. szCommonName,
  57. ClassName,
  58. Credentials,
  59. dwObjectState,
  60. riid,
  61. ppvObj
  62. );
  63. RRETURN_EXP_IF_ERR(hr);
  64. }
  65. HRESULT
  66. CNDSGenObject::CreateGenericObject(
  67. BSTR Parent,
  68. BSTR CommonName,
  69. BSTR ClassName,
  70. CCredentials& Credentials,
  71. DWORD dwObjectState,
  72. REFIID riid,
  73. void **ppvObj
  74. )
  75. {
  76. CNDSGenObject FAR * pGenObject = NULL;
  77. HRESULT hr = S_OK;
  78. hr = AllocateGenObject(Credentials, &pGenObject);
  79. BAIL_ON_FAILURE(hr);
  80. hr = pGenObject->InitializeCoreObject(
  81. Parent,
  82. CommonName,
  83. ClassName,
  84. L"",
  85. CLSID_NDSGenObject,
  86. dwObjectState
  87. );
  88. BAIL_ON_FAILURE(hr);
  89. hr = pGenObject->QueryInterface(riid, ppvObj);
  90. BAIL_ON_FAILURE(hr);
  91. pGenObject->Release();
  92. RRETURN(hr);
  93. error:
  94. delete pGenObject;
  95. RRETURN(hr);
  96. }
  97. CNDSGenObject::~CNDSGenObject( )
  98. {
  99. VariantClear(&_vFilter);
  100. delete _pDispMgr;
  101. delete _pPropertyCache;
  102. }
  103. STDMETHODIMP
  104. CNDSGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  105. {
  106. if (ppv == NULL) {
  107. RRETURN(E_POINTER);
  108. }
  109. if (IsEqualIID(iid, IID_IUnknown))
  110. {
  111. *ppv = (IADs FAR *) this;
  112. }
  113. else if (IsEqualIID(iid, IID_IADsContainer))
  114. {
  115. *ppv = (IADsContainer FAR *) this;
  116. }
  117. else if (IsEqualIID(iid, IID_IADs))
  118. {
  119. *ppv = (IADs FAR *) this;
  120. }
  121. else if (IsEqualIID(iid, IID_IDispatch))
  122. {
  123. *ppv = (IADs FAR *) this;
  124. }
  125. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  126. {
  127. *ppv = (ISupportErrorInfo FAR *) this;
  128. }
  129. else if (IsEqualIID(iid, IID_IDirectoryObject))
  130. {
  131. *ppv = (IDirectoryObject FAR *) this;
  132. }
  133. else if (IsEqualIID(iid, IID_IDirectorySearch))
  134. {
  135. *ppv = (IDirectorySearch FAR *) this;
  136. }
  137. else if (IsEqualIID(iid, IID_IDirectorySchemaMgmt))
  138. {
  139. *ppv = (IDirectorySchemaMgmt FAR *) this;
  140. }
  141. else if (IsEqualIID(iid, IID_IADsPropertyList))
  142. {
  143. *ppv = (IADsPropertyList FAR *) this;
  144. }
  145. else
  146. {
  147. *ppv = NULL;
  148. return E_NOINTERFACE;
  149. }
  150. AddRef();
  151. return NOERROR;
  152. }
  153. /* ISupportErrorInfo method */
  154. HRESULT
  155. CNDSGenObject::InterfaceSupportsErrorInfo(
  156. THIS_ REFIID riid
  157. )
  158. {
  159. if (IsEqualIID(riid, IID_IADs) ||
  160. IsEqualIID(riid, IID_IADsPropertyList) ||
  161. #if 0
  162. IsEqualIID(riid, IID_IDirectoryObject) ||
  163. IsEqualIID(riid, IID_IDirectorySearch) ||
  164. IsEqualIID(riid, IID_IDirectorySchemaMgmt) ||
  165. #endif
  166. IsEqualIID(riid, IID_IADsContainer)) {
  167. RRETURN(S_OK);
  168. } else {
  169. RRETURN(S_FALSE);
  170. }
  171. }
  172. HRESULT
  173. CNDSGenObject::SetInfo()
  174. {
  175. DWORD dwStatus = 0L;
  176. WCHAR szNDSPathName[MAX_PATH];
  177. HANDLE hOperationData = NULL;
  178. HANDLE hObject = NULL;
  179. HRESULT hr = S_OK;
  180. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  181. hr = NDSCreateObject();
  182. BAIL_ON_FAILURE(hr);
  183. //
  184. // If the create succeded, set the object type to bound
  185. //
  186. SetObjectState(ADS_OBJECT_BOUND);
  187. }else {
  188. hr = NDSSetObject();
  189. BAIL_ON_FAILURE(hr);
  190. }
  191. error:
  192. RRETURN_EXP_IF_ERR(hr);
  193. }
  194. HRESULT
  195. CNDSGenObject::NDSSetObject()
  196. {
  197. DWORD dwStatus = 0L;
  198. LPWSTR pszNDSPathName = NULL;
  199. HANDLE hOperationData = NULL;
  200. HANDLE hObject = NULL;
  201. HRESULT hr = S_OK;
  202. hr = BuildNDSPathFromADsPath(
  203. _ADsPath,
  204. &pszNDSPathName
  205. );
  206. BAIL_ON_FAILURE(hr);
  207. dwStatus = ADsNwNdsOpenObject(
  208. pszNDSPathName,
  209. _Credentials,
  210. &hObject,
  211. NULL,
  212. NULL,
  213. NULL,
  214. NULL
  215. );
  216. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  217. dwStatus = NwNdsCreateBuffer(
  218. NDS_OBJECT_MODIFY,
  219. &hOperationData
  220. );
  221. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  222. hr = _pPropertyCache->NDSMarshallProperties(
  223. hOperationData
  224. );
  225. BAIL_ON_FAILURE(hr);
  226. dwStatus = NwNdsModifyObject(
  227. hObject,
  228. hOperationData
  229. );
  230. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  231. error:
  232. if (pszNDSPathName) {
  233. FreeADsStr(pszNDSPathName);
  234. }
  235. if (hOperationData) {
  236. dwStatus = NwNdsFreeBuffer(hOperationData);
  237. }
  238. if (hObject) {
  239. dwStatus = NwNdsCloseObject(hObject);
  240. }
  241. RRETURN_EXP_IF_ERR(hr);
  242. }
  243. HRESULT
  244. CNDSGenObject::NDSCreateObject()
  245. {
  246. DWORD dwStatus = 0L;
  247. LPWSTR pszNDSParentName = NULL;
  248. HANDLE hOperationData = NULL;
  249. HANDLE hObject = NULL;
  250. HRESULT hr = S_OK;
  251. hr = BuildNDSPathFromADsPath(
  252. _Parent,
  253. &pszNDSParentName
  254. );
  255. BAIL_ON_FAILURE(hr);
  256. dwStatus = ADsNwNdsOpenObject(
  257. pszNDSParentName,
  258. _Credentials,
  259. &hObject,
  260. NULL,
  261. NULL,
  262. NULL,
  263. NULL
  264. );
  265. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  266. dwStatus = NwNdsCreateBuffer(
  267. NDS_OBJECT_ADD,
  268. &hOperationData
  269. );
  270. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  271. hr = _pPropertyCache->NDSMarshallProperties(
  272. hOperationData
  273. );
  274. BAIL_ON_FAILURE(hr);
  275. dwStatus = NwNdsAddObject(
  276. hObject,
  277. _Name,
  278. hOperationData
  279. );
  280. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  281. error:
  282. if (hOperationData) {
  283. dwStatus = NwNdsFreeBuffer(hOperationData);
  284. }
  285. if (hObject) {
  286. dwStatus = NwNdsCloseObject(hObject);
  287. }
  288. if (pszNDSParentName) {
  289. FreeADsStr(pszNDSParentName);
  290. }
  291. RRETURN_EXP_IF_ERR(hr);
  292. }
  293. HRESULT
  294. CNDSGenObject::GetInfo()
  295. {
  296. _pPropertyCache->flushpropcache();
  297. RRETURN(GetInfo(TRUE));
  298. }
  299. HRESULT
  300. CNDSGenObject::GetInfo(
  301. BOOL fExplicit
  302. )
  303. {
  304. DWORD dwStatus = 0L;
  305. HANDLE hObject = NULL;
  306. HANDLE hOperationData = NULL;
  307. HRESULT hr = S_OK;
  308. LPWSTR pszNDSPathName = NULL;
  309. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  310. hr = E_ADS_OBJECT_UNBOUND;
  311. BAIL_ON_FAILURE(hr);
  312. }
  313. hr = BuildNDSPathFromADsPath(
  314. _ADsPath,
  315. &pszNDSPathName
  316. );
  317. BAIL_ON_FAILURE(hr);
  318. dwStatus = ADsNwNdsOpenObject(
  319. pszNDSPathName,
  320. _Credentials,
  321. &hObject,
  322. NULL,
  323. NULL,
  324. NULL,
  325. NULL
  326. );
  327. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  328. hOperationData = NULL;
  329. dwStatus = NwNdsReadObject(
  330. hObject,
  331. NDS_INFO_ATTR_NAMES_VALUES,
  332. &hOperationData
  333. );
  334. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  335. hr = _pPropertyCache->NDSUnMarshallProperties(
  336. hOperationData,
  337. fExplicit
  338. );
  339. BAIL_ON_FAILURE(hr);
  340. error:
  341. if (hOperationData) {
  342. dwStatus = NwNdsFreeBuffer(hOperationData);
  343. }
  344. if (hObject) {
  345. dwStatus = NwNdsCloseObject(hObject);
  346. }
  347. if (pszNDSPathName) {
  348. FreeADsStr(pszNDSPathName);
  349. }
  350. if (_pPropertyCache) {
  351. Reset();
  352. }
  353. RRETURN_EXP_IF_ERR(hr);
  354. }
  355. STDMETHODIMP
  356. CNDSGenObject::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  357. {
  358. HRESULT hr = S_OK;
  359. DWORD dwStatus = 0L;
  360. HANDLE hObject = NULL;
  361. VARIANT *vVarArray = NULL;
  362. DWORD dwNumVariants = 0;
  363. HANDLE hOperationData = NULL;
  364. LPWSTR pszNDSPathName = NULL;
  365. DWORD i;
  366. UNREFERENCED_PARAMETER(lnReserved);
  367. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  368. hr = E_ADS_OBJECT_UNBOUND;
  369. BAIL_ON_FAILURE(hr);
  370. }
  371. hr = BuildNDSPathFromADsPath(_ADsPath, &pszNDSPathName);
  372. BAIL_ON_FAILURE(hr);
  373. hr = ConvertSafeArrayToVariantArray(
  374. vProperties,
  375. &vVarArray,
  376. &dwNumVariants
  377. );
  378. BAIL_ON_FAILURE(hr);
  379. dwStatus = ADsNwNdsOpenObject(
  380. pszNDSPathName, _Credentials, &hObject, NULL, NULL, NULL, NULL);
  381. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  382. hOperationData = NULL;
  383. dwStatus = NwNdsCreateBuffer(NDS_OBJECT_READ, &hOperationData);
  384. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  385. //
  386. // Fill up the buffer with our search parameters.
  387. //
  388. for (i = 0; i < dwNumVariants; i++)
  389. {
  390. if (!(V_VT(vVarArray + i) == VT_BSTR))
  391. BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
  392. dwStatus = NwNdsPutInBuffer(
  393. V_BSTR(vVarArray + i), 0, NULL, 0, 0, hOperationData);
  394. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  395. }
  396. dwStatus = NwNdsReadObject(
  397. hObject,
  398. NDS_INFO_ATTR_NAMES_VALUES,
  399. &hOperationData
  400. );
  401. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  402. //
  403. // The TRUE is "fExplicit" -- we want to make sure that any
  404. // properties we get back from the server get updated in the
  405. // property cache.
  406. //
  407. hr = _pPropertyCache->NDSUnMarshallProperties(hOperationData, TRUE);
  408. BAIL_ON_FAILURE(hr);
  409. error:
  410. if (hOperationData)
  411. dwStatus = NwNdsFreeBuffer(hOperationData);
  412. if (vVarArray){
  413. // Need to free each variants content and then the arrays.
  414. for (i = 0; i < dwNumVariants; i++) {
  415. VariantClear(vVarArray + i);
  416. }
  417. FreeADsMem(vVarArray);
  418. }
  419. if (hObject)
  420. dwStatus = NwNdsCloseObject(hObject);
  421. if (pszNDSPathName)
  422. FreeADsStr(pszNDSPathName);
  423. RRETURN_EXP_IF_ERR(hr);
  424. }
  425. /* IADsContainer methods */
  426. STDMETHODIMP
  427. CNDSGenObject::get_Count(long FAR* retval)
  428. {
  429. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  430. }
  431. STDMETHODIMP
  432. CNDSGenObject::get_Filter(THIS_ VARIANT FAR* pVar)
  433. {
  434. HRESULT hr;
  435. VariantInit(pVar);
  436. hr = VariantCopy(pVar, &_vFilter);
  437. RRETURN_EXP_IF_ERR(hr);
  438. }
  439. STDMETHODIMP
  440. CNDSGenObject::put_Filter(THIS_ VARIANT Var)
  441. {
  442. HRESULT hr;
  443. VariantClear(&_vFilter);
  444. hr = VariantCopy(&_vFilter, &Var);
  445. RRETURN_EXP_IF_ERR(hr);
  446. }
  447. STDMETHODIMP
  448. CNDSGenObject::put_Hints(THIS_ VARIANT Var)
  449. {
  450. RRETURN_EXP_IF_ERR( E_NOTIMPL);
  451. }
  452. STDMETHODIMP
  453. CNDSGenObject::get_Hints(THIS_ VARIANT FAR* pVar)
  454. {
  455. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  456. }
  457. STDMETHODIMP
  458. CNDSGenObject::GetObject(
  459. BSTR ClassName,
  460. BSTR RelativeName,
  461. IDispatch * FAR* ppObject
  462. )
  463. {
  464. HRESULT hr = S_OK;
  465. hr = ::RelativeGetObject(
  466. _ADsPath,
  467. ClassName,
  468. RelativeName,
  469. _Credentials,
  470. ppObject,
  471. FALSE
  472. );
  473. RRETURN_EXP_IF_ERR(hr);
  474. }
  475. STDMETHODIMP
  476. CNDSGenObject::get__NewEnum(
  477. THIS_ IUnknown * FAR* retval
  478. )
  479. {
  480. HRESULT hr;
  481. IUnknown FAR* punkEnum=NULL;
  482. IEnumVARIANT * penum = NULL;
  483. *retval = NULL;
  484. hr = CNDSGenObjectEnum::Create(
  485. (CNDSGenObjectEnum **)&penum,
  486. _ADsPath,
  487. _vFilter,
  488. _Credentials
  489. );
  490. BAIL_ON_FAILURE(hr);
  491. hr = penum->QueryInterface(
  492. IID_IUnknown,
  493. (VOID FAR* FAR*)retval
  494. );
  495. BAIL_ON_FAILURE(hr);
  496. if (penum) {
  497. penum->Release();
  498. }
  499. RRETURN(NOERROR);
  500. error:
  501. if (penum) {
  502. delete penum;
  503. }
  504. RRETURN_EXP_IF_ERR(hr);
  505. }
  506. STDMETHODIMP
  507. CNDSGenObject::Create(
  508. THIS_ BSTR ClassName,
  509. BSTR RelativeName,
  510. IDispatch * FAR* ppObject
  511. )
  512. {
  513. HRESULT hr = S_OK;
  514. IADs * pADs = NULL;
  515. VARIANT var;
  516. WCHAR szNDSTreeName[MAX_PATH];
  517. DWORD dwSyntaxId = 0;
  518. VARIANT vNewValue;
  519. //
  520. // Get the TreeName for this object
  521. //
  522. hr = BuildNDSTreeNameFromADsPath(
  523. _ADsPath,
  524. szNDSTreeName
  525. );
  526. BAIL_ON_FAILURE(hr);
  527. //
  528. // Validate if this class really exists in the schema
  529. // and validate that this object can be created in this
  530. // container
  531. //
  532. hr = CNDSGenObject::CreateGenericObject(
  533. _ADsPath,
  534. RelativeName,
  535. ClassName,
  536. _Credentials,
  537. ADS_OBJECT_UNBOUND,
  538. IID_IADs,
  539. (void **)&pADs
  540. );
  541. BAIL_ON_FAILURE(hr);
  542. VariantInit(&vNewValue);
  543. V_BSTR(&vNewValue) = ClassName;
  544. V_VT(&vNewValue) = VT_BSTR;
  545. hr = pADs->Put(L"Object Class", vNewValue);
  546. BAIL_ON_FAILURE(hr);
  547. //
  548. // InstantiateDerivedObject should addref this pointer for us.
  549. //
  550. hr = InstantiateDerivedObject(
  551. pADs,
  552. _Credentials,
  553. IID_IDispatch,
  554. (void **)ppObject
  555. );
  556. if (FAILED(hr)) {
  557. hr = pADs->QueryInterface(
  558. IID_IDispatch,
  559. (void **)ppObject
  560. );
  561. BAIL_ON_FAILURE(hr);
  562. }
  563. error:
  564. //
  565. // Free the intermediate pADs pointer.
  566. //
  567. if (pADs) {
  568. pADs->Release();
  569. }
  570. RRETURN_EXP_IF_ERR(hr);
  571. }
  572. STDMETHODIMP
  573. CNDSGenObject::Delete(
  574. THIS_ BSTR bstrClassName,
  575. BSTR bstrRelativeName
  576. )
  577. {
  578. LPWSTR pszNDSPathName = NULL;
  579. LPWSTR pszNDSChildPath = NULL;
  580. WCHAR szChildObjectClassName[MAX_PATH];
  581. HRESULT hr = S_OK;
  582. DWORD dwStatus = 0;
  583. HANDLE hChildObject = NULL;
  584. HANDLE hParentObject = NULL;
  585. BSTR bstrChildPath = NULL;
  586. hr = BuildADsPath(
  587. _ADsPath,
  588. bstrRelativeName,
  589. &bstrChildPath
  590. );
  591. BAIL_ON_FAILURE(hr);
  592. hr = BuildNDSPathFromADsPath(
  593. bstrChildPath,
  594. &pszNDSChildPath
  595. );
  596. BAIL_ON_FAILURE(hr);
  597. dwStatus = ADsNwNdsOpenObject(
  598. pszNDSChildPath,
  599. _Credentials,
  600. &hChildObject,
  601. NULL,
  602. szChildObjectClassName,
  603. NULL,
  604. NULL
  605. );
  606. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  607. if (hChildObject) {
  608. NwNdsCloseObject(hChildObject);
  609. }
  610. if (_wcsicmp(szChildObjectClassName, bstrClassName)) {
  611. hr = E_ADS_BAD_PARAMETER;
  612. BAIL_ON_FAILURE(hr);
  613. }
  614. //
  615. // We now are sure we're deleting an object of the
  616. // specified class
  617. //
  618. hr = BuildNDSPathFromADsPath(
  619. _ADsPath,
  620. &pszNDSPathName
  621. );
  622. BAIL_ON_FAILURE(hr);
  623. dwStatus = ADsNwNdsOpenObject(
  624. pszNDSPathName,
  625. _Credentials,
  626. &hParentObject,
  627. NULL,
  628. NULL,
  629. NULL,
  630. NULL
  631. );
  632. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  633. dwStatus = NwNdsRemoveObject(
  634. hParentObject,
  635. bstrRelativeName
  636. );
  637. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  638. error:
  639. if (bstrChildPath) {
  640. SysFreeString(bstrChildPath);
  641. }
  642. if (pszNDSPathName) {
  643. FreeADsStr(pszNDSPathName);
  644. }
  645. if (pszNDSChildPath) {
  646. FreeADsStr(pszNDSChildPath);
  647. }
  648. if (hParentObject) {
  649. NwNdsCloseObject(
  650. hParentObject
  651. );
  652. }
  653. RRETURN_EXP_IF_ERR(hr);
  654. }
  655. STDMETHODIMP
  656. CNDSGenObject::CopyHere(
  657. THIS_ BSTR SourceName,
  658. BSTR NewName,
  659. IDispatch * FAR* ppObject
  660. )
  661. {
  662. HRESULT hr = S_OK;
  663. IUnknown *pUnk = NULL;
  664. hr = CopyObject(
  665. SourceName,
  666. _ADsPath,
  667. NewName,
  668. _Credentials,
  669. (void**)&pUnk
  670. );
  671. BAIL_ON_FAILURE(hr);
  672. hr = pUnk->QueryInterface(IID_IDispatch, (void **)ppObject);
  673. error:
  674. RRETURN_EXP_IF_ERR(hr);
  675. }
  676. STDMETHODIMP
  677. CNDSGenObject::MoveHere(
  678. THIS_ BSTR SourceName,
  679. BSTR NewName,
  680. IDispatch * FAR* ppObject
  681. )
  682. {
  683. LPWSTR pszNDSDestPathName = NULL; // Target Parent DN (NDS format)
  684. LPWSTR pszNDSSrcParent = NULL; // Source Parent DN (NDS format)
  685. WCHAR szSrcParent[MAX_PATH]; // Source Parent DN (ADSI format)
  686. WCHAR szCN[MAX_PATH]; // Source RDN
  687. LPWSTR pszRelativeName = NULL; // Target RDN
  688. WCHAR szObjectClass[MAX_PATH]; // Object class of object being moved/renamed
  689. LPWSTR pszNDSSrcPathName = NULL; // Source DN for move (NDS format)
  690. BSTR pszADsSrcPathName = NULL; // Source DN for move (ADSI format)
  691. HRESULT hr = S_OK;
  692. DWORD dwStatus = 0;
  693. HANDLE hSrcObject = NULL;
  694. HANDLE hParentObject = NULL;
  695. IADs *pADs = NULL;
  696. hr = BuildNDSPathFromADsPath(
  697. _ADsPath,
  698. &pszNDSDestPathName
  699. );
  700. BAIL_ON_FAILURE(hr);
  701. hr = BuildADsParentPath(
  702. SourceName,
  703. szSrcParent,
  704. szCN
  705. );
  706. hr = BuildNDSPathFromADsPath(
  707. szSrcParent,
  708. &pszNDSSrcParent
  709. );
  710. BAIL_ON_FAILURE(hr);
  711. if (NewName)
  712. pszRelativeName = NewName;
  713. else
  714. pszRelativeName = szCN;
  715. BuildADsPath(szSrcParent, pszRelativeName, &pszADsSrcPathName);
  716. hr = BuildNDSPathFromADsPath(
  717. pszADsSrcPathName,
  718. &pszNDSSrcPathName
  719. );
  720. BAIL_ON_FAILURE(hr);
  721. //
  722. // Get the value of the new and old name
  723. //
  724. if ( NewName != NULL) {
  725. //
  726. // Get the value from the NewName if user supplies 'CN=xxx'
  727. //
  728. LPWSTR pszCN = NewName;
  729. while (*pszCN != '\0' && *pszCN != '=') {
  730. pszCN++;
  731. }
  732. if (*pszCN != '\0') {
  733. NewName = ++pszCN;
  734. }
  735. //
  736. // Getting the value from the CN since it is always in the format 'CN=xxx'
  737. //
  738. LPWSTR pszRDN = szCN;
  739. while (*pszRDN != '\0' && *pszRDN != '=') {
  740. pszRDN++;
  741. }
  742. if (*pszRDN == '\0') {
  743. hr = E_FAIL;
  744. BAIL_ON_FAILURE(hr);
  745. }
  746. else {
  747. pszRDN++;
  748. }
  749. //
  750. // Only carry out rename if the names are different
  751. //
  752. if (wcscmp(pszRDN,NewName) != 0) {
  753. dwStatus = ADsNwNdsOpenObject(
  754. pszNDSSrcParent,
  755. _Credentials,
  756. &hParentObject,
  757. NULL,
  758. NULL,
  759. NULL,
  760. NULL
  761. );
  762. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  763. dwStatus = NwNdsRenameObject(
  764. hParentObject,
  765. pszRDN,
  766. NewName,
  767. FALSE);
  768. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  769. }
  770. }
  771. //
  772. // Only carry out move if the two parents are different
  773. //
  774. dwStatus = ADsNwNdsOpenObject(
  775. pszNDSSrcPathName,
  776. _Credentials,
  777. &hSrcObject,
  778. NULL,
  779. szObjectClass,
  780. NULL,
  781. NULL
  782. );
  783. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  784. if (wcscmp(pszNDSDestPathName, pszNDSSrcParent) != 0) {
  785. dwStatus = NwNdsMoveObject(
  786. hSrcObject,
  787. pszNDSDestPathName
  788. );
  789. CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
  790. }
  791. if (ppObject) {
  792. hr = CNDSGenObject::CreateGenericObject(
  793. _ADsPath,
  794. pszRelativeName,
  795. szObjectClass,
  796. _Credentials,
  797. ADS_OBJECT_BOUND,
  798. IID_IADs,
  799. (void **)&pADs
  800. );
  801. BAIL_ON_FAILURE(hr);
  802. //
  803. // InstantiateDerivedObject should add-ref this pointer for us.
  804. //
  805. hr = InstantiateDerivedObject(
  806. pADs,
  807. _Credentials,
  808. IID_IDispatch,
  809. (void**)ppObject
  810. );
  811. if (FAILED(hr)) {
  812. hr = pADs->QueryInterface(
  813. IID_IDispatch,
  814. (void**)ppObject
  815. );
  816. BAIL_ON_FAILURE(hr);
  817. }
  818. }
  819. error:
  820. if (hSrcObject) {
  821. NwNdsCloseObject(hSrcObject);
  822. }
  823. if (hParentObject) {
  824. NwNdsCloseObject(hParentObject);
  825. }
  826. if (pszNDSSrcParent) {
  827. FreeADsMem(pszNDSSrcParent);
  828. }
  829. if (pszNDSDestPathName) {
  830. FreeADsMem(pszNDSDestPathName);
  831. }
  832. if (pszNDSSrcPathName) {
  833. FreeADsMem(pszNDSSrcPathName);
  834. }
  835. if (pszADsSrcPathName) {
  836. ADsFreeString(pszADsSrcPathName);
  837. }
  838. if (pADs) {
  839. pADs->Release();
  840. }
  841. RRETURN_EXP_IF_ERR(hr);
  842. }
  843. HRESULT
  844. CNDSGenObject::AllocateGenObject(
  845. CCredentials& Credentials,
  846. CNDSGenObject ** ppGenObject
  847. )
  848. {
  849. CNDSGenObject FAR * pGenObject = NULL;
  850. CDispatchMgr FAR * pDispMgr = NULL;
  851. CPropertyCache FAR * pPropertyCache = NULL;
  852. HRESULT hr = S_OK;
  853. pGenObject = new CNDSGenObject();
  854. if (pGenObject == NULL) {
  855. hr = E_OUTOFMEMORY;
  856. }
  857. BAIL_ON_FAILURE(hr);
  858. pDispMgr = new CDispatchMgr;
  859. if (pDispMgr == NULL) {
  860. hr = E_OUTOFMEMORY;
  861. }
  862. BAIL_ON_FAILURE(hr);
  863. hr = LoadTypeInfoEntry(pDispMgr,
  864. LIBID_ADs,
  865. IID_IADs,
  866. (IADs *)pGenObject,
  867. DISPID_REGULAR
  868. );
  869. BAIL_ON_FAILURE(hr);
  870. hr = LoadTypeInfoEntry(pDispMgr,
  871. LIBID_ADs,
  872. IID_IADsContainer,
  873. (IADsContainer *)pGenObject,
  874. DISPID_NEWENUM
  875. );
  876. BAIL_ON_FAILURE(hr);
  877. hr = LoadTypeInfoEntry(pDispMgr,
  878. LIBID_ADs,
  879. IID_IADsPropertyList,
  880. (IADsPropertyList *)pGenObject,
  881. DISPID_VALUE
  882. );
  883. BAIL_ON_FAILURE(hr);
  884. hr = CPropertyCache::createpropertycache(
  885. (CCoreADsObject FAR *)pGenObject,
  886. &pPropertyCache
  887. );
  888. BAIL_ON_FAILURE(hr);
  889. pGenObject->_Credentials = Credentials;
  890. pGenObject->_pPropertyCache = pPropertyCache;
  891. pGenObject->_pDispMgr = pDispMgr;
  892. *ppGenObject = pGenObject;
  893. RRETURN(hr);
  894. error:
  895. delete pGenObject;
  896. delete pDispMgr;
  897. RRETURN(hr);
  898. }
  899. STDMETHODIMP
  900. CNDSGenObject::Get(
  901. THIS_ BSTR bstrName,
  902. VARIANT FAR* pvProp
  903. )
  904. {
  905. HRESULT hr = S_OK;
  906. DWORD dwSyntaxId;
  907. DWORD dwNumValues;
  908. LPNDSOBJECT pNdsSrcObjects = NULL;
  909. //
  910. // retrieve data object from cache; if one exists
  911. //
  912. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  913. hr = _pPropertyCache->unboundgetproperty(
  914. bstrName,
  915. &dwSyntaxId,
  916. &dwNumValues,
  917. &pNdsSrcObjects
  918. );
  919. BAIL_ON_FAILURE(hr);
  920. }else {
  921. hr = _pPropertyCache->getproperty(
  922. bstrName,
  923. &dwSyntaxId,
  924. &dwNumValues,
  925. &pNdsSrcObjects
  926. );
  927. BAIL_ON_FAILURE(hr);
  928. }
  929. //
  930. // translate the Nds objects to variants
  931. //
  932. hr = NdsTypeToVarTypeCopyConstruct(
  933. pNdsSrcObjects,
  934. dwNumValues,
  935. pvProp,
  936. FALSE
  937. );
  938. BAIL_ON_FAILURE(hr);
  939. error:
  940. if (pNdsSrcObjects) {
  941. NdsTypeFreeNdsObjects(
  942. pNdsSrcObjects,
  943. dwNumValues
  944. );
  945. }
  946. RRETURN_EXP_IF_ERR(hr);
  947. }
  948. STDMETHODIMP
  949. CNDSGenObject::Put(
  950. THIS_ BSTR bstrName,
  951. VARIANT vProp
  952. )
  953. {
  954. HRESULT hr = S_OK;
  955. DWORD dwSyntaxId = 0;
  956. DWORD dwIndex = 0;
  957. LPNDSOBJECT pNdsDestObjects = NULL;
  958. WCHAR szNDSTreeName[MAX_PATH];
  959. DWORD dwNumValues = 0, dwNumVariants = 0;
  960. VARIANT * pVarArray = NULL;
  961. VARIANT * pvProp = NULL;
  962. VARIANT vDefProp;
  963. VariantInit(&vDefProp);
  964. //
  965. // Issue: How do we handle multi-valued support
  966. //
  967. //
  968. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  969. // We should dereference a VT_BYREF|VT_VARIANT once and see
  970. // what's inside.
  971. //
  972. pvProp = &vProp;
  973. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  974. pvProp = V_VARIANTREF(&vProp);
  975. }
  976. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  977. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  978. hr = ConvertByRefSafeArrayToVariantArray(
  979. *pvProp,
  980. &pVarArray,
  981. &dwNumValues
  982. );
  983. BAIL_ON_FAILURE(hr);
  984. pvProp = pVarArray;
  985. }else {
  986. //
  987. // If pvProp is a reference to a fundamental type,
  988. // we have to dereference it once.
  989. //
  990. if (V_ISBYREF(pvProp)) {
  991. hr = VariantCopyInd(&vDefProp, pvProp);
  992. BAIL_ON_FAILURE(hr);
  993. pvProp = &vDefProp;
  994. }
  995. dwNumValues = 1;
  996. }
  997. //
  998. // Save it in case dwNumValues changes below (as in the case of ACLs)
  999. //
  1000. dwNumVariants = dwNumValues;
  1001. //
  1002. // Get the TreeName for this object
  1003. //
  1004. hr = BuildNDSTreeNameFromADsPath(
  1005. _ADsPath,
  1006. szNDSTreeName
  1007. );
  1008. BAIL_ON_FAILURE(hr);
  1009. //
  1010. // check if this is a legal property for this object,
  1011. //
  1012. hr = ValidatePropertyinCache(
  1013. szNDSTreeName,
  1014. _ADsClass,
  1015. bstrName,
  1016. _Credentials,
  1017. &dwSyntaxId
  1018. );
  1019. BAIL_ON_FAILURE(hr);
  1020. //
  1021. // check if the variant maps to the syntax of this property
  1022. //
  1023. hr = VarTypeToNdsTypeCopyConstruct(
  1024. dwSyntaxId,
  1025. pvProp,
  1026. &dwNumValues,
  1027. &pNdsDestObjects
  1028. );
  1029. BAIL_ON_FAILURE(hr);
  1030. //
  1031. // Find this property in the cache
  1032. //
  1033. hr = _pPropertyCache->findproperty(
  1034. bstrName,
  1035. &dwIndex
  1036. );
  1037. //
  1038. // If this property does not exist in the
  1039. // cache, add this property into the cache.
  1040. //
  1041. if (FAILED(hr)) {
  1042. hr = _pPropertyCache->addproperty(
  1043. bstrName,
  1044. dwSyntaxId
  1045. );
  1046. //
  1047. // If the operation fails for some reason
  1048. // move on to the next property
  1049. //
  1050. BAIL_ON_FAILURE(hr);
  1051. }
  1052. //
  1053. // Now update the property in the cache
  1054. //
  1055. hr = _pPropertyCache->putproperty(
  1056. bstrName,
  1057. CACHE_PROPERTY_MODIFIED,
  1058. dwSyntaxId,
  1059. dwNumValues,
  1060. pNdsDestObjects
  1061. );
  1062. BAIL_ON_FAILURE(hr);
  1063. error:
  1064. VariantClear(&vDefProp);
  1065. if (pNdsDestObjects) {
  1066. NdsTypeFreeNdsObjects(
  1067. pNdsDestObjects,
  1068. dwNumValues
  1069. );
  1070. }
  1071. if (pVarArray) {
  1072. DWORD i = 0;
  1073. for (i = 0; i < dwNumVariants; i++) {
  1074. VariantClear(pVarArray + i);
  1075. }
  1076. FreeADsMem(pVarArray);
  1077. }
  1078. RRETURN_EXP_IF_ERR(hr);
  1079. }
  1080. STDMETHODIMP
  1081. CNDSGenObject::PutEx(
  1082. THIS_ long lnControlCode,
  1083. BSTR bstrName,
  1084. VARIANT vProp
  1085. )
  1086. {
  1087. HRESULT hr = S_OK;
  1088. DWORD dwSyntaxId = 0;
  1089. DWORD dwIndex = 0;
  1090. LPNDSOBJECT pNdsDestObjects = NULL;
  1091. WCHAR szNDSTreeName[MAX_PATH];
  1092. DWORD dwNumValues = 0, dwNumVariants = 0;
  1093. DWORD dwFlags = 0;
  1094. VARIANT * pVarArray = NULL;
  1095. VARIANT * pvProp = NULL;
  1096. //
  1097. // Get the TreeName for this object
  1098. //
  1099. hr = BuildNDSTreeNameFromADsPath(
  1100. _ADsPath,
  1101. szNDSTreeName
  1102. );
  1103. BAIL_ON_FAILURE(hr);
  1104. //
  1105. // check if this is a legal property for this object,
  1106. //
  1107. hr = ValidatePropertyinCache(
  1108. szNDSTreeName,
  1109. _ADsClass,
  1110. bstrName,
  1111. _Credentials,
  1112. &dwSyntaxId
  1113. );
  1114. BAIL_ON_FAILURE(hr);
  1115. switch (lnControlCode) {
  1116. case ADS_PROPERTY_CLEAR:
  1117. dwFlags = CACHE_PROPERTY_CLEARED;
  1118. pNdsDestObjects = NULL;
  1119. dwNumValues = 0;
  1120. break;
  1121. case ADS_PROPERTY_UPDATE:
  1122. case ADS_PROPERTY_APPEND:
  1123. case ADS_PROPERTY_DELETE:
  1124. if (lnControlCode == ADS_PROPERTY_UPDATE) {
  1125. dwFlags = CACHE_PROPERTY_MODIFIED;
  1126. }
  1127. else if (lnControlCode == ADS_PROPERTY_APPEND) {
  1128. dwFlags = CACHE_PROPERTY_APPENDED;
  1129. }
  1130. else {
  1131. dwFlags = CACHE_PROPERTY_DELETED;
  1132. }
  1133. //
  1134. // Now begin the rest of the processing
  1135. //
  1136. //
  1137. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1138. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1139. // what's inside.
  1140. //
  1141. pvProp = &vProp;
  1142. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1143. pvProp = V_VARIANTREF(&vProp);
  1144. }
  1145. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
  1146. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
  1147. hr = ConvertByRefSafeArrayToVariantArray(
  1148. *pvProp,
  1149. &pVarArray,
  1150. &dwNumValues
  1151. );
  1152. BAIL_ON_FAILURE(hr);
  1153. pvProp = pVarArray;
  1154. }else {
  1155. hr = E_FAIL;
  1156. BAIL_ON_FAILURE(hr);
  1157. }
  1158. //
  1159. // Save it in case dwNumValues changes below (as in the case of ACLs)
  1160. //
  1161. dwNumVariants = dwNumValues;
  1162. //
  1163. // check if the variant maps to the syntax of this property
  1164. //
  1165. hr = VarTypeToNdsTypeCopyConstruct(
  1166. dwSyntaxId,
  1167. pvProp,
  1168. &dwNumValues,
  1169. &pNdsDestObjects
  1170. );
  1171. BAIL_ON_FAILURE(hr);
  1172. break;
  1173. default:
  1174. RRETURN_EXP_IF_ERR(hr = E_ADS_BAD_PARAMETER);
  1175. }
  1176. //
  1177. // Find this property in the cache
  1178. //
  1179. hr = _pPropertyCache->findproperty(
  1180. bstrName,
  1181. &dwIndex
  1182. );
  1183. //
  1184. // If this property does not exist in the
  1185. // cache, add this property into the cache.
  1186. //
  1187. if (FAILED(hr)) {
  1188. hr = _pPropertyCache->addproperty(
  1189. bstrName,
  1190. dwSyntaxId
  1191. );
  1192. //
  1193. // If the operation fails for some reason
  1194. // move on to the next property
  1195. //
  1196. BAIL_ON_FAILURE(hr);
  1197. }
  1198. //
  1199. // Now update the property in the cache
  1200. //
  1201. hr = _pPropertyCache->putproperty(
  1202. bstrName,
  1203. dwFlags,
  1204. dwSyntaxId,
  1205. dwNumValues,
  1206. pNdsDestObjects
  1207. );
  1208. BAIL_ON_FAILURE(hr);
  1209. error:
  1210. if (pNdsDestObjects) {
  1211. NdsTypeFreeNdsObjects(
  1212. pNdsDestObjects,
  1213. dwNumValues
  1214. );
  1215. }
  1216. if (pVarArray) {
  1217. DWORD i = 0;
  1218. for (i = 0; i < dwNumVariants; i++) {
  1219. VariantClear(pVarArray + i);
  1220. }
  1221. FreeADsMem(pVarArray);
  1222. }
  1223. RRETURN_EXP_IF_ERR(hr);
  1224. }
  1225. STDMETHODIMP
  1226. CNDSGenObject::GetEx(
  1227. THIS_ BSTR bstrName,
  1228. VARIANT FAR* pvProp
  1229. )
  1230. {
  1231. HRESULT hr = S_OK;
  1232. DWORD dwSyntaxId;
  1233. DWORD dwNumValues;
  1234. LPNDSOBJECT pNdsSrcObjects = NULL;
  1235. //
  1236. // retrieve data object from cache; if one exists
  1237. //
  1238. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1239. hr = _pPropertyCache->unboundgetproperty(
  1240. bstrName,
  1241. &dwSyntaxId,
  1242. &dwNumValues,
  1243. &pNdsSrcObjects
  1244. );
  1245. BAIL_ON_FAILURE(hr);
  1246. }else {
  1247. hr = _pPropertyCache->getproperty(
  1248. bstrName,
  1249. &dwSyntaxId,
  1250. &dwNumValues,
  1251. &pNdsSrcObjects
  1252. );
  1253. BAIL_ON_FAILURE(hr);
  1254. }
  1255. //
  1256. // translate the Nds objects to variants
  1257. //
  1258. hr = NdsTypeToVarTypeCopyConstruct(
  1259. pNdsSrcObjects,
  1260. dwNumValues,
  1261. pvProp,
  1262. TRUE
  1263. );
  1264. BAIL_ON_FAILURE(hr);
  1265. error:
  1266. if (pNdsSrcObjects) {
  1267. NdsTypeFreeNdsObjects(
  1268. pNdsSrcObjects,
  1269. dwNumValues
  1270. );
  1271. }
  1272. RRETURN_EXP_IF_ERR(hr);
  1273. }
  1274. void
  1275. CNDSGenObject::InitSearchPrefs()
  1276. {
  1277. _SearchPref._iScope = 1;
  1278. _SearchPref._fDerefAliases = FALSE;
  1279. _SearchPref._fAttrsOnly = FALSE;
  1280. }
  1281. STDMETHODIMP
  1282. CNDSGenObject::get_PropertyCount(
  1283. THIS_ long FAR *plCount
  1284. )
  1285. {
  1286. HRESULT hr = E_FAIL;
  1287. if (_pPropertyCache) {
  1288. hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
  1289. }
  1290. RRETURN_EXP_IF_ERR(hr);
  1291. }
  1292. STDMETHODIMP
  1293. CNDSGenObject::Next(
  1294. THIS_ VARIANT FAR *pVariant
  1295. )
  1296. {
  1297. HRESULT hr = E_FAIL;
  1298. DWORD dwSyntaxId = 0;
  1299. DWORD dwNumValues = 0;
  1300. LPNDSOBJECT pNdsSrcObjects = NULL;
  1301. VARIANT varData;
  1302. IDispatch * pDispatch = NULL;
  1303. PADSVALUE pAdsValues = NULL;
  1304. if (!_pPropertyCache->index_valid())
  1305. RRETURN_EXP_IF_ERR(E_FAIL);
  1306. VariantInit(&varData);
  1307. hr = _pPropertyCache->unboundgetproperty(
  1308. _pPropertyCache->get_CurrentIndex(),
  1309. &dwSyntaxId,
  1310. &dwNumValues,
  1311. &pNdsSrcObjects
  1312. );
  1313. BAIL_ON_FAILURE(hr);
  1314. //
  1315. // translate the Nds objects to variants
  1316. //
  1317. hr = ConvertNdsValuesToVariant(
  1318. _pPropertyCache->get_CurrentPropName(),
  1319. pNdsSrcObjects,
  1320. dwSyntaxId,
  1321. dwNumValues,
  1322. pVariant
  1323. );
  1324. BAIL_ON_FAILURE(hr);
  1325. error:
  1326. //
  1327. // - goto next one even if error to avoid infinite looping at a property
  1328. // which we cannot convert (e.g. schemaless server property.)
  1329. // - do not return the result of Skip() as current operation does not
  1330. // depend on the sucess of Skip().
  1331. //
  1332. Skip(1);
  1333. if (pNdsSrcObjects) {
  1334. NdsTypeFreeNdsObjects(pNdsSrcObjects, dwNumValues);
  1335. }
  1336. RRETURN_EXP_IF_ERR(hr);
  1337. }
  1338. STDMETHODIMP
  1339. CNDSGenObject::Skip(
  1340. THIS_ long cElements
  1341. )
  1342. {
  1343. HRESULT hr = S_OK;
  1344. hr = _pPropertyCache->skip_propindex(
  1345. cElements
  1346. );
  1347. RRETURN_EXP_IF_ERR(hr);
  1348. }
  1349. STDMETHODIMP
  1350. CNDSGenObject::Reset(
  1351. )
  1352. {
  1353. _pPropertyCache->reset_propindex();
  1354. RRETURN_EXP_IF_ERR(S_OK);
  1355. }
  1356. STDMETHODIMP
  1357. CNDSGenObject::ResetPropertyItem(THIS_ VARIANT varEntry)
  1358. {
  1359. HRESULT hr = S_OK;
  1360. DWORD dwIndex = 0;
  1361. switch (V_VT(&varEntry)) {
  1362. case VT_BSTR:
  1363. hr = _pPropertyCache->findproperty(
  1364. V_BSTR(&varEntry),
  1365. &dwIndex
  1366. );
  1367. BAIL_ON_FAILURE(hr);
  1368. break;
  1369. case VT_I4:
  1370. dwIndex = V_I4(&varEntry);
  1371. break;
  1372. case VT_I2:
  1373. dwIndex = V_I2(&varEntry);
  1374. break;
  1375. default:
  1376. hr = E_FAIL;
  1377. BAIL_ON_FAILURE(hr);
  1378. }
  1379. hr = _pPropertyCache->deleteproperty(
  1380. dwIndex
  1381. );
  1382. error:
  1383. RRETURN_EXP_IF_ERR(hr);
  1384. }
  1385. STDMETHODIMP
  1386. CNDSGenObject::GetPropertyItem(
  1387. THIS_ BSTR bstrName,
  1388. LONG lnType,
  1389. VARIANT * pVariant
  1390. )
  1391. {
  1392. HRESULT hr = S_OK;
  1393. DWORD dwSyntaxId;
  1394. DWORD dwNumValues;
  1395. LPNDSOBJECT pNdsSrcObjects = NULL;
  1396. PADSVALUE pAdsValues = NULL;
  1397. //
  1398. // retrieve data object from cache; if one exists
  1399. //
  1400. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1401. hr = _pPropertyCache->unboundgetproperty(
  1402. bstrName,
  1403. &dwSyntaxId,
  1404. &dwNumValues,
  1405. &pNdsSrcObjects
  1406. );
  1407. BAIL_ON_FAILURE(hr);
  1408. }else {
  1409. hr = _pPropertyCache->getproperty(
  1410. bstrName,
  1411. &dwSyntaxId,
  1412. &dwNumValues,
  1413. &pNdsSrcObjects
  1414. );
  1415. BAIL_ON_FAILURE(hr);
  1416. }
  1417. //
  1418. // translate the Nds objects to variants
  1419. //
  1420. hr = ConvertNdsValuesToVariant(
  1421. bstrName,
  1422. pNdsSrcObjects,
  1423. dwSyntaxId,
  1424. dwNumValues,
  1425. pVariant
  1426. );
  1427. error:
  1428. if (pNdsSrcObjects) {
  1429. NdsTypeFreeNdsObjects(
  1430. pNdsSrcObjects,
  1431. dwNumValues
  1432. );
  1433. }
  1434. RRETURN_EXP_IF_ERR(hr);
  1435. }
  1436. STDMETHODIMP
  1437. CNDSGenObject::PutPropertyItem(THIS_ VARIANT varData)
  1438. {
  1439. HRESULT hr = S_OK;
  1440. DWORD dwSyntaxId = 0;
  1441. DWORD dwIndex = 0;
  1442. WCHAR szPropertyName[MAX_PATH];
  1443. DWORD dwControlCode = 0;
  1444. LPNDSOBJECT pNdsDestObjects = NULL;
  1445. DWORD dwNumValues = 0;
  1446. DWORD dwFlags = 0;
  1447. VARIANT * pVarArray = NULL;
  1448. VARIANT * pvarData = NULL;
  1449. PADSVALUE pAdsValues = NULL;
  1450. DWORD dwAdsValues = 0;
  1451. DWORD dwSyntaxId2 = 0;
  1452. DWORD dwNumNdsValues = 0;
  1453. hr = ConvertVariantToNdsValues(
  1454. varData,
  1455. szPropertyName,
  1456. &dwControlCode,
  1457. &pNdsDestObjects,
  1458. &dwNumValues,
  1459. &dwSyntaxId
  1460. );
  1461. BAIL_ON_FAILURE(hr);
  1462. switch (dwControlCode) {
  1463. case ADS_PROPERTY_CLEAR:
  1464. dwFlags = CACHE_PROPERTY_CLEARED;
  1465. pNdsDestObjects = NULL;
  1466. dwNumValues = 0;
  1467. break;
  1468. case ADS_PROPERTY_UPDATE:
  1469. dwFlags = CACHE_PROPERTY_MODIFIED;
  1470. break;
  1471. case ADS_PROPERTY_APPEND:
  1472. dwFlags = CACHE_PROPERTY_APPENDED;
  1473. break;
  1474. case ADS_PROPERTY_DELETE:
  1475. dwFlags = CACHE_PROPERTY_DELETED;
  1476. break;
  1477. default:
  1478. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1479. }
  1480. //
  1481. // Find this property in the cache
  1482. //
  1483. hr = _pPropertyCache->findproperty(
  1484. szPropertyName,
  1485. &dwIndex
  1486. );
  1487. //
  1488. // If this property does not exist in the
  1489. // cache, add this property into the cache.
  1490. //
  1491. if (FAILED(hr)) {
  1492. hr = _pPropertyCache->addproperty(
  1493. szPropertyName,
  1494. dwSyntaxId
  1495. );
  1496. //
  1497. // If the operation fails for some reason
  1498. // move on to the next property
  1499. //
  1500. BAIL_ON_FAILURE(hr);
  1501. }
  1502. //
  1503. // Now update the property in the cache
  1504. //
  1505. hr = _pPropertyCache->putproperty(
  1506. szPropertyName,
  1507. dwFlags,
  1508. dwSyntaxId,
  1509. dwNumValues,
  1510. pNdsDestObjects
  1511. );
  1512. BAIL_ON_FAILURE(hr);
  1513. error:
  1514. if (pNdsDestObjects) {
  1515. NdsTypeFreeNdsObjects(
  1516. pNdsDestObjects,
  1517. dwNumValues
  1518. );
  1519. }
  1520. RRETURN_EXP_IF_ERR(hr);
  1521. }
  1522. HRESULT
  1523. CreatePropEntry(
  1524. LPWSTR szPropName,
  1525. DWORD ADsType,
  1526. DWORD numValues,
  1527. VARIANT varData,
  1528. REFIID riid,
  1529. LPVOID * ppDispatch
  1530. )
  1531. {
  1532. HRESULT hr = S_OK;
  1533. IADsPropertyEntry * pPropEntry = NULL;
  1534. hr = CoCreateInstance(
  1535. CLSID_PropertyEntry,
  1536. NULL,
  1537. CLSCTX_INPROC_SERVER,
  1538. IID_IADsPropertyEntry,
  1539. (void **)&pPropEntry
  1540. );
  1541. BAIL_ON_FAILURE(hr);
  1542. hr = pPropEntry->put_Name(szPropName);
  1543. BAIL_ON_FAILURE(hr);
  1544. hr = pPropEntry->put_ADsType(ADsType);
  1545. BAIL_ON_FAILURE(hr);
  1546. hr = pPropEntry->put_Values(varData);
  1547. BAIL_ON_FAILURE(hr);
  1548. hr = pPropEntry->QueryInterface(
  1549. riid,
  1550. ppDispatch
  1551. );
  1552. BAIL_ON_FAILURE(hr);
  1553. error:
  1554. if (pPropEntry) {
  1555. pPropEntry->Release();
  1556. }
  1557. RRETURN(hr);
  1558. }
  1559. STDMETHODIMP
  1560. CNDSGenObject::Item(
  1561. THIS_ VARIANT varIndex,
  1562. VARIANT * pVariant
  1563. )
  1564. {
  1565. HRESULT hr = S_OK;
  1566. DWORD dwSyntaxId;
  1567. DWORD dwNumValues;
  1568. LPNDSOBJECT pNdsSrcObjects = NULL;
  1569. PADSVALUE pAdsValues = NULL;
  1570. LPWSTR szPropName = NULL;
  1571. VARIANT * pvVar = &varIndex;
  1572. //
  1573. // retrieve data object from cache; if one exis
  1574. //
  1575. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  1576. //
  1577. // The value is being passed in byref so we need to
  1578. // deref it for vbs stuff to work
  1579. //
  1580. pvVar = V_VARIANTREF(&varIndex);
  1581. }
  1582. switch (V_VT(pvVar)) {
  1583. case VT_BSTR:
  1584. //
  1585. // retrieve data object from cache; if one exists
  1586. //
  1587. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1588. hr = _pPropertyCache->unboundgetproperty(
  1589. V_BSTR(pvVar),
  1590. &dwSyntaxId,
  1591. &dwNumValues,
  1592. &pNdsSrcObjects
  1593. );
  1594. BAIL_ON_FAILURE(hr);
  1595. }else {
  1596. hr = _pPropertyCache->getproperty(
  1597. V_BSTR(pvVar),
  1598. &dwSyntaxId,
  1599. &dwNumValues,
  1600. &pNdsSrcObjects
  1601. );
  1602. BAIL_ON_FAILURE(hr);
  1603. }
  1604. hr = ConvertNdsValuesToVariant(
  1605. V_BSTR(pvVar),
  1606. pNdsSrcObjects,
  1607. dwSyntaxId,
  1608. dwNumValues,
  1609. pVariant
  1610. );
  1611. BAIL_ON_FAILURE(hr);
  1612. break;
  1613. case VT_I4:
  1614. hr = _pPropertyCache->unboundgetproperty(
  1615. V_I4(pvVar),
  1616. &dwSyntaxId,
  1617. &dwNumValues,
  1618. &pNdsSrcObjects
  1619. );
  1620. BAIL_ON_FAILURE(hr);
  1621. szPropName = _pPropertyCache->get_PropName(V_I4(pvVar));
  1622. hr = ConvertNdsValuesToVariant(
  1623. szPropName,
  1624. pNdsSrcObjects,
  1625. dwSyntaxId,
  1626. dwNumValues,
  1627. pVariant
  1628. );
  1629. BAIL_ON_FAILURE(hr);
  1630. break;
  1631. case VT_I2:
  1632. hr = _pPropertyCache->unboundgetproperty(
  1633. (DWORD)V_I2(pvVar),
  1634. &dwSyntaxId,
  1635. &dwNumValues,
  1636. &pNdsSrcObjects
  1637. );
  1638. BAIL_ON_FAILURE(hr);
  1639. szPropName = _pPropertyCache->get_PropName(V_I2(pvVar));
  1640. hr = ConvertNdsValuesToVariant(
  1641. szPropName,
  1642. pNdsSrcObjects,
  1643. dwSyntaxId,
  1644. dwNumValues,
  1645. pVariant
  1646. );
  1647. BAIL_ON_FAILURE(hr);
  1648. break;
  1649. default:
  1650. hr = E_FAIL;
  1651. BAIL_ON_FAILURE(hr);
  1652. }
  1653. error:
  1654. if (pNdsSrcObjects) {
  1655. NdsTypeFreeNdsObjects(
  1656. pNdsSrcObjects,
  1657. dwNumValues
  1658. );
  1659. }
  1660. RRETURN_EXP_IF_ERR(hr);
  1661. }
  1662. STDMETHODIMP
  1663. CNDSGenObject::PurgePropertyList()
  1664. {
  1665. _pPropertyCache->flushpropcache();
  1666. RRETURN(S_OK);
  1667. }
  1668. HRESULT
  1669. ConvertVariantToVariantArray(
  1670. VARIANT varData,
  1671. VARIANT ** ppVarArray,
  1672. DWORD * pdwNumValues
  1673. )
  1674. {
  1675. DWORD dwNumValues = 0;
  1676. VARIANT * pVarArray = NULL;
  1677. VARIANT * pVarData = NULL;
  1678. HRESULT hr = S_OK;
  1679. *ppVarArray = NULL;
  1680. *pdwNumValues = 0;
  1681. //
  1682. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1683. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1684. // what's inside.
  1685. //
  1686. pVarData = &varData;
  1687. if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) {
  1688. pVarData = V_VARIANTREF(&varData);
  1689. }
  1690. if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  1691. (V_VT(pVarData) == (VT_VARIANT|VT_ARRAY))) {
  1692. hr = ConvertSafeArrayToVariantArray(
  1693. *pVarData,
  1694. &pVarArray,
  1695. &dwNumValues
  1696. );
  1697. BAIL_ON_FAILURE(hr);
  1698. } else {
  1699. pVarArray = NULL;
  1700. dwNumValues = 0;
  1701. }
  1702. *ppVarArray = pVarArray;
  1703. *pdwNumValues = dwNumValues;
  1704. error:
  1705. RRETURN(hr);
  1706. }
  1707. void
  1708. FreeVariantArray(
  1709. VARIANT * pVarArray,
  1710. DWORD dwNumValues
  1711. )
  1712. {
  1713. if (pVarArray) {
  1714. DWORD i = 0;
  1715. for (i = 0; i < dwNumValues; i++) {
  1716. VariantClear(pVarArray + i);
  1717. }
  1718. FreeADsMem(pVarArray);
  1719. }
  1720. }
  1721. HRESULT
  1722. ConvertVariantToNdsValues(
  1723. VARIANT varData,
  1724. LPWSTR szPropertyName,
  1725. PDWORD pdwControlCode,
  1726. PNDSOBJECT * ppNdsDestObjects,
  1727. PDWORD pdwNumValues,
  1728. PDWORD pdwSyntaxId
  1729. )
  1730. {
  1731. HRESULT hr = S_OK;
  1732. IADsPropertyEntry * pPropEntry = NULL;
  1733. IDispatch * pDispatch = NULL;
  1734. BSTR bstrPropName = NULL;
  1735. DWORD dwControlCode = 0;
  1736. DWORD dwAdsType = 0;
  1737. VARIANT varValues;
  1738. VARIANT * pVarArray = NULL;
  1739. DWORD dwNumValues = 0;
  1740. PADSVALUE pAdsValues = NULL;
  1741. DWORD dwAdsValues = 0;
  1742. PNDSOBJECT pNdsDestObjects = 0;
  1743. DWORD dwNumNdsObjects = 0;
  1744. DWORD dwNdsSyntaxId = 0;
  1745. if (V_VT(&varData) != VT_DISPATCH) {
  1746. RRETURN (hr = DISP_E_TYPEMISMATCH);
  1747. }
  1748. pDispatch = V_DISPATCH(&varData);
  1749. hr = pDispatch->QueryInterface(
  1750. IID_IADsPropertyEntry,
  1751. (void **)&pPropEntry
  1752. );
  1753. BAIL_ON_FAILURE(hr);
  1754. VariantInit(&varValues);
  1755. VariantClear(&varValues);
  1756. hr = pPropEntry->get_Name(&bstrPropName);
  1757. BAIL_ON_FAILURE(hr);
  1758. wcscpy(szPropertyName, bstrPropName);
  1759. hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
  1760. BAIL_ON_FAILURE(hr);
  1761. *pdwControlCode = dwControlCode;
  1762. hr = pPropEntry->get_ADsType((long *)&dwAdsType);
  1763. BAIL_ON_FAILURE(hr);
  1764. hr = pPropEntry->get_Values(&varValues);
  1765. BAIL_ON_FAILURE(hr);
  1766. hr = ConvertVariantToVariantArray(
  1767. varValues,
  1768. &pVarArray,
  1769. &dwNumValues
  1770. );
  1771. BAIL_ON_FAILURE(hr);
  1772. if (dwNumValues) {
  1773. hr = PropVariantToAdsType(
  1774. pVarArray,
  1775. dwNumValues,
  1776. &pAdsValues,
  1777. &dwAdsValues
  1778. );
  1779. BAIL_ON_FAILURE(hr);
  1780. hr = AdsTypeToNdsTypeCopyConstruct(
  1781. pAdsValues,
  1782. dwAdsValues,
  1783. &pNdsDestObjects,
  1784. &dwNumNdsObjects,
  1785. &dwNdsSyntaxId
  1786. );
  1787. BAIL_ON_FAILURE(hr);
  1788. }
  1789. *ppNdsDestObjects = pNdsDestObjects;
  1790. *pdwNumValues = dwNumNdsObjects;
  1791. *pdwSyntaxId = dwNdsSyntaxId;
  1792. cleanup:
  1793. if (bstrPropName) {
  1794. ADsFreeString(bstrPropName);
  1795. }
  1796. if (pAdsValues) {
  1797. AdsFreeAdsValues(
  1798. pAdsValues,
  1799. dwNumValues
  1800. );
  1801. FreeADsMem( pAdsValues );
  1802. }
  1803. if (pVarArray) {
  1804. FreeVariantArray(
  1805. pVarArray,
  1806. dwAdsValues
  1807. );
  1808. }
  1809. if (pPropEntry) {
  1810. pPropEntry->Release();
  1811. }
  1812. VariantClear(&varValues);
  1813. RRETURN(hr);
  1814. error:
  1815. if (pNdsDestObjects) {
  1816. NdsTypeFreeNdsObjects(
  1817. pNdsDestObjects,
  1818. dwNumNdsObjects
  1819. );
  1820. }
  1821. *ppNdsDestObjects = NULL;
  1822. *pdwNumValues = 0;
  1823. goto cleanup;
  1824. }
  1825. HRESULT
  1826. ConvertNdsValuesToVariant(
  1827. BSTR bstrPropName,
  1828. LPNDSOBJECT pNdsSrcObjects,
  1829. DWORD dwSyntaxId,
  1830. DWORD dwNumValues,
  1831. PVARIANT pVarProp
  1832. )
  1833. {
  1834. HRESULT hr = S_OK;
  1835. PADSVALUE pAdsValues = NULL;
  1836. DWORD dwNumAdsValues = 0;
  1837. VARIANT varData;
  1838. IDispatch * pDispatch = NULL;
  1839. DWORD dwADsType = 0;
  1840. VariantInit(&varData);
  1841. VariantInit(pVarProp);
  1842. //
  1843. // translate the Nds objects to variants
  1844. //
  1845. hr = NdsTypeToAdsTypeCopyConstruct(
  1846. pNdsSrcObjects,
  1847. dwNumValues,
  1848. &pAdsValues
  1849. );
  1850. if (SUCCEEDED(hr)){
  1851. hr = AdsTypeToPropVariant(
  1852. pAdsValues,
  1853. dwNumValues,
  1854. &varData
  1855. );
  1856. if (SUCCEEDED(hr)) {
  1857. dwADsType = (dwSyntaxId >= g_cMapNdsTypeToADsType) ?
  1858. ADSTYPE_INVALID :
  1859. g_MapNdsTypeToADsType[dwSyntaxId];
  1860. }else {
  1861. VariantClear(&varData);
  1862. hr = S_OK;
  1863. }
  1864. }else {
  1865. VariantClear(&varData);
  1866. VariantInit(&varData);
  1867. hr = S_OK;
  1868. }
  1869. hr = CreatePropEntry(
  1870. bstrPropName,
  1871. dwADsType,
  1872. dwNumValues,
  1873. varData,
  1874. IID_IDispatch,
  1875. (void **)&pDispatch
  1876. );
  1877. BAIL_ON_FAILURE(hr);
  1878. V_DISPATCH(pVarProp) = pDispatch;
  1879. V_VT(pVarProp) = VT_DISPATCH;
  1880. error:
  1881. if (pAdsValues) {
  1882. AdsFreeAdsValues(
  1883. pAdsValues,
  1884. dwNumValues
  1885. );
  1886. FreeADsMem( pAdsValues );
  1887. }
  1888. VariantClear(&varData);
  1889. RRETURN(hr);
  1890. }