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.

2414 lines
50 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 pDispMgr;
  896. RRETURN(hr);
  897. }
  898. STDMETHODIMP
  899. CNDSGenObject::Get(
  900. THIS_ BSTR bstrName,
  901. VARIANT FAR* pvProp
  902. )
  903. {
  904. HRESULT hr = S_OK;
  905. DWORD dwSyntaxId;
  906. DWORD dwNumValues;
  907. LPNDSOBJECT pNdsSrcObjects = NULL;
  908. //
  909. // retrieve data object from cache; if one exists
  910. //
  911. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  912. hr = _pPropertyCache->unboundgetproperty(
  913. bstrName,
  914. &dwSyntaxId,
  915. &dwNumValues,
  916. &pNdsSrcObjects
  917. );
  918. BAIL_ON_FAILURE(hr);
  919. }else {
  920. hr = _pPropertyCache->getproperty(
  921. bstrName,
  922. &dwSyntaxId,
  923. &dwNumValues,
  924. &pNdsSrcObjects
  925. );
  926. BAIL_ON_FAILURE(hr);
  927. }
  928. //
  929. // translate the Nds objects to variants
  930. //
  931. hr = NdsTypeToVarTypeCopyConstruct(
  932. pNdsSrcObjects,
  933. dwNumValues,
  934. pvProp,
  935. FALSE
  936. );
  937. BAIL_ON_FAILURE(hr);
  938. error:
  939. if (pNdsSrcObjects) {
  940. NdsTypeFreeNdsObjects(
  941. pNdsSrcObjects,
  942. dwNumValues
  943. );
  944. }
  945. RRETURN_EXP_IF_ERR(hr);
  946. }
  947. STDMETHODIMP
  948. CNDSGenObject::Put(
  949. THIS_ BSTR bstrName,
  950. VARIANT vProp
  951. )
  952. {
  953. HRESULT hr = S_OK;
  954. DWORD dwSyntaxId = 0;
  955. DWORD dwIndex = 0;
  956. LPNDSOBJECT pNdsDestObjects = NULL;
  957. WCHAR szNDSTreeName[MAX_PATH];
  958. DWORD dwNumValues = 0, dwNumVariants = 0;
  959. VARIANT * pVarArray = NULL;
  960. VARIANT * pvProp = NULL;
  961. VARIANT vDefProp;
  962. VariantInit(&vDefProp);
  963. //
  964. // Issue: How do we handle multi-valued support
  965. //
  966. //
  967. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  968. // We should dereference a VT_BYREF|VT_VARIANT once and see
  969. // what's inside.
  970. //
  971. pvProp = &vProp;
  972. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  973. pvProp = V_VARIANTREF(&vProp);
  974. }
  975. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  976. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  977. hr = ConvertByRefSafeArrayToVariantArray(
  978. *pvProp,
  979. &pVarArray,
  980. &dwNumValues
  981. );
  982. BAIL_ON_FAILURE(hr);
  983. pvProp = pVarArray;
  984. }else {
  985. //
  986. // If pvProp is a reference to a fundamental type,
  987. // we have to dereference it once.
  988. //
  989. if (V_ISBYREF(pvProp)) {
  990. hr = VariantCopyInd(&vDefProp, pvProp);
  991. BAIL_ON_FAILURE(hr);
  992. pvProp = &vDefProp;
  993. }
  994. dwNumValues = 1;
  995. }
  996. //
  997. // Save it in case dwNumValues changes below (as in the case of ACLs)
  998. //
  999. dwNumVariants = dwNumValues;
  1000. //
  1001. // Get the TreeName for this object
  1002. //
  1003. hr = BuildNDSTreeNameFromADsPath(
  1004. _ADsPath,
  1005. szNDSTreeName
  1006. );
  1007. BAIL_ON_FAILURE(hr);
  1008. //
  1009. // check if this is a legal property for this object,
  1010. //
  1011. hr = ValidatePropertyinCache(
  1012. szNDSTreeName,
  1013. _ADsClass,
  1014. bstrName,
  1015. _Credentials,
  1016. &dwSyntaxId
  1017. );
  1018. BAIL_ON_FAILURE(hr);
  1019. //
  1020. // check if the variant maps to the syntax of this property
  1021. //
  1022. hr = VarTypeToNdsTypeCopyConstruct(
  1023. dwSyntaxId,
  1024. pvProp,
  1025. &dwNumValues,
  1026. &pNdsDestObjects
  1027. );
  1028. BAIL_ON_FAILURE(hr);
  1029. //
  1030. // Find this property in the cache
  1031. //
  1032. hr = _pPropertyCache->findproperty(
  1033. bstrName,
  1034. &dwIndex
  1035. );
  1036. //
  1037. // If this property does not exist in the
  1038. // cache, add this property into the cache.
  1039. //
  1040. if (FAILED(hr)) {
  1041. hr = _pPropertyCache->addproperty(
  1042. bstrName,
  1043. dwSyntaxId
  1044. );
  1045. //
  1046. // If the operation fails for some reason
  1047. // move on to the next property
  1048. //
  1049. BAIL_ON_FAILURE(hr);
  1050. }
  1051. //
  1052. // Now update the property in the cache
  1053. //
  1054. hr = _pPropertyCache->putproperty(
  1055. bstrName,
  1056. CACHE_PROPERTY_MODIFIED,
  1057. dwSyntaxId,
  1058. dwNumValues,
  1059. pNdsDestObjects
  1060. );
  1061. BAIL_ON_FAILURE(hr);
  1062. error:
  1063. VariantClear(&vDefProp);
  1064. if (pNdsDestObjects) {
  1065. NdsTypeFreeNdsObjects(
  1066. pNdsDestObjects,
  1067. dwNumValues
  1068. );
  1069. }
  1070. if (pVarArray) {
  1071. DWORD i = 0;
  1072. for (i = 0; i < dwNumVariants; i++) {
  1073. VariantClear(pVarArray + i);
  1074. }
  1075. FreeADsMem(pVarArray);
  1076. }
  1077. RRETURN_EXP_IF_ERR(hr);
  1078. }
  1079. STDMETHODIMP
  1080. CNDSGenObject::PutEx(
  1081. THIS_ long lnControlCode,
  1082. BSTR bstrName,
  1083. VARIANT vProp
  1084. )
  1085. {
  1086. HRESULT hr = S_OK;
  1087. DWORD dwSyntaxId = 0;
  1088. DWORD dwIndex = 0;
  1089. LPNDSOBJECT pNdsDestObjects = NULL;
  1090. WCHAR szNDSTreeName[MAX_PATH];
  1091. DWORD dwNumValues = 0, dwNumVariants = 0;
  1092. DWORD dwFlags = 0;
  1093. VARIANT * pVarArray = NULL;
  1094. VARIANT * pvProp = NULL;
  1095. //
  1096. // Get the TreeName for this object
  1097. //
  1098. hr = BuildNDSTreeNameFromADsPath(
  1099. _ADsPath,
  1100. szNDSTreeName
  1101. );
  1102. BAIL_ON_FAILURE(hr);
  1103. //
  1104. // check if this is a legal property for this object,
  1105. //
  1106. hr = ValidatePropertyinCache(
  1107. szNDSTreeName,
  1108. _ADsClass,
  1109. bstrName,
  1110. _Credentials,
  1111. &dwSyntaxId
  1112. );
  1113. BAIL_ON_FAILURE(hr);
  1114. switch (lnControlCode) {
  1115. case ADS_PROPERTY_CLEAR:
  1116. dwFlags = CACHE_PROPERTY_CLEARED;
  1117. pNdsDestObjects = NULL;
  1118. dwNumValues = 0;
  1119. break;
  1120. case ADS_PROPERTY_UPDATE:
  1121. case ADS_PROPERTY_APPEND:
  1122. case ADS_PROPERTY_DELETE:
  1123. if (lnControlCode == ADS_PROPERTY_UPDATE) {
  1124. dwFlags = CACHE_PROPERTY_MODIFIED;
  1125. }
  1126. else if (lnControlCode == ADS_PROPERTY_APPEND) {
  1127. dwFlags = CACHE_PROPERTY_APPENDED;
  1128. }
  1129. else {
  1130. dwFlags = CACHE_PROPERTY_DELETED;
  1131. }
  1132. //
  1133. // Now begin the rest of the processing
  1134. //
  1135. //
  1136. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1137. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1138. // what's inside.
  1139. //
  1140. pvProp = &vProp;
  1141. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1142. pvProp = V_VARIANTREF(&vProp);
  1143. }
  1144. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
  1145. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
  1146. hr = ConvertByRefSafeArrayToVariantArray(
  1147. *pvProp,
  1148. &pVarArray,
  1149. &dwNumValues
  1150. );
  1151. BAIL_ON_FAILURE(hr);
  1152. pvProp = pVarArray;
  1153. }else {
  1154. hr = E_FAIL;
  1155. BAIL_ON_FAILURE(hr);
  1156. }
  1157. //
  1158. // Save it in case dwNumValues changes below (as in the case of ACLs)
  1159. //
  1160. dwNumVariants = dwNumValues;
  1161. //
  1162. // check if the variant maps to the syntax of this property
  1163. //
  1164. hr = VarTypeToNdsTypeCopyConstruct(
  1165. dwSyntaxId,
  1166. pvProp,
  1167. &dwNumValues,
  1168. &pNdsDestObjects
  1169. );
  1170. BAIL_ON_FAILURE(hr);
  1171. break;
  1172. default:
  1173. RRETURN_EXP_IF_ERR(hr = E_ADS_BAD_PARAMETER);
  1174. }
  1175. //
  1176. // Find this property in the cache
  1177. //
  1178. hr = _pPropertyCache->findproperty(
  1179. bstrName,
  1180. &dwIndex
  1181. );
  1182. //
  1183. // If this property does not exist in the
  1184. // cache, add this property into the cache.
  1185. //
  1186. if (FAILED(hr)) {
  1187. hr = _pPropertyCache->addproperty(
  1188. bstrName,
  1189. dwSyntaxId
  1190. );
  1191. //
  1192. // If the operation fails for some reason
  1193. // move on to the next property
  1194. //
  1195. BAIL_ON_FAILURE(hr);
  1196. }
  1197. //
  1198. // Now update the property in the cache
  1199. //
  1200. hr = _pPropertyCache->putproperty(
  1201. bstrName,
  1202. dwFlags,
  1203. dwSyntaxId,
  1204. dwNumValues,
  1205. pNdsDestObjects
  1206. );
  1207. BAIL_ON_FAILURE(hr);
  1208. error:
  1209. if (pNdsDestObjects) {
  1210. NdsTypeFreeNdsObjects(
  1211. pNdsDestObjects,
  1212. dwNumValues
  1213. );
  1214. }
  1215. if (pVarArray) {
  1216. DWORD i = 0;
  1217. for (i = 0; i < dwNumVariants; i++) {
  1218. VariantClear(pVarArray + i);
  1219. }
  1220. FreeADsMem(pVarArray);
  1221. }
  1222. RRETURN_EXP_IF_ERR(hr);
  1223. }
  1224. STDMETHODIMP
  1225. CNDSGenObject::GetEx(
  1226. THIS_ BSTR bstrName,
  1227. VARIANT FAR* pvProp
  1228. )
  1229. {
  1230. HRESULT hr = S_OK;
  1231. DWORD dwSyntaxId;
  1232. DWORD dwNumValues;
  1233. LPNDSOBJECT pNdsSrcObjects = NULL;
  1234. //
  1235. // retrieve data object from cache; if one exists
  1236. //
  1237. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1238. hr = _pPropertyCache->unboundgetproperty(
  1239. bstrName,
  1240. &dwSyntaxId,
  1241. &dwNumValues,
  1242. &pNdsSrcObjects
  1243. );
  1244. BAIL_ON_FAILURE(hr);
  1245. }else {
  1246. hr = _pPropertyCache->getproperty(
  1247. bstrName,
  1248. &dwSyntaxId,
  1249. &dwNumValues,
  1250. &pNdsSrcObjects
  1251. );
  1252. BAIL_ON_FAILURE(hr);
  1253. }
  1254. //
  1255. // translate the Nds objects to variants
  1256. //
  1257. hr = NdsTypeToVarTypeCopyConstruct(
  1258. pNdsSrcObjects,
  1259. dwNumValues,
  1260. pvProp,
  1261. TRUE
  1262. );
  1263. BAIL_ON_FAILURE(hr);
  1264. error:
  1265. if (pNdsSrcObjects) {
  1266. NdsTypeFreeNdsObjects(
  1267. pNdsSrcObjects,
  1268. dwNumValues
  1269. );
  1270. }
  1271. RRETURN_EXP_IF_ERR(hr);
  1272. }
  1273. void
  1274. CNDSGenObject::InitSearchPrefs()
  1275. {
  1276. _SearchPref._iScope = 1;
  1277. _SearchPref._fDerefAliases = FALSE;
  1278. _SearchPref._fAttrsOnly = FALSE;
  1279. }
  1280. STDMETHODIMP
  1281. CNDSGenObject::get_PropertyCount(
  1282. THIS_ long FAR *plCount
  1283. )
  1284. {
  1285. HRESULT hr = E_FAIL;
  1286. if (_pPropertyCache) {
  1287. hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
  1288. }
  1289. RRETURN_EXP_IF_ERR(hr);
  1290. }
  1291. STDMETHODIMP
  1292. CNDSGenObject::Next(
  1293. THIS_ VARIANT FAR *pVariant
  1294. )
  1295. {
  1296. HRESULT hr = E_FAIL;
  1297. DWORD dwSyntaxId = 0;
  1298. DWORD dwNumValues = 0;
  1299. LPNDSOBJECT pNdsSrcObjects = NULL;
  1300. VARIANT varData;
  1301. IDispatch * pDispatch = NULL;
  1302. PADSVALUE pAdsValues = NULL;
  1303. if (!_pPropertyCache->index_valid())
  1304. RRETURN_EXP_IF_ERR(E_FAIL);
  1305. VariantInit(&varData);
  1306. hr = _pPropertyCache->unboundgetproperty(
  1307. _pPropertyCache->get_CurrentIndex(),
  1308. &dwSyntaxId,
  1309. &dwNumValues,
  1310. &pNdsSrcObjects
  1311. );
  1312. BAIL_ON_FAILURE(hr);
  1313. //
  1314. // translate the Nds objects to variants
  1315. //
  1316. hr = ConvertNdsValuesToVariant(
  1317. _pPropertyCache->get_CurrentPropName(),
  1318. pNdsSrcObjects,
  1319. dwSyntaxId,
  1320. dwNumValues,
  1321. pVariant
  1322. );
  1323. BAIL_ON_FAILURE(hr);
  1324. error:
  1325. //
  1326. // - goto next one even if error to avoid infinite looping at a property
  1327. // which we cannot convert (e.g. schemaless server property.)
  1328. // - do not return the result of Skip() as current operation does not
  1329. // depend on the sucess of Skip().
  1330. //
  1331. Skip(1);
  1332. if (pNdsSrcObjects) {
  1333. NdsTypeFreeNdsObjects(pNdsSrcObjects, dwNumValues);
  1334. }
  1335. RRETURN_EXP_IF_ERR(hr);
  1336. }
  1337. STDMETHODIMP
  1338. CNDSGenObject::Skip(
  1339. THIS_ long cElements
  1340. )
  1341. {
  1342. HRESULT hr = S_OK;
  1343. hr = _pPropertyCache->skip_propindex(
  1344. cElements
  1345. );
  1346. RRETURN_EXP_IF_ERR(hr);
  1347. }
  1348. STDMETHODIMP
  1349. CNDSGenObject::Reset(
  1350. )
  1351. {
  1352. _pPropertyCache->reset_propindex();
  1353. RRETURN_EXP_IF_ERR(S_OK);
  1354. }
  1355. STDMETHODIMP
  1356. CNDSGenObject::ResetPropertyItem(THIS_ VARIANT varEntry)
  1357. {
  1358. HRESULT hr = S_OK;
  1359. DWORD dwIndex = 0;
  1360. switch (V_VT(&varEntry)) {
  1361. case VT_BSTR:
  1362. hr = _pPropertyCache->findproperty(
  1363. V_BSTR(&varEntry),
  1364. &dwIndex
  1365. );
  1366. BAIL_ON_FAILURE(hr);
  1367. break;
  1368. case VT_I4:
  1369. dwIndex = V_I4(&varEntry);
  1370. break;
  1371. case VT_I2:
  1372. dwIndex = V_I2(&varEntry);
  1373. break;
  1374. default:
  1375. hr = E_FAIL;
  1376. BAIL_ON_FAILURE(hr);
  1377. }
  1378. hr = _pPropertyCache->deleteproperty(
  1379. dwIndex
  1380. );
  1381. error:
  1382. RRETURN_EXP_IF_ERR(hr);
  1383. }
  1384. STDMETHODIMP
  1385. CNDSGenObject::GetPropertyItem(
  1386. THIS_ BSTR bstrName,
  1387. LONG lnType,
  1388. VARIANT * pVariant
  1389. )
  1390. {
  1391. HRESULT hr = S_OK;
  1392. DWORD dwSyntaxId;
  1393. DWORD dwNumValues;
  1394. LPNDSOBJECT pNdsSrcObjects = NULL;
  1395. PADSVALUE pAdsValues = NULL;
  1396. //
  1397. // retrieve data object from cache; if one exists
  1398. //
  1399. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1400. hr = _pPropertyCache->unboundgetproperty(
  1401. bstrName,
  1402. &dwSyntaxId,
  1403. &dwNumValues,
  1404. &pNdsSrcObjects
  1405. );
  1406. BAIL_ON_FAILURE(hr);
  1407. }else {
  1408. hr = _pPropertyCache->getproperty(
  1409. bstrName,
  1410. &dwSyntaxId,
  1411. &dwNumValues,
  1412. &pNdsSrcObjects
  1413. );
  1414. BAIL_ON_FAILURE(hr);
  1415. }
  1416. //
  1417. // translate the Nds objects to variants
  1418. //
  1419. hr = ConvertNdsValuesToVariant(
  1420. bstrName,
  1421. pNdsSrcObjects,
  1422. dwSyntaxId,
  1423. dwNumValues,
  1424. pVariant
  1425. );
  1426. error:
  1427. if (pNdsSrcObjects) {
  1428. NdsTypeFreeNdsObjects(
  1429. pNdsSrcObjects,
  1430. dwNumValues
  1431. );
  1432. }
  1433. RRETURN_EXP_IF_ERR(hr);
  1434. }
  1435. STDMETHODIMP
  1436. CNDSGenObject::PutPropertyItem(THIS_ VARIANT varData)
  1437. {
  1438. HRESULT hr = S_OK;
  1439. DWORD dwSyntaxId = 0;
  1440. DWORD dwIndex = 0;
  1441. WCHAR szPropertyName[MAX_PATH];
  1442. DWORD dwControlCode = 0;
  1443. LPNDSOBJECT pNdsDestObjects = NULL;
  1444. DWORD dwNumValues = 0;
  1445. DWORD dwFlags = 0;
  1446. VARIANT * pVarArray = NULL;
  1447. VARIANT * pvarData = NULL;
  1448. PADSVALUE pAdsValues = NULL;
  1449. DWORD dwAdsValues = 0;
  1450. DWORD dwSyntaxId2 = 0;
  1451. DWORD dwNumNdsValues = 0;
  1452. hr = ConvertVariantToNdsValues(
  1453. varData,
  1454. szPropertyName,
  1455. &dwControlCode,
  1456. &pNdsDestObjects,
  1457. &dwNumValues,
  1458. &dwSyntaxId
  1459. );
  1460. BAIL_ON_FAILURE(hr);
  1461. switch (dwControlCode) {
  1462. case ADS_PROPERTY_CLEAR:
  1463. dwFlags = CACHE_PROPERTY_CLEARED;
  1464. pNdsDestObjects = NULL;
  1465. dwNumValues = 0;
  1466. break;
  1467. case ADS_PROPERTY_UPDATE:
  1468. dwFlags = CACHE_PROPERTY_MODIFIED;
  1469. break;
  1470. case ADS_PROPERTY_APPEND:
  1471. dwFlags = CACHE_PROPERTY_APPENDED;
  1472. break;
  1473. case ADS_PROPERTY_DELETE:
  1474. dwFlags = CACHE_PROPERTY_DELETED;
  1475. break;
  1476. default:
  1477. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1478. }
  1479. //
  1480. // Find this property in the cache
  1481. //
  1482. hr = _pPropertyCache->findproperty(
  1483. szPropertyName,
  1484. &dwIndex
  1485. );
  1486. //
  1487. // If this property does not exist in the
  1488. // cache, add this property into the cache.
  1489. //
  1490. if (FAILED(hr)) {
  1491. hr = _pPropertyCache->addproperty(
  1492. szPropertyName,
  1493. dwSyntaxId
  1494. );
  1495. //
  1496. // If the operation fails for some reason
  1497. // move on to the next property
  1498. //
  1499. BAIL_ON_FAILURE(hr);
  1500. }
  1501. //
  1502. // Now update the property in the cache
  1503. //
  1504. hr = _pPropertyCache->putproperty(
  1505. szPropertyName,
  1506. dwFlags,
  1507. dwSyntaxId,
  1508. dwNumValues,
  1509. pNdsDestObjects
  1510. );
  1511. BAIL_ON_FAILURE(hr);
  1512. error:
  1513. if (pNdsDestObjects) {
  1514. NdsTypeFreeNdsObjects(
  1515. pNdsDestObjects,
  1516. dwNumValues
  1517. );
  1518. }
  1519. RRETURN_EXP_IF_ERR(hr);
  1520. }
  1521. HRESULT
  1522. CreatePropEntry(
  1523. LPWSTR szPropName,
  1524. DWORD ADsType,
  1525. DWORD numValues,
  1526. VARIANT varData,
  1527. REFIID riid,
  1528. LPVOID * ppDispatch
  1529. )
  1530. {
  1531. HRESULT hr = S_OK;
  1532. IADsPropertyEntry * pPropEntry = NULL;
  1533. hr = CoCreateInstance(
  1534. CLSID_PropertyEntry,
  1535. NULL,
  1536. CLSCTX_INPROC_SERVER,
  1537. IID_IADsPropertyEntry,
  1538. (void **)&pPropEntry
  1539. );
  1540. BAIL_ON_FAILURE(hr);
  1541. hr = pPropEntry->put_Name(szPropName);
  1542. BAIL_ON_FAILURE(hr);
  1543. hr = pPropEntry->put_ADsType(ADsType);
  1544. BAIL_ON_FAILURE(hr);
  1545. hr = pPropEntry->put_Values(varData);
  1546. BAIL_ON_FAILURE(hr);
  1547. hr = pPropEntry->QueryInterface(
  1548. riid,
  1549. ppDispatch
  1550. );
  1551. BAIL_ON_FAILURE(hr);
  1552. error:
  1553. if (pPropEntry) {
  1554. pPropEntry->Release();
  1555. }
  1556. RRETURN(hr);
  1557. }
  1558. STDMETHODIMP
  1559. CNDSGenObject::Item(
  1560. THIS_ VARIANT varIndex,
  1561. VARIANT * pVariant
  1562. )
  1563. {
  1564. HRESULT hr = S_OK;
  1565. DWORD dwSyntaxId;
  1566. DWORD dwNumValues;
  1567. LPNDSOBJECT pNdsSrcObjects = NULL;
  1568. PADSVALUE pAdsValues = NULL;
  1569. LPWSTR szPropName = NULL;
  1570. VARIANT * pvVar = &varIndex;
  1571. //
  1572. // retrieve data object from cache; if one exis
  1573. //
  1574. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  1575. //
  1576. // The value is being passed in byref so we need to
  1577. // deref it for vbs stuff to work
  1578. //
  1579. pvVar = V_VARIANTREF(&varIndex);
  1580. }
  1581. switch (V_VT(pvVar)) {
  1582. case VT_BSTR:
  1583. //
  1584. // retrieve data object from cache; if one exists
  1585. //
  1586. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1587. hr = _pPropertyCache->unboundgetproperty(
  1588. V_BSTR(pvVar),
  1589. &dwSyntaxId,
  1590. &dwNumValues,
  1591. &pNdsSrcObjects
  1592. );
  1593. BAIL_ON_FAILURE(hr);
  1594. }else {
  1595. hr = _pPropertyCache->getproperty(
  1596. V_BSTR(pvVar),
  1597. &dwSyntaxId,
  1598. &dwNumValues,
  1599. &pNdsSrcObjects
  1600. );
  1601. BAIL_ON_FAILURE(hr);
  1602. }
  1603. hr = ConvertNdsValuesToVariant(
  1604. V_BSTR(pvVar),
  1605. pNdsSrcObjects,
  1606. dwSyntaxId,
  1607. dwNumValues,
  1608. pVariant
  1609. );
  1610. BAIL_ON_FAILURE(hr);
  1611. break;
  1612. case VT_I4:
  1613. hr = _pPropertyCache->unboundgetproperty(
  1614. V_I4(pvVar),
  1615. &dwSyntaxId,
  1616. &dwNumValues,
  1617. &pNdsSrcObjects
  1618. );
  1619. BAIL_ON_FAILURE(hr);
  1620. szPropName = _pPropertyCache->get_PropName(V_I4(pvVar));
  1621. hr = ConvertNdsValuesToVariant(
  1622. szPropName,
  1623. pNdsSrcObjects,
  1624. dwSyntaxId,
  1625. dwNumValues,
  1626. pVariant
  1627. );
  1628. BAIL_ON_FAILURE(hr);
  1629. break;
  1630. case VT_I2:
  1631. hr = _pPropertyCache->unboundgetproperty(
  1632. (DWORD)V_I2(pvVar),
  1633. &dwSyntaxId,
  1634. &dwNumValues,
  1635. &pNdsSrcObjects
  1636. );
  1637. BAIL_ON_FAILURE(hr);
  1638. szPropName = _pPropertyCache->get_PropName(V_I2(pvVar));
  1639. hr = ConvertNdsValuesToVariant(
  1640. szPropName,
  1641. pNdsSrcObjects,
  1642. dwSyntaxId,
  1643. dwNumValues,
  1644. pVariant
  1645. );
  1646. BAIL_ON_FAILURE(hr);
  1647. break;
  1648. default:
  1649. hr = E_FAIL;
  1650. BAIL_ON_FAILURE(hr);
  1651. }
  1652. error:
  1653. if (pNdsSrcObjects) {
  1654. NdsTypeFreeNdsObjects(
  1655. pNdsSrcObjects,
  1656. dwNumValues
  1657. );
  1658. }
  1659. RRETURN_EXP_IF_ERR(hr);
  1660. }
  1661. STDMETHODIMP
  1662. CNDSGenObject::PurgePropertyList()
  1663. {
  1664. _pPropertyCache->flushpropcache();
  1665. RRETURN(S_OK);
  1666. }
  1667. HRESULT
  1668. ConvertVariantToVariantArray(
  1669. VARIANT varData,
  1670. VARIANT ** ppVarArray,
  1671. DWORD * pdwNumValues
  1672. )
  1673. {
  1674. DWORD dwNumValues = 0;
  1675. VARIANT * pVarArray = NULL;
  1676. VARIANT * pVarData = NULL;
  1677. HRESULT hr = S_OK;
  1678. *ppVarArray = NULL;
  1679. *pdwNumValues = 0;
  1680. //
  1681. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1682. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1683. // what's inside.
  1684. //
  1685. pVarData = &varData;
  1686. if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) {
  1687. pVarData = V_VARIANTREF(&varData);
  1688. }
  1689. if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  1690. (V_VT(pVarData) == (VT_VARIANT|VT_ARRAY))) {
  1691. hr = ConvertSafeArrayToVariantArray(
  1692. *pVarData,
  1693. &pVarArray,
  1694. &dwNumValues
  1695. );
  1696. BAIL_ON_FAILURE(hr);
  1697. } else {
  1698. pVarArray = NULL;
  1699. dwNumValues = 0;
  1700. }
  1701. *ppVarArray = pVarArray;
  1702. *pdwNumValues = dwNumValues;
  1703. error:
  1704. RRETURN(hr);
  1705. }
  1706. void
  1707. FreeVariantArray(
  1708. VARIANT * pVarArray,
  1709. DWORD dwNumValues
  1710. )
  1711. {
  1712. if (pVarArray) {
  1713. DWORD i = 0;
  1714. for (i = 0; i < dwNumValues; i++) {
  1715. VariantClear(pVarArray + i);
  1716. }
  1717. FreeADsMem(pVarArray);
  1718. }
  1719. }
  1720. HRESULT
  1721. ConvertVariantToNdsValues(
  1722. VARIANT varData,
  1723. LPWSTR szPropertyName,
  1724. PDWORD pdwControlCode,
  1725. PNDSOBJECT * ppNdsDestObjects,
  1726. PDWORD pdwNumValues,
  1727. PDWORD pdwSyntaxId
  1728. )
  1729. {
  1730. HRESULT hr = S_OK;
  1731. IADsPropertyEntry * pPropEntry = NULL;
  1732. IDispatch * pDispatch = NULL;
  1733. BSTR bstrPropName = NULL;
  1734. DWORD dwControlCode = 0;
  1735. DWORD dwAdsType = 0;
  1736. VARIANT varValues;
  1737. VARIANT * pVarArray = NULL;
  1738. DWORD dwNumValues = 0;
  1739. PADSVALUE pAdsValues = NULL;
  1740. DWORD dwAdsValues = 0;
  1741. PNDSOBJECT pNdsDestObjects = 0;
  1742. DWORD dwNumNdsObjects = 0;
  1743. DWORD dwNdsSyntaxId = 0;
  1744. if (V_VT(&varData) != VT_DISPATCH) {
  1745. RRETURN (hr = DISP_E_TYPEMISMATCH);
  1746. }
  1747. pDispatch = V_DISPATCH(&varData);
  1748. hr = pDispatch->QueryInterface(
  1749. IID_IADsPropertyEntry,
  1750. (void **)&pPropEntry
  1751. );
  1752. BAIL_ON_FAILURE(hr);
  1753. VariantInit(&varValues);
  1754. VariantClear(&varValues);
  1755. hr = pPropEntry->get_Name(&bstrPropName);
  1756. BAIL_ON_FAILURE(hr);
  1757. wcscpy(szPropertyName, bstrPropName);
  1758. hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
  1759. BAIL_ON_FAILURE(hr);
  1760. *pdwControlCode = dwControlCode;
  1761. hr = pPropEntry->get_ADsType((long *)&dwAdsType);
  1762. BAIL_ON_FAILURE(hr);
  1763. hr = pPropEntry->get_Values(&varValues);
  1764. BAIL_ON_FAILURE(hr);
  1765. hr = ConvertVariantToVariantArray(
  1766. varValues,
  1767. &pVarArray,
  1768. &dwNumValues
  1769. );
  1770. BAIL_ON_FAILURE(hr);
  1771. if (dwNumValues) {
  1772. hr = PropVariantToAdsType(
  1773. pVarArray,
  1774. dwNumValues,
  1775. &pAdsValues,
  1776. &dwAdsValues
  1777. );
  1778. BAIL_ON_FAILURE(hr);
  1779. hr = AdsTypeToNdsTypeCopyConstruct(
  1780. pAdsValues,
  1781. dwAdsValues,
  1782. &pNdsDestObjects,
  1783. &dwNumNdsObjects,
  1784. &dwNdsSyntaxId
  1785. );
  1786. BAIL_ON_FAILURE(hr);
  1787. }
  1788. *ppNdsDestObjects = pNdsDestObjects;
  1789. *pdwNumValues = dwNumNdsObjects;
  1790. *pdwSyntaxId = dwNdsSyntaxId;
  1791. cleanup:
  1792. if (bstrPropName) {
  1793. ADsFreeString(bstrPropName);
  1794. }
  1795. if (pAdsValues) {
  1796. AdsFreeAdsValues(
  1797. pAdsValues,
  1798. dwNumValues
  1799. );
  1800. FreeADsMem( pAdsValues );
  1801. }
  1802. if (pVarArray) {
  1803. FreeVariantArray(
  1804. pVarArray,
  1805. dwAdsValues
  1806. );
  1807. }
  1808. if (pPropEntry) {
  1809. pPropEntry->Release();
  1810. }
  1811. VariantClear(&varValues);
  1812. RRETURN(hr);
  1813. error:
  1814. if (pNdsDestObjects) {
  1815. NdsTypeFreeNdsObjects(
  1816. pNdsDestObjects,
  1817. dwNumNdsObjects
  1818. );
  1819. }
  1820. *ppNdsDestObjects = NULL;
  1821. *pdwNumValues = 0;
  1822. goto cleanup;
  1823. }
  1824. HRESULT
  1825. ConvertNdsValuesToVariant(
  1826. BSTR bstrPropName,
  1827. LPNDSOBJECT pNdsSrcObjects,
  1828. DWORD dwSyntaxId,
  1829. DWORD dwNumValues,
  1830. PVARIANT pVarProp
  1831. )
  1832. {
  1833. HRESULT hr = S_OK;
  1834. PADSVALUE pAdsValues = NULL;
  1835. DWORD dwNumAdsValues = 0;
  1836. VARIANT varData;
  1837. IDispatch * pDispatch = NULL;
  1838. DWORD dwADsType = 0;
  1839. VariantInit(&varData);
  1840. VariantInit(pVarProp);
  1841. //
  1842. // translate the Nds objects to variants
  1843. //
  1844. hr = NdsTypeToAdsTypeCopyConstruct(
  1845. pNdsSrcObjects,
  1846. dwNumValues,
  1847. &pAdsValues
  1848. );
  1849. if (SUCCEEDED(hr)){
  1850. hr = AdsTypeToPropVariant(
  1851. pAdsValues,
  1852. dwNumValues,
  1853. &varData
  1854. );
  1855. if (SUCCEEDED(hr)) {
  1856. dwADsType = (dwSyntaxId >= g_cMapNdsTypeToADsType) ?
  1857. ADSTYPE_INVALID :
  1858. g_MapNdsTypeToADsType[dwSyntaxId];
  1859. }else {
  1860. VariantClear(&varData);
  1861. hr = S_OK;
  1862. }
  1863. }else {
  1864. VariantClear(&varData);
  1865. VariantInit(&varData);
  1866. hr = S_OK;
  1867. }
  1868. hr = CreatePropEntry(
  1869. bstrPropName,
  1870. dwADsType,
  1871. dwNumValues,
  1872. varData,
  1873. IID_IDispatch,
  1874. (void **)&pDispatch
  1875. );
  1876. BAIL_ON_FAILURE(hr);
  1877. V_DISPATCH(pVarProp) = pDispatch;
  1878. V_VT(pVarProp) = VT_DISPATCH;
  1879. error:
  1880. if (pAdsValues) {
  1881. AdsFreeAdsValues(
  1882. pAdsValues,
  1883. dwNumValues
  1884. );
  1885. FreeADsMem( pAdsValues );
  1886. }
  1887. VariantClear(&varData);
  1888. RRETURN(hr);
  1889. }