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.

1802 lines
61 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1992 - 1995
  6. //
  7. // File: cdssrch.cxx
  8. //
  9. // Contents: Microsoft ADs NDS Provider Generic Object
  10. //
  11. //
  12. // History: 03-02-97 ShankSh Created.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "nds.hxx"
  16. #pragma hdrstop
  17. const int NO_NDS_RESULT_HANDLES = 32;
  18. const int NO_UNCACHED_RESULTS_TO_KEEP = 3;
  19. static
  20. HRESULT
  21. NdsValueToADsColumn(
  22. LPWSTR pszColumnName,
  23. DWORD dwSyntaxId,
  24. DWORD dwValues,
  25. LPBYTE lpValue,
  26. ADS_SEARCH_COLUMN * pColumn
  27. );
  28. static
  29. HRESULT
  30. NdsValueToADsColumnAppend(
  31. DWORD dwSyntaxId,
  32. DWORD dwValues,
  33. LPBYTE lpObject,
  34. ADS_SEARCH_COLUMN * pColumn
  35. );
  36. //
  37. // Sets the appropriate search preferences.
  38. //
  39. HRESULT
  40. CNDSGenObject::SetSearchPreference(
  41. IN PADS_SEARCHPREF_INFO pSearchPrefs,
  42. IN DWORD dwNumPrefs
  43. )
  44. {
  45. HRESULT hr = S_OK;
  46. BOOL fWarning = FALSE;
  47. DWORD i;
  48. if (!pSearchPrefs && dwNumPrefs > 0) {
  49. RRETURN (E_ADS_BAD_PARAMETER);
  50. }
  51. for (i=0; i<dwNumPrefs; i++) {
  52. pSearchPrefs[i].dwStatus = ADS_STATUS_S_OK;
  53. switch(pSearchPrefs[i].dwSearchPref) {
  54. case ADS_SEARCHPREF_ASYNCHRONOUS:
  55. case ADS_SEARCHPREF_SIZE_LIMIT:
  56. case ADS_SEARCHPREF_TIME_LIMIT:
  57. case ADS_SEARCHPREF_TIMEOUT:
  58. case ADS_SEARCHPREF_PAGESIZE:
  59. case ADS_SEARCHPREF_PAGED_TIME_LIMIT:
  60. case ADS_SEARCHPREF_CHASE_REFERRALS:
  61. //
  62. // Can't be set
  63. //
  64. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  65. fWarning = TRUE;
  66. continue;
  67. case ADS_SEARCHPREF_DEREF_ALIASES:
  68. if (pSearchPrefs[i].vValue.dwType != ADSTYPE_INTEGER) {
  69. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  70. fWarning = TRUE;
  71. continue;
  72. }
  73. switch (pSearchPrefs[i].vValue.Integer) {
  74. case ADS_DEREF_NEVER:
  75. _SearchPref._fDerefAliases = FALSE;
  76. break;
  77. case ADS_DEREF_ALWAYS:
  78. _SearchPref._fDerefAliases = TRUE;
  79. break;
  80. default:
  81. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  82. fWarning = TRUE;
  83. continue;
  84. }
  85. break;
  86. case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
  87. if (pSearchPrefs[i].vValue.dwType != ADSTYPE_BOOLEAN) {
  88. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  89. fWarning = TRUE;
  90. continue;
  91. }
  92. _SearchPref._fAttrsOnly = pSearchPrefs[i].vValue.Boolean;
  93. break;
  94. case ADS_SEARCHPREF_CACHE_RESULTS:
  95. if (pSearchPrefs[i].vValue.dwType != ADSTYPE_BOOLEAN) {
  96. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  97. fWarning = TRUE;
  98. continue;
  99. }
  100. _SearchPref._fCacheResults = pSearchPrefs[i].vValue.Boolean;
  101. break;
  102. case ADS_SEARCHPREF_SEARCH_SCOPE:
  103. if (pSearchPrefs[i].vValue.dwType != ADSTYPE_INTEGER) {
  104. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  105. fWarning = TRUE;
  106. continue;
  107. }
  108. switch (pSearchPrefs[i].vValue.Integer) {
  109. case ADS_SCOPE_BASE:
  110. _SearchPref._dwSearchScope = DS_SEARCH_ENTRY;
  111. break;
  112. case ADS_SCOPE_ONELEVEL:
  113. _SearchPref._dwSearchScope = DS_SEARCH_SUBORDINATES;
  114. break;
  115. case ADS_SCOPE_SUBTREE:
  116. _SearchPref._dwSearchScope = DS_SEARCH_SUBTREE;
  117. break;
  118. default:
  119. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  120. fWarning = TRUE;
  121. continue;
  122. }
  123. break;
  124. default:
  125. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  126. fWarning = TRUE;
  127. continue;
  128. }
  129. }
  130. RRETURN (fWarning ? S_ADS_ERRORSOCCURRED : S_OK);
  131. }
  132. HRESULT
  133. CNDSGenObject::ExecuteSearch(
  134. IN LPWSTR pszSearchFilter,
  135. IN LPWSTR * pAttributeNames,
  136. IN DWORD dwNumberAttributes,
  137. OUT PADS_SEARCH_HANDLE phSearchHandle
  138. )
  139. {
  140. PNDS_SEARCHINFO phSearchInfo = NULL;
  141. LPWSTR szCurrAttr = NULL;
  142. DWORD dwAttrNamesLen = 0;
  143. HRESULT hr = S_OK;
  144. ULONG i, j;
  145. LPWSTR pszAttrNameBuffer = NULL, *ppszAttrs = NULL;
  146. if (!phSearchHandle) {
  147. RRETURN (E_ADS_BAD_PARAMETER);
  148. }
  149. //
  150. // Allocate search handle
  151. //
  152. phSearchInfo = (PNDS_SEARCHINFO) AllocADsMem(sizeof(NDS_SEARCHINFO));
  153. if(!phSearchInfo)
  154. BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
  155. hr = AdsNdsGenerateFilterBuffer(
  156. _hADsContext,
  157. pszSearchFilter,
  158. &phSearchInfo->_pFilterBuf
  159. );
  160. BAIL_ON_FAILURE(hr);
  161. phSearchInfo->_fADsPathPresent = FALSE;
  162. phSearchInfo->_fADsPathReturned = FALSE;
  163. if (dwNumberAttributes == -1) {
  164. //
  165. // Specifies returning all attributes
  166. //
  167. phSearchInfo->_ppszAttrs = NULL;
  168. phSearchInfo->_pszAttrNameBuffer = NULL;
  169. phSearchInfo->_fADsPathPresent = TRUE;
  170. phSearchInfo->_nAttrs = (DWORD) -1;
  171. }
  172. else {
  173. ppszAttrs = (LPWSTR *) AllocADsMem(
  174. sizeof(LPWSTR) *
  175. (dwNumberAttributes)
  176. );
  177. if (!ppszAttrs)
  178. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  179. for (i = 0; i < dwNumberAttributes; i++)
  180. dwAttrNamesLen+= (wcslen(pAttributeNames[i]) + 1) * sizeof(WCHAR);
  181. pszAttrNameBuffer = (LPWSTR) AllocADsMem(
  182. dwAttrNamesLen
  183. );
  184. if (!pszAttrNameBuffer)
  185. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  186. szCurrAttr = pszAttrNameBuffer;
  187. for (i = 0, j = 0; i < dwNumberAttributes; i++) {
  188. wcscpy(szCurrAttr, pAttributeNames[i]);
  189. ppszAttrs[j] = szCurrAttr;
  190. szCurrAttr += wcslen(ppszAttrs[j]) + 1;
  191. if(_wcsicmp(ppszAttrs[j], L"ADsPath") == 0) {
  192. //
  193. // ADsPath need not be sent
  194. //
  195. phSearchInfo->_fADsPathPresent = TRUE;
  196. }
  197. else {
  198. j++;
  199. }
  200. }
  201. phSearchInfo->_ppszAttrs = ppszAttrs;
  202. phSearchInfo->_nAttrs = j;
  203. phSearchInfo->_pszAttrNameBuffer = pszAttrNameBuffer;
  204. }
  205. phSearchInfo->_lIterationHandle = NO_MORE_ITERATIONS;
  206. phSearchInfo->_pSearchResults = NULL;
  207. phSearchInfo->_cSearchResults = 0;
  208. phSearchInfo->_dwCurrResult = 0;
  209. phSearchInfo->_cResultPrefetched = 0;
  210. phSearchInfo->_fCheckForDuplicates = TRUE;
  211. phSearchInfo->_dwCurrAttr = 0;
  212. phSearchInfo->_SearchPref = _SearchPref;
  213. *phSearchHandle = phSearchInfo;
  214. RRETURN(S_OK);
  215. error:
  216. if(phSearchInfo) {
  217. if(phSearchInfo->_ppszAttrs)
  218. FreeADsMem(phSearchInfo->_ppszAttrs);
  219. if(phSearchInfo->_pszAttrNameBuffer)
  220. FreeADsMem(phSearchInfo->_pszAttrNameBuffer);
  221. FreeADsMem(phSearchInfo);
  222. }
  223. RRETURN (hr);
  224. }
  225. HRESULT
  226. CNDSGenObject::AbandonSearch(
  227. IN ADS_SEARCH_HANDLE hSearchHandle
  228. )
  229. {
  230. RRETURN(E_NOTIMPL);
  231. }
  232. HRESULT
  233. CNDSGenObject::CloseSearchHandle (
  234. IN ADS_SEARCH_HANDLE hSearchHandle
  235. )
  236. {
  237. HRESULT hr = S_OK;
  238. PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
  239. if (!phSearchInfo)
  240. RRETURN (E_ADS_BAD_PARAMETER);
  241. if (phSearchInfo->_pFilterBuf) {
  242. ADsNdsFreeBuffer(phSearchInfo->_pFilterBuf);
  243. }
  244. if(phSearchInfo->_ppszAttrs)
  245. FreeADsMem(phSearchInfo->_ppszAttrs);
  246. if(phSearchInfo->_pszAttrNameBuffer)
  247. FreeADsMem(phSearchInfo->_pszAttrNameBuffer);
  248. if (phSearchInfo->_pSearchResults) {
  249. for (DWORD i=0; i < phSearchInfo->_cSearchResults; i++) {
  250. // If we're not caching all results, these may already have been freed
  251. // and set to NULL, but this is okay --- ADsNdsFreeBuffer and
  252. // ADsNdsFreeNdsObjInfoList will catch this.
  253. ADsNdsFreeBuffer(phSearchInfo->_pSearchResults[i]._hSearchResult);
  254. ADsNdsFreeNdsObjInfoList(phSearchInfo->_pSearchResults[i]._pObjects,
  255. phSearchInfo->_pSearchResults[i]._dwObjects);
  256. }
  257. FreeADsMem(phSearchInfo->_pSearchResults);
  258. }
  259. FreeADsMem(phSearchInfo);
  260. RRETURN (hr);
  261. }
  262. HRESULT
  263. CNDSGenObject::GetFirstRow(
  264. IN ADS_SEARCH_HANDLE hSearchHandle
  265. )
  266. {
  267. RRETURN(E_NOTIMPL);
  268. }
  269. HRESULT
  270. CNDSGenObject::GetNextRow(
  271. IN ADS_SEARCH_HANDLE hSearchHandle
  272. )
  273. {
  274. HRESULT hr;
  275. DWORD dwStatus = NO_ERROR;
  276. PNDS_SEARCH_RESULT pResult, pNextResult, pEvictedResult;
  277. PADSNDS_OBJECT_INFO pObject, pNextObject;
  278. PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
  279. DWORD dwType;
  280. DWORD nObjectsSearched;
  281. DWORD i;
  282. if (!phSearchInfo) {
  283. RRETURN(E_ADS_BAD_PARAMETER);
  284. }
  285. if (phSearchInfo->_fCheckForDuplicates) {
  286. phSearchInfo->_dwCurrAttr = 0;
  287. }
  288. //
  289. // dwCurrResult indexes the location of the array where we have already got
  290. // information from. If it is < 0, it indicates that there is no information
  291. // in this searchinfo at all
  292. //
  293. if (phSearchInfo->_dwCurrResult < 0)
  294. RRETURN(S_ADS_NOMORE_ROWS);
  295. if (phSearchInfo->_pSearchResults) {
  296. pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  297. //
  298. // If next object is available in current result
  299. //
  300. if (pResult->_pObjects &&
  301. ((pResult->_dwObjectCurrent+1) < pResult->_dwObjects)) {
  302. pResult->_dwObjectCurrent++;
  303. RRETURN(S_OK);
  304. }
  305. if (pResult->_dwObjectCurrent+1 == pResult->_dwObjects &&
  306. (phSearchInfo->_cResultPrefetched > 0)) {
  307. pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult+1]);
  308. pNextResult->_dwObjectCurrent = 0;
  309. phSearchInfo->_cResultPrefetched--;
  310. //
  311. // If next object points to NULL, it means we have no objects in
  312. // the next row
  313. //
  314. if (!pNextResult->_pObjects)
  315. RRETURN(S_ADS_NOMORE_ROWS);
  316. if(phSearchInfo->_fCheckForDuplicates) {
  317. pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
  318. pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
  319. if (!_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
  320. //
  321. // Duplicates; Skip one more result
  322. //
  323. //if (pNextResult->_dwObjectCurrent+1 < pNextResult->_dwObjects)
  324. pNextResult->_dwObjectCurrent++;
  325. //else
  326. // RRETURN(S_ADS_NOMORE_ROWS);
  327. }
  328. }
  329. if( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects &&
  330. phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS) {
  331. RRETURN(S_ADS_NOMORE_ROWS);
  332. }
  333. else {
  334. //
  335. // We have successfully moved onto the next value in the array
  336. //
  337. phSearchInfo->_dwCurrResult++;
  338. if ( (phSearchInfo->_dwCurrResult >= NO_UNCACHED_RESULTS_TO_KEEP) &&
  339. !phSearchInfo->_SearchPref._fCacheResults ) {
  340. // Not caching --- evict the old result
  341. pEvictedResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-NO_UNCACHED_RESULTS_TO_KEEP]);
  342. ADsNdsFreeBuffer(pEvictedResult->_hSearchResult);
  343. ADsNdsFreeNdsObjInfoList(pEvictedResult->_pObjects, pEvictedResult->_dwObjects);
  344. pEvictedResult->_hSearchResult = NULL;
  345. pEvictedResult->_pObjects = NULL;
  346. pEvictedResult->_dwObjects = 0;
  347. pEvictedResult->_fInUse = FALSE;
  348. }
  349. if ( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects) {
  350. // phSearchInfo->_lIterationHandle != NO_MORE_ITERATIONS
  351. // We have incremented pNextResult->_dwObjectCurrent past the number
  352. // of objects in pNextResult, but there are more iterations left to go.
  353. // This can occur if there was exactly one object in pNextResult, that
  354. // object is a duplicate of the last object in pResult, and there are
  355. // more objects left to retrieve. (This same case can also occur later
  356. // in this function, after calling AdsNdsSearch to get a new result set,
  357. // and code was added there as well to handle it.)
  358. //
  359. // We make it look like we've exhausted the results in pNextResult (which
  360. // we have) and recursively get the next row to get the next
  361. // result set (which may either be prefetched or retrieved from the server
  362. // via AdsNdsSearch). Since _dwCurrResult has already been
  363. // incremented, our pNextResult will be the recursive call's pResult,
  364. // it will look like we've exhausted the objects in the result,
  365. // and it will fetch the next result.
  366. //
  367. // We do this here, after the cache eviction code, so that we evict the
  368. // _dwCurrentResult-NO_UNCACHED_RESULTS_TO_KEEP result before going on
  369. // to _dwCurrentResult+1
  370. pNextResult->_dwObjectCurrent = pNextResult->_dwObjects-1;
  371. RRETURN(GetNextRow(hSearchHandle));
  372. }
  373. else {
  374. // We haven't exhausted pNextResult, so we're done
  375. RRETURN(S_OK);
  376. }
  377. }
  378. }
  379. else if( pResult->_dwObjectCurrent+1 == pResult->_dwObjects &&
  380. phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS)
  381. RRETURN(S_ADS_NOMORE_ROWS);
  382. }
  383. if (!phSearchInfo->_pFilterBuf) {
  384. //
  385. // querynode not setup yet
  386. //
  387. RRETURN (E_FAIL);
  388. }
  389. if(!phSearchInfo->_pSearchResults) {
  390. //
  391. // Allocate an array of handles to Search Handles
  392. //
  393. phSearchInfo->_pSearchResults = (PNDS_SEARCH_RESULT) AllocADsMem(
  394. sizeof(NDS_SEARCH_RESULT) *
  395. NO_NDS_RESULT_HANDLES);
  396. if(!phSearchInfo->_pSearchResults) {
  397. hr = E_OUTOFMEMORY;
  398. goto error;
  399. }
  400. phSearchInfo->_dwCurrResult = 0;
  401. phSearchInfo->_cSearchResults = NO_NDS_RESULT_HANDLES;
  402. for (i=0; i < phSearchInfo->_cSearchResults; i++) {
  403. phSearchInfo->_pSearchResults[i]._fInUse = 0;
  404. phSearchInfo->_pSearchResults[i]._hSearchResult = NULL;
  405. phSearchInfo->_pSearchResults[i]._pObjects = NULL;
  406. phSearchInfo->_pSearchResults[i]._dwObjects = 0;
  407. }
  408. }
  409. else {
  410. phSearchInfo->_dwCurrResult++;
  411. if (phSearchInfo->_dwCurrResult >= (LONG) phSearchInfo->_cSearchResults) {
  412. //
  413. // Need to allocate more memory for handles
  414. //
  415. phSearchInfo->_pSearchResults = (PNDS_SEARCH_RESULT) ReallocADsMem(
  416. (void *) phSearchInfo->_pSearchResults,
  417. sizeof(NDS_SEARCH_RESULT) *
  418. phSearchInfo->_cSearchResults,
  419. sizeof(NDS_SEARCH_RESULT) *
  420. (phSearchInfo->_cSearchResults +
  421. NO_NDS_RESULT_HANDLES)
  422. );
  423. if(!phSearchInfo->_pSearchResults) {
  424. hr = E_OUTOFMEMORY;
  425. goto error;
  426. }
  427. for (i=phSearchInfo->_cSearchResults; i < phSearchInfo->_cSearchResults + NO_NDS_RESULT_HANDLES; i++) {
  428. phSearchInfo->_pSearchResults[i]._fInUse = 0;
  429. phSearchInfo->_pSearchResults[i]._hSearchResult = NULL;
  430. phSearchInfo->_pSearchResults[i]._pObjects = NULL;
  431. phSearchInfo->_pSearchResults[i]._dwObjects = 0;
  432. }
  433. phSearchInfo->_cSearchResults += NO_NDS_RESULT_HANDLES;
  434. }
  435. }
  436. pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  437. ADsNdsFreeNdsObjInfoList(pNextResult->_pObjects, pNextResult->_dwObjects);
  438. pNextResult->_dwObjects = 0;
  439. pNextResult->_pObjects = NULL;
  440. pNextResult->_dwObjectCurrent = 0;
  441. pNextResult->_hSearchResult = NULL;
  442. pNextResult->_fInUse = TRUE;
  443. hr = ADsNdsSearch(
  444. _hADsContext,
  445. _pszNDSDn,
  446. _SearchPref._dwSearchScope,
  447. _SearchPref._fDerefAliases,
  448. phSearchInfo->_pFilterBuf,
  449. 0,
  450. _SearchPref._fAttrsOnly ?
  451. DS_ATTRIBUTE_NAMES : DS_ATTRIBUTE_VALUES,
  452. phSearchInfo->_ppszAttrs,
  453. phSearchInfo->_nAttrs,
  454. 0,
  455. &nObjectsSearched,
  456. &pNextResult->_hSearchResult,
  457. &phSearchInfo->_lIterationHandle
  458. );
  459. BAIL_ON_FAILURE(hr);
  460. hr = ADsNdsGetObjectListFromBuffer(
  461. _hADsContext,
  462. pNextResult->_hSearchResult,
  463. (PDWORD)&pNextResult->_dwObjects,
  464. &pNextResult->_pObjects
  465. );
  466. BAIL_ON_FAILURE(hr);
  467. if (pNextResult->_dwObjects > 0) {
  468. pNextResult->_dwObjectCurrent = 0;
  469. if(phSearchInfo->_fCheckForDuplicates && phSearchInfo->_dwCurrResult > 0) {
  470. pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-1]);
  471. pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
  472. pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
  473. if (!_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
  474. //
  475. // Duplicates; Skip one more result
  476. //
  477. pNextResult->_dwObjectCurrent++;
  478. }
  479. }
  480. if( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects &&
  481. phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS) {
  482. phSearchInfo->_dwCurrResult--;
  483. RRETURN(S_ADS_NOMORE_ROWS);
  484. }
  485. if ( !phSearchInfo->_SearchPref._fCacheResults &&
  486. (phSearchInfo->_dwCurrResult >= NO_UNCACHED_RESULTS_TO_KEEP) ) {
  487. // Not caching --- evict the old result
  488. pEvictedResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-NO_UNCACHED_RESULTS_TO_KEEP]);
  489. ADsNdsFreeBuffer(pEvictedResult->_hSearchResult);
  490. ADsNdsFreeNdsObjInfoList(pEvictedResult->_pObjects, pEvictedResult->_dwObjects);
  491. pEvictedResult->_hSearchResult = NULL;
  492. pEvictedResult->_pObjects = NULL;
  493. pEvictedResult->_dwObjects = 0;
  494. pEvictedResult->_fInUse = FALSE;
  495. }
  496. // Above, we test if we have incremented _dwObjectCurrent past the last
  497. // object in the result AND there are no more iterations. This would happen
  498. // if there is exactly one object in this result, and that object is a duplicate
  499. // of the last object in the previous result (i.e., the _wcsicmp above is executed
  500. // and returns 0), and there are no more results (no more iterations to go).
  501. //
  502. // But, suppose the above conditions are true, EXCEPT that there are still more
  503. // iterations to go. Then the above test wouldn't succeed, and we'd return with
  504. // _dwObjectCurrent == _dwObjects, an invalid condition.
  505. //
  506. // In this case, we've exhausted the result and must fetch the next one.
  507. // We do this by calling GetNextRow again. Since _dwCurrResult has already been
  508. // incremented, our pNextResult will be the recursive call's pResult, it will look
  509. // like we've exhausted the objects in the result, and it will fetch the next result.
  510. //
  511. // Note that we do this recursive call after the caching code so that we evict the
  512. // _dwCurrResult-NO_UNCACHED_RESULTS_TO_KEEP entry before going on to _dwCurrResult+1.
  513. if( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects) {
  514. // phSearchInfo->_lIterationHandle != NO_MORE_ITERATIONS
  515. pNextResult->_dwObjectCurrent = pNextResult->_dwObjects-1;
  516. RRETURN(GetNextRow(hSearchHandle));
  517. }
  518. RRETURN(S_OK);
  519. }
  520. else {
  521. phSearchInfo->_dwCurrResult--;
  522. RRETURN(S_ADS_NOMORE_ROWS);
  523. }
  524. error:
  525. RRETURN(hr);
  526. }
  527. HRESULT
  528. CNDSGenObject::GetPreviousRow(
  529. IN ADS_SEARCH_HANDLE hSearchHandle
  530. )
  531. {
  532. PNDS_SEARCH_RESULT pResult, pPrevResult;
  533. PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
  534. if(!phSearchInfo || !phSearchInfo->_pSearchResults)
  535. RRETURN(E_FAIL);
  536. if (phSearchInfo->_fCheckForDuplicates) {
  537. phSearchInfo->_dwCurrAttr = 0;
  538. }
  539. if (phSearchInfo->_dwCurrResult < 0)
  540. RRETURN(S_ADS_NOMORE_ROWS);
  541. pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  542. if (pResult->_dwObjectCurrent > 0)
  543. pResult->_dwObjectCurrent--;
  544. else if (phSearchInfo->_dwCurrResult > 0) {
  545. pPrevResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-1]);
  546. // Make sure the previous result hasn't been evicted from the cache
  547. if (!pPrevResult->_fInUse)
  548. RRETURN(S_ADS_NOMORE_ROWS);
  549. pPrevResult->_dwObjectCurrent = pPrevResult->_dwObjects-1;
  550. phSearchInfo->_cResultPrefetched++;
  551. phSearchInfo->_dwCurrResult--;
  552. // Check for duplicates
  553. if (phSearchInfo->_fCheckForDuplicates) {
  554. PADSNDS_OBJECT_INFO pObject, pPrevObject;
  555. pPrevObject = pPrevResult->_pObjects + pPrevResult->_dwObjectCurrent;
  556. pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
  557. if (!_wcsicmp(pPrevObject->szObjectName, pObject->szObjectName)) {
  558. // dupe
  559. RRETURN(GetPreviousRow(hSearchHandle));
  560. }
  561. }
  562. }
  563. else if(0 == pResult->_dwObjectCurrent)
  564. // we are at the very beginning of the result set
  565. pResult->_dwObjectCurrent--;
  566. else
  567. RRETURN(S_ADS_NOMORE_ROWS);
  568. RRETURN(S_OK);
  569. }
  570. HRESULT
  571. CNDSGenObject::GetColumn(
  572. IN ADS_SEARCH_HANDLE hSearchHandle,
  573. IN LPWSTR pszColumnName,
  574. OUT PADS_SEARCH_COLUMN pColumn
  575. )
  576. {
  577. HRESULT hr = S_OK;
  578. DWORD dwStatus;
  579. DWORD dwSyntaxId = 0;
  580. DWORD dwNumValues = 0;
  581. LPNDS_ATTR_INFO pAttribute;
  582. PNDS_SEARCH_RESULT pResult, pNextResult;
  583. PADSNDS_OBJECT_INFO pObject, pNextObject;
  584. DWORD cAttr;
  585. BOOL fRowAdvanced = FALSE;
  586. PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
  587. LPWSTR pszNDSDn = NULL;
  588. LPWSTR pszNDSTreeName = NULL;
  589. LPWSTR szADsPath = NULL;
  590. if( !pColumn ||
  591. !phSearchInfo ||
  592. !phSearchInfo->_pSearchResults )
  593. RRETURN (E_ADS_BAD_PARAMETER);
  594. pColumn->pszAttrName = NULL;
  595. pColumn->dwADsType = ADSTYPE_INVALID;
  596. pColumn->pADsValues = NULL;
  597. pColumn->dwNumValues = 0;
  598. pColumn->hReserved = NULL;
  599. if (phSearchInfo->_dwCurrResult < 0)
  600. RRETURN(S_ADS_NOMORE_ROWS);
  601. pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  602. if( pResult->_dwObjectCurrent < 0 )
  603. RRETURN (E_ADS_BAD_PARAMETER);
  604. if ((pResult->_dwObjects == 0) || (!pResult->_pObjects))
  605. RRETURN (S_ADS_NOMORE_COLUMNS);
  606. pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
  607. pColumn->pszAttrName = AllocADsStr(pszColumnName);
  608. if (!pColumn->pszAttrName)
  609. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  610. if(!_wcsicmp (pszColumnName, L"ADsPath")) {
  611. //
  612. // Build the ADsPathName
  613. //
  614. hr = BuildNDSPathFromADsPath2(
  615. _ADsPath,
  616. &pszNDSTreeName,
  617. &pszNDSDn
  618. );
  619. BAIL_ON_FAILURE(hr);
  620. hr = BuildADsPathFromNDSPath(
  621. pszNDSTreeName,
  622. pObject->szObjectName,
  623. &szADsPath
  624. );
  625. BAIL_ON_FAILURE(hr);
  626. if(*szADsPath) {
  627. pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE));
  628. if (!pColumn->pADsValues)
  629. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  630. pColumn->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
  631. pColumn->dwNumValues = 1;
  632. pColumn->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
  633. pColumn->pADsValues[0].CaseIgnoreString = AllocADsStr(szADsPath);
  634. if (!pColumn->pADsValues[0].CaseIgnoreString)
  635. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  636. pColumn->hReserved = pColumn->pADsValues[0].CaseIgnoreString;
  637. }
  638. if (szADsPath) {
  639. FreeADsMem(szADsPath);
  640. }
  641. if (pszNDSDn) {
  642. FreeADsMem(pszNDSDn);
  643. }
  644. if (pszNDSTreeName) {
  645. FreeADsMem(pszNDSTreeName);
  646. }
  647. RRETURN(S_OK);
  648. }
  649. if (phSearchInfo->_SearchPref._fAttrsOnly) {
  650. //
  651. // Only Names got. So, don't return any values
  652. //
  653. RRETURN (S_OK);
  654. }
  655. pAttribute = (LPNDS_ATTR_INFO)pObject->lpAttribute;
  656. for (cAttr=0;cAttr<pObject->dwNumAttributes;cAttr++,pAttribute++) {
  657. if (_wcsicmp(
  658. pAttribute->szAttributeName,
  659. pszColumnName
  660. ) == 0)
  661. break;
  662. }
  663. if (cAttr == pObject->dwNumAttributes) {
  664. if(pResult->_dwObjectCurrent+1 != pResult->_dwObjects ||
  665. (phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS &&
  666. (phSearchInfo->_cResultPrefetched == 0))) {
  667. //
  668. // No need to look in the next result set;
  669. //
  670. BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
  671. }
  672. else {
  673. //
  674. // There is a chance that the column may come in the next
  675. // result set. So, fetch the next set of results.
  676. //
  677. // Since this isn't actually the user causing the row to be advanced,
  678. // we don't want to do any cache evictions
  679. phSearchInfo->_fCheckForDuplicates = FALSE;
  680. BOOL fCurrentCachingStatus = phSearchInfo->_SearchPref._fCacheResults;
  681. phSearchInfo->_SearchPref._fCacheResults = TRUE;
  682. hr = GetNextRow(
  683. phSearchInfo
  684. );
  685. phSearchInfo->_fCheckForDuplicates = TRUE;
  686. phSearchInfo->_SearchPref._fCacheResults = fCurrentCachingStatus;
  687. BAIL_ON_FAILURE(hr);
  688. if (hr == S_ADS_NOMORE_ROWS) {
  689. BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
  690. }
  691. fRowAdvanced = TRUE;
  692. pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  693. pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
  694. if (_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
  695. //
  696. // No need to look in the next object;
  697. //
  698. BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
  699. }
  700. else {
  701. //
  702. // Look in the next object
  703. //
  704. pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute;
  705. for (cAttr=0;cAttr<pNextObject->dwNumAttributes;cAttr++,pAttribute++) {
  706. if (_wcsicmp(
  707. pAttribute->szAttributeName,
  708. pszColumnName
  709. ) == 0)
  710. break;
  711. }
  712. if (cAttr == pNextObject->dwNumAttributes) {
  713. //
  714. // Didn't find in the next result set containing the row too
  715. //
  716. BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
  717. }
  718. }
  719. }
  720. }
  721. hr = NdsValueToADsColumn(
  722. pszColumnName,
  723. pAttribute->dwSyntaxId,
  724. pAttribute->dwNumberOfValues,
  725. (LPBYTE) pAttribute->lpValue,
  726. pColumn
  727. );
  728. BAIL_ON_FAILURE(hr);
  729. //
  730. // Added in to support the case when one multivalue attribute is split into 2 packets. The
  731. // following case checks
  732. // 1) if we haven't advanced the row, if we have advanced already, the whole
  733. // Attribute will already be completely residing in the second packet
  734. // 2) the attribute was the last attribute from the last packet, thus
  735. // the next attribute, (the first attribute of the next row) might be
  736. // the same.
  737. //
  738. if ((!fRowAdvanced) &&
  739. (cAttr == (pObject->dwNumAttributes - 1))) {
  740. //
  741. // If there is indeed a need to try out an extra packet
  742. //
  743. if(pResult->_dwObjectCurrent+1 != pResult->_dwObjects ||
  744. (phSearchInfo->_lIterationHandle == NDS_NO_MORE_ITERATIONS &&
  745. (phSearchInfo->_cResultPrefetched == 0))) {
  746. //
  747. // No need to look in the next result set;
  748. //
  749. hr = S_OK;
  750. goto done;
  751. }
  752. else {
  753. //
  754. // There is a chance that the column may come in the next
  755. // result set. So, fetch the next set of results.
  756. //
  757. // Since this isn't actually the user causing the row to be advanced,
  758. // we don't want to do any cache evictions
  759. phSearchInfo->_fCheckForDuplicates = FALSE;
  760. BOOL fCurrentCachingStatus = phSearchInfo->_SearchPref._fCacheResults;
  761. phSearchInfo->_SearchPref._fCacheResults = TRUE;
  762. hr = GetNextRow(
  763. phSearchInfo
  764. );
  765. phSearchInfo->_fCheckForDuplicates = TRUE;
  766. phSearchInfo->_SearchPref._fCacheResults = fCurrentCachingStatus;
  767. BAIL_ON_FAILURE(hr);
  768. if (hr == S_ADS_NOMORE_ROWS) {
  769. hr = S_OK;
  770. goto done;
  771. }
  772. fRowAdvanced = TRUE;
  773. pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  774. pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
  775. if (_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
  776. //
  777. // No need to look in the next object, since objname is different
  778. //
  779. hr = S_OK;
  780. goto done;
  781. }
  782. else {
  783. //
  784. // Look in the next object, look for the same attribute
  785. //
  786. pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute;
  787. for (cAttr=0;cAttr<pNextObject->dwNumAttributes;cAttr++,pAttribute++) {
  788. if (_wcsicmp(
  789. pAttribute->szAttributeName,
  790. pszColumnName
  791. ) == 0)
  792. break;
  793. }
  794. if (cAttr == pNextObject->dwNumAttributes) {
  795. //
  796. // Didn't find in the next result set containing the row too
  797. //
  798. hr = S_OK;
  799. goto done;
  800. }
  801. }
  802. }
  803. //
  804. // If found, we'll append it to the last column
  805. //
  806. hr = NdsValueToADsColumnAppend(
  807. pAttribute->dwSyntaxId,
  808. pAttribute->dwNumberOfValues,
  809. (LPBYTE) pAttribute->lpValue,
  810. pColumn
  811. );
  812. BAIL_ON_FAILURE(hr);
  813. }
  814. done:
  815. if (fRowAdvanced) {
  816. phSearchInfo->_fCheckForDuplicates = FALSE;
  817. GetPreviousRow(phSearchInfo);
  818. phSearchInfo->_fCheckForDuplicates = TRUE;
  819. }
  820. if (szADsPath) {
  821. FreeADsMem(szADsPath);
  822. }
  823. if (pszNDSDn) {
  824. FreeADsMem(pszNDSDn);
  825. }
  826. if (pszNDSTreeName) {
  827. FreeADsMem(pszNDSTreeName);
  828. }
  829. RRETURN(S_OK);
  830. error:
  831. if (fRowAdvanced) {
  832. phSearchInfo->_fCheckForDuplicates = FALSE;
  833. GetPreviousRow(phSearchInfo);
  834. phSearchInfo->_fCheckForDuplicates = TRUE;
  835. }
  836. if (szADsPath) {
  837. FreeADsMem(szADsPath);
  838. }
  839. if (pszNDSDn) {
  840. FreeADsMem(pszNDSDn);
  841. }
  842. if (pszNDSTreeName) {
  843. FreeADsMem(pszNDSTreeName);
  844. }
  845. FreeColumn(pColumn);
  846. RRETURN (hr);
  847. }
  848. HRESULT
  849. CNDSGenObject::GetNextColumnName(
  850. IN ADS_SEARCH_HANDLE hSearchHandle,
  851. OUT LPWSTR * ppszColumnName
  852. )
  853. {
  854. HRESULT hr = S_OK;
  855. LPNDS_ATTR_INFO pAttribute;
  856. LPNDS_ATTR_INFO pAttributeOld = NULL;
  857. LPNDS_NAME_ONLY pNameOnlyAttr;
  858. PNDS_SEARCH_RESULT pResult, pNextResult;
  859. PADSNDS_OBJECT_INFO pObject, pNextObject;
  860. BOOL fRowAdvanced = FALSE;
  861. PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
  862. if( !phSearchInfo ||
  863. !phSearchInfo->_pSearchResults ||
  864. !ppszColumnName)
  865. RRETURN (E_ADS_BAD_PARAMETER);
  866. *ppszColumnName = NULL;
  867. if (phSearchInfo->_dwCurrResult < 0)
  868. RRETURN(S_ADS_NOMORE_ROWS);
  869. pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  870. if( pResult->_dwObjectCurrent < 0 )
  871. RRETURN (E_ADS_BAD_PARAMETER);
  872. if ((pResult->_dwObjects == 0) || (!pResult->_pObjects))
  873. RRETURN (S_ADS_NOMORE_COLUMNS);
  874. pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
  875. pNameOnlyAttr = (LPNDS_NAME_ONLY)pObject->lpAttribute +
  876. phSearchInfo->_dwCurrAttr;
  877. pAttribute = (LPNDS_ATTR_INFO)pObject->lpAttribute +
  878. phSearchInfo->_dwCurrAttr;
  879. //
  880. // Get the last attribute's name to test it to avoid getting duplicate
  881. // column names. This will happen if a multi-value got divided into two
  882. // packets. In that case, both attribute names would be the same.
  883. // We are only getting the last attribute if this object has greater than
  884. // 1 object, or else if this attribute is the first attribute, there would
  885. // not be a one before
  886. //
  887. if (phSearchInfo->_dwCurrAttr > 0) {
  888. pAttributeOld = pAttribute - 1;
  889. }
  890. if (phSearchInfo->_dwCurrAttr >= pObject->dwNumAttributes) {
  891. if(pResult->_dwObjectCurrent+1 != pResult->_dwObjects ||
  892. (phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS &&
  893. (phSearchInfo->_cResultPrefetched == 0))) {
  894. //
  895. // No need to look in the next result set;
  896. //
  897. hr = S_ADS_NOMORE_COLUMNS;
  898. goto error;
  899. }
  900. else {
  901. //
  902. // There is a chance that the column may come in the next
  903. // result set. So, fetch the next set of results.
  904. //
  905. // Since this isn't actually the user causing the row to be advanced,
  906. // we don't want to do any cache evictions
  907. phSearchInfo->_fCheckForDuplicates = FALSE;
  908. BOOL fCurrentCachingStatus = phSearchInfo->_SearchPref._fCacheResults;
  909. phSearchInfo->_SearchPref._fCacheResults = TRUE;
  910. hr = GetNextRow(
  911. phSearchInfo
  912. );
  913. phSearchInfo->_fCheckForDuplicates = TRUE;
  914. phSearchInfo->_SearchPref._fCacheResults = fCurrentCachingStatus;
  915. BAIL_ON_FAILURE(hr);
  916. if (hr == S_ADS_NOMORE_ROWS) {
  917. hr = S_ADS_NOMORE_COLUMNS;
  918. goto error;
  919. }
  920. fRowAdvanced = TRUE;
  921. pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  922. pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
  923. if (_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
  924. //
  925. // No need to look in the next object;
  926. //
  927. hr = S_ADS_NOMORE_COLUMNS;
  928. goto error;
  929. }
  930. else {
  931. //
  932. // Look in the next object
  933. //
  934. pNameOnlyAttr = (LPNDS_NAME_ONLY)pNextObject->lpAttribute +
  935. phSearchInfo->_dwCurrAttr -
  936. pObject->dwNumAttributes;
  937. pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute +
  938. phSearchInfo->_dwCurrAttr -
  939. pObject->dwNumAttributes;
  940. //
  941. // If the new attribute is after the first attribute in the new object,
  942. // we'll reset AttributeOld to point to the attribute before this.
  943. // Because the old attribute will be the one before the current one
  944. // in this case.
  945. //
  946. if ((phSearchInfo->_dwCurrAttr - pObject->dwNumAttributes) > 0) {
  947. pAttributeOld = pAttribute - 1;
  948. }
  949. if (phSearchInfo->_dwCurrAttr >= (pObject->dwNumAttributes +
  950. pNextObject->dwNumAttributes)) {
  951. //
  952. // Didn't find in the next result set
  953. // containing the row too
  954. //
  955. hr = S_ADS_NOMORE_COLUMNS;
  956. goto error;
  957. }
  958. //
  959. // If it is a duplicate column, go on to the next one
  960. //
  961. if (pAttributeOld) {
  962. if(wcscmp(pAttribute->szAttributeName,
  963. pAttributeOld->szAttributeName) == 0) {
  964. phSearchInfo->_dwCurrAttr++;
  965. if (phSearchInfo->_dwCurrAttr >= (pObject->dwNumAttributes +
  966. pNextObject->dwNumAttributes)) {
  967. //
  968. // Didn't find in the next result set
  969. // containing the row too
  970. //
  971. hr = S_ADS_NOMORE_COLUMNS;
  972. goto error;
  973. }
  974. pNameOnlyAttr = (LPNDS_NAME_ONLY)pNextObject->lpAttribute +
  975. phSearchInfo->_dwCurrAttr -
  976. pObject->dwNumAttributes;
  977. pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute +
  978. phSearchInfo->_dwCurrAttr -
  979. pObject->dwNumAttributes;
  980. }
  981. }
  982. }
  983. }
  984. }
  985. if (phSearchInfo->_SearchPref._fAttrsOnly)
  986. *ppszColumnName = AllocADsStr(
  987. pNameOnlyAttr->szName
  988. );
  989. else
  990. *ppszColumnName = AllocADsStr(
  991. pAttribute->szAttributeName
  992. );
  993. phSearchInfo->_dwCurrAttr++;
  994. if (fRowAdvanced) {
  995. phSearchInfo->_fCheckForDuplicates = FALSE;
  996. GetPreviousRow(phSearchInfo);
  997. phSearchInfo->_fCheckForDuplicates = TRUE;
  998. }
  999. RRETURN(S_OK);
  1000. error:
  1001. if (fRowAdvanced) {
  1002. phSearchInfo->_fCheckForDuplicates = FALSE;
  1003. GetPreviousRow(phSearchInfo);
  1004. phSearchInfo->_fCheckForDuplicates = TRUE;
  1005. }
  1006. if (*ppszColumnName)
  1007. FreeADsStr(*ppszColumnName);
  1008. if (hr == S_ADS_NOMORE_COLUMNS && phSearchInfo->_fADsPathPresent) {
  1009. //
  1010. // If ADsPath was specified, return it as the last column in the row
  1011. //
  1012. if (!phSearchInfo->_fADsPathReturned) {
  1013. *ppszColumnName = AllocADsStr(L"ADsPath");
  1014. phSearchInfo->_fADsPathReturned = TRUE;
  1015. hr = S_OK;
  1016. }
  1017. else {
  1018. //
  1019. // We need to reset it back so that we return it for the next
  1020. // row
  1021. //
  1022. phSearchInfo->_fADsPathReturned = FALSE;
  1023. hr = S_ADS_NOMORE_COLUMNS;
  1024. }
  1025. }
  1026. RRETURN (hr);
  1027. }
  1028. HRESULT
  1029. CNDSGenObject::FreeColumn(
  1030. IN PADS_SEARCH_COLUMN pColumn
  1031. )
  1032. {
  1033. HRESULT hr = S_OK;
  1034. if(!pColumn)
  1035. RRETURN (E_ADS_BAD_PARAMETER);
  1036. if (pColumn->pszAttrName)
  1037. FreeADsStr(pColumn->pszAttrName);
  1038. if (pColumn->pADsValues) {
  1039. AdsFreeAdsValues(pColumn->pADsValues, pColumn->dwNumValues);
  1040. FreeADsMem(pColumn->pADsValues);
  1041. }
  1042. RRETURN(hr);
  1043. }
  1044. HRESULT
  1045. NdsValueToADsColumn(
  1046. LPWSTR pszColumnName,
  1047. DWORD dwSyntaxId,
  1048. DWORD dwValues,
  1049. LPBYTE lpObject,
  1050. ADS_SEARCH_COLUMN * pColumn
  1051. )
  1052. {
  1053. HRESULT hr = S_OK;
  1054. LPNDS_ASN1_TYPE_1 lpNDS_ASN1_1;
  1055. LPNDS_ASN1_TYPE_7 lpNDS_ASN1_7;
  1056. LPNDS_ASN1_TYPE_8 lpNDS_ASN1_8;
  1057. LPNDS_ASN1_TYPE_9 lpNDS_ASN1_9;
  1058. LPNDS_ASN1_TYPE_11 lpNDS_ASN1_11;
  1059. LPNDS_ASN1_TYPE_14 lpNDS_ASN1_14;
  1060. LPNDS_ASN1_TYPE_18 lpNDS_ASN1_18;
  1061. LPNDS_ASN1_TYPE_20 lpNDS_ASN1_20;
  1062. LPNDS_ASN1_TYPE_24 lpNDS_ASN1_24;
  1063. DWORD i, j, dwValuesAllocated = 0;
  1064. LPBYTE lpValue = NULL;
  1065. PNDSOBJECT lpNdsObject = NULL;
  1066. if(!pszColumnName || !pColumn || !lpObject)
  1067. RRETURN(E_ADS_BAD_PARAMETER);
  1068. lpNdsObject = (PNDSOBJECT) lpObject;
  1069. pColumn->hReserved = NULL;
  1070. pColumn->dwNumValues = dwValues;
  1071. pColumn->pADsValues = (PADSVALUE) AllocADsMem(
  1072. sizeof(ADSVALUE) * dwValues
  1073. );
  1074. if (!pColumn->pADsValues)
  1075. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1076. if (dwSyntaxId >= g_cMapNdsTypeToADsType)
  1077. pColumn->dwADsType = ADSTYPE_INVALID;
  1078. else
  1079. pColumn->dwADsType = g_MapNdsTypeToADsType[dwSyntaxId];
  1080. switch (dwSyntaxId) {
  1081. // WIDE STRING
  1082. case NDS_SYNTAX_ID_1:
  1083. case NDS_SYNTAX_ID_2:
  1084. case NDS_SYNTAX_ID_3:
  1085. case NDS_SYNTAX_ID_4:
  1086. case NDS_SYNTAX_ID_5:
  1087. case NDS_SYNTAX_ID_10:
  1088. for (i=0; i < dwValues; i++) {
  1089. lpNDS_ASN1_1 = (LPNDS_ASN1_TYPE_1) &((lpNdsObject + i)->NdsValue);
  1090. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1091. pColumn->pADsValues[i].CaseIgnoreString = AllocADsStr(lpNDS_ASN1_1->DNString);
  1092. if (!(pColumn->pADsValues[i].CaseIgnoreString))
  1093. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1094. dwValuesAllocated++;
  1095. }
  1096. break;
  1097. case NDS_SYNTAX_ID_20:
  1098. for (i=0; i < dwValues; i++) {
  1099. lpNDS_ASN1_20 = (LPNDS_ASN1_TYPE_20) &((lpNdsObject + i)->NdsValue);
  1100. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1101. pColumn->pADsValues[i].ClassName = AllocADsStr(lpNDS_ASN1_20->ClassName);
  1102. if (!(pColumn->pADsValues[i].ClassName))
  1103. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1104. dwValuesAllocated++;
  1105. }
  1106. break;
  1107. // EMAIL
  1108. case NDS_SYNTAX_ID_14 :
  1109. for (i=0; i < dwValues; i++) {
  1110. lpNDS_ASN1_14 = (LPNDS_ASN1_TYPE_14) &((lpNdsObject + i)->NdsValue);
  1111. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1112. pColumn->pADsValues[i].Email.Address = AllocADsStr(lpNDS_ASN1_14->Address);
  1113. pColumn->pADsValues[i].Email.Type = lpNDS_ASN1_14->Type;
  1114. if (!(pColumn->pADsValues[i].Email.Address))
  1115. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1116. dwValuesAllocated++;
  1117. }
  1118. break;
  1119. // BYTE STREAM
  1120. case NDS_SYNTAX_ID_9:
  1121. for (i=0; i < dwValues; i++) {
  1122. lpNDS_ASN1_9 = (LPNDS_ASN1_TYPE_9) &((lpNdsObject + i)->NdsValue);
  1123. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1124. if (lpNDS_ASN1_9->Length)
  1125. {
  1126. LPBYTE lpByte = (LPBYTE)AllocADsMem(lpNDS_ASN1_9->Length);
  1127. if (!lpByte)
  1128. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1129. if (lpNDS_ASN1_9->OctetString)
  1130. memcpy(lpByte, lpNDS_ASN1_9->OctetString, lpNDS_ASN1_9->Length);
  1131. pColumn->pADsValues[i].OctetString.dwLength =lpNDS_ASN1_9->Length;
  1132. pColumn->pADsValues[i].OctetString.lpValue = lpByte;
  1133. }
  1134. else
  1135. {
  1136. pColumn->pADsValues[i].OctetString.dwLength = 0;
  1137. pColumn->pADsValues[i].OctetString.lpValue = NULL;
  1138. }
  1139. dwValuesAllocated++;
  1140. }
  1141. break;
  1142. // BOOLEAN
  1143. case NDS_SYNTAX_ID_7:
  1144. for (i=0; i < dwValues; i++) {
  1145. lpNDS_ASN1_7 = (LPNDS_ASN1_TYPE_7) &((lpNdsObject + i)->NdsValue);
  1146. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1147. pColumn->pADsValues[i].Boolean = lpNDS_ASN1_7->Boolean;
  1148. }
  1149. dwValuesAllocated = dwValues; // no intermediate failures possible
  1150. break;
  1151. // INTEGER
  1152. case NDS_SYNTAX_ID_8:
  1153. case NDS_SYNTAX_ID_22:
  1154. case NDS_SYNTAX_ID_27:
  1155. for (i=0; i < dwValues; i++) {
  1156. lpNDS_ASN1_8 = (LPNDS_ASN1_TYPE_8) &((lpNdsObject + i)->NdsValue);
  1157. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1158. pColumn->pADsValues[i].Integer = lpNDS_ASN1_8->Integer;
  1159. }
  1160. dwValuesAllocated = dwValues; // no intermediate failures possible
  1161. break;
  1162. // TIME
  1163. case NDS_SYNTAX_ID_24 :
  1164. for (i=0; i < dwValues; i++) {
  1165. lpNDS_ASN1_24 = (LPNDS_ASN1_TYPE_24) &((lpNdsObject + i)->NdsValue);
  1166. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1167. hr = ConvertDWORDtoSYSTEMTIME(
  1168. lpNDS_ASN1_24->Time,
  1169. &(pColumn->pADsValues[i].UTCTime)
  1170. );
  1171. BAIL_ON_FAILURE(hr);
  1172. dwValuesAllocated++;
  1173. }
  1174. break;
  1175. // FAX NUMBER
  1176. case NDS_SYNTAX_ID_11 :
  1177. for (i=0; i < dwValues; i++) {
  1178. lpNDS_ASN1_11 = (LPNDS_ASN1_TYPE_11) &((lpNdsObject + i)->NdsValue);
  1179. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1180. pColumn->pADsValues[i].pFaxNumber = (PADS_FAXNUMBER)AllocADsMem(sizeof(ADS_FAXNUMBER));
  1181. if (!pColumn->pADsValues[i].pFaxNumber) {
  1182. hr = E_OUTOFMEMORY;
  1183. BAIL_ON_FAILURE(hr);
  1184. }
  1185. pColumn->pADsValues[i].pFaxNumber->TelephoneNumber =
  1186. AllocADsStr(lpNDS_ASN1_11->TelephoneNumber);
  1187. if (!pColumn->pADsValues[i].pFaxNumber->TelephoneNumber) {
  1188. FreeADsMem(pColumn->pADsValues[i].pFaxNumber);
  1189. hr = E_OUTOFMEMORY;
  1190. BAIL_ON_FAILURE(hr);
  1191. }
  1192. hr = CopyOctetString(lpNDS_ASN1_11->NumberOfBits,
  1193. lpNDS_ASN1_11->Parameters,
  1194. &pColumn->pADsValues[i].pFaxNumber->NumberOfBits,
  1195. &pColumn->pADsValues[i].pFaxNumber->Parameters);
  1196. if (FAILED(hr)) {
  1197. FreeADsStr(pColumn->pADsValues[i].pFaxNumber->TelephoneNumber);
  1198. FreeADsMem(pColumn->pADsValues[i].pFaxNumber);
  1199. BAIL_ON_FAILURE(hr);
  1200. }
  1201. dwValuesAllocated++;
  1202. }
  1203. break;
  1204. // POSTAL ADDRESS
  1205. case NDS_SYNTAX_ID_18 :
  1206. for (i=0; i<dwValues; i++) {
  1207. lpNDS_ASN1_18 = (LPNDS_ASN1_TYPE_18) &((lpNdsObject + i)->NdsValue);
  1208. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1209. pColumn->pADsValues[i].pPostalAddress = (PADS_POSTALADDRESS)AllocADsMem(sizeof(ADS_POSTALADDRESS));
  1210. if (!pColumn->pADsValues[i].pPostalAddress) {
  1211. hr = E_OUTOFMEMORY;
  1212. BAIL_ON_FAILURE(hr);
  1213. }
  1214. for (j=0;j<6;j++) {
  1215. if (lpNDS_ASN1_18->PostalAddress[j]) {
  1216. pColumn->pADsValues[i].pPostalAddress->PostalAddress[j] =
  1217. AllocADsStr(
  1218. lpNDS_ASN1_18->PostalAddress[j]
  1219. );
  1220. }
  1221. else {
  1222. pColumn->pADsValues[i].pPostalAddress->PostalAddress[j] =
  1223. AllocADsStr(
  1224. L""
  1225. );
  1226. }
  1227. if (!pColumn->pADsValues[i].pPostalAddress->PostalAddress[j]) {
  1228. hr = E_OUTOFMEMORY;
  1229. while (j>0) {
  1230. FreeADsStr(pColumn->pADsValues[i].pPostalAddress->PostalAddress[j-1]);
  1231. j--;
  1232. }
  1233. FreeADsMem(pColumn->pADsValues[i].pPostalAddress);
  1234. BAIL_ON_FAILURE(hr);
  1235. }
  1236. }
  1237. dwValuesAllocated++;
  1238. }
  1239. break;
  1240. case NDS_SYNTAX_ID_6 :
  1241. case NDS_SYNTAX_ID_12 :
  1242. case NDS_SYNTAX_ID_13 :
  1243. case NDS_SYNTAX_ID_15 :
  1244. case NDS_SYNTAX_ID_16 :
  1245. case NDS_SYNTAX_ID_17 :
  1246. case NDS_SYNTAX_ID_19 :
  1247. case NDS_SYNTAX_ID_21 :
  1248. case NDS_SYNTAX_ID_23 :
  1249. case NDS_SYNTAX_ID_25 :
  1250. case NDS_SYNTAX_ID_26 :
  1251. default:
  1252. for (i=0; i < dwValues; i++) {
  1253. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1254. pColumn->pADsValues[i].ProviderSpecific.dwLength =0;
  1255. pColumn->pADsValues[i].ProviderSpecific.lpValue = NULL;
  1256. }
  1257. dwValuesAllocated = dwValues; // no intermediate failures possible
  1258. break;
  1259. }
  1260. RRETURN(hr);
  1261. error:
  1262. if (pColumn->pADsValues) {
  1263. AdsFreeAdsValues(pColumn->pADsValues, dwValuesAllocated);
  1264. FreeADsMem(pColumn->pADsValues);
  1265. pColumn->pADsValues = NULL;
  1266. pColumn->dwNumValues = 0;
  1267. }
  1268. RRETURN(hr);
  1269. }
  1270. HRESULT
  1271. NdsValueToADsColumnAppend(
  1272. DWORD dwSyntaxId,
  1273. DWORD dwValues,
  1274. LPBYTE lpObject,
  1275. ADS_SEARCH_COLUMN * pColumn
  1276. )
  1277. {
  1278. HRESULT hr = S_OK;
  1279. LPNDS_ASN1_TYPE_1 lpNDS_ASN1_1;
  1280. LPNDS_ASN1_TYPE_7 lpNDS_ASN1_7;
  1281. LPNDS_ASN1_TYPE_8 lpNDS_ASN1_8;
  1282. LPNDS_ASN1_TYPE_9 lpNDS_ASN1_9;
  1283. LPNDS_ASN1_TYPE_11 lpNDS_ASN1_11;
  1284. LPNDS_ASN1_TYPE_14 lpNDS_ASN1_14;
  1285. LPNDS_ASN1_TYPE_18 lpNDS_ASN1_18;
  1286. LPNDS_ASN1_TYPE_20 lpNDS_ASN1_20;
  1287. LPNDS_ASN1_TYPE_24 lpNDS_ASN1_24;
  1288. DWORD i, j, dwValuesAllocated;
  1289. PNDSOBJECT lpNdsObject = NULL;
  1290. PADSVALUE pADsValuesNew = NULL;
  1291. DWORD dwValuesBase;
  1292. if(!pColumn || !lpObject)
  1293. RRETURN(E_ADS_BAD_PARAMETER);
  1294. dwValuesBase = pColumn->dwNumValues;
  1295. dwValuesAllocated = pColumn->dwNumValues;
  1296. lpNdsObject = (PNDSOBJECT) lpObject;
  1297. //
  1298. // Allocate memory for new values + old values
  1299. //
  1300. pADsValuesNew = (PADSVALUE) AllocADsMem(
  1301. sizeof(ADSVALUE) * (pColumn->dwNumValues + dwValues)
  1302. );
  1303. if (!pADsValuesNew) {
  1304. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1305. }
  1306. //
  1307. // Copy old values into new array, and free the old one
  1308. //
  1309. memcpy(pADsValuesNew,
  1310. pColumn->pADsValues,
  1311. sizeof(ADSVALUE) * dwValuesBase);
  1312. FreeADsMem(pColumn->pADsValues);
  1313. pColumn->pADsValues = pADsValuesNew;
  1314. switch (dwSyntaxId) {
  1315. // WIDE STRING
  1316. case NDS_SYNTAX_ID_1:
  1317. case NDS_SYNTAX_ID_2:
  1318. case NDS_SYNTAX_ID_3:
  1319. case NDS_SYNTAX_ID_4:
  1320. case NDS_SYNTAX_ID_5:
  1321. case NDS_SYNTAX_ID_10:
  1322. for (i=0; i < dwValues; i++) {
  1323. lpNDS_ASN1_1 = (LPNDS_ASN1_TYPE_1) &((lpNdsObject + i)->NdsValue);
  1324. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1325. pColumn->pADsValues[dwValuesBase+i].CaseIgnoreString = AllocADsStr(lpNDS_ASN1_1->DNString);
  1326. if (!(pColumn->pADsValues[dwValuesBase+i].CaseIgnoreString))
  1327. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1328. dwValuesAllocated++;
  1329. }
  1330. break;
  1331. case NDS_SYNTAX_ID_20:
  1332. for (i=0; i < dwValues; i++) {
  1333. lpNDS_ASN1_20 = (LPNDS_ASN1_TYPE_20) &((lpNdsObject + i)->NdsValue);
  1334. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1335. pColumn->pADsValues[dwValuesBase+i].ClassName = AllocADsStr(lpNDS_ASN1_20->ClassName);
  1336. if (!(pColumn->pADsValues[dwValuesBase+i].ClassName))
  1337. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1338. dwValuesAllocated++;
  1339. }
  1340. break;
  1341. // EMAIL
  1342. case NDS_SYNTAX_ID_14 :
  1343. for (i=0; i < dwValues; i++) {
  1344. lpNDS_ASN1_14 = (LPNDS_ASN1_TYPE_14) &((lpNdsObject + i)->NdsValue);
  1345. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1346. pColumn->pADsValues[dwValuesBase+i].Email.Address = AllocADsStr(lpNDS_ASN1_14->Address);
  1347. pColumn->pADsValues[dwValuesBase+i].Email.Type = lpNDS_ASN1_14->Type;
  1348. if (!(pColumn->pADsValues[dwValuesBase+i].Email.Address))
  1349. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1350. dwValuesAllocated++;
  1351. }
  1352. break;
  1353. // BYTE STREAM
  1354. case NDS_SYNTAX_ID_9:
  1355. for (i=0; i < dwValues; i++) {
  1356. lpNDS_ASN1_9 = (LPNDS_ASN1_TYPE_9) &((lpNdsObject + i)->NdsValue);
  1357. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1358. if (lpNDS_ASN1_9->Length)
  1359. {
  1360. LPBYTE lpByte = (LPBYTE)AllocADsMem(lpNDS_ASN1_9->Length);
  1361. if (!lpByte)
  1362. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1363. if (lpNDS_ASN1_9->OctetString)
  1364. memcpy(lpByte, lpNDS_ASN1_9->OctetString, lpNDS_ASN1_9->Length);
  1365. pColumn->pADsValues[dwValuesBase+i].OctetString.dwLength =lpNDS_ASN1_9->Length;
  1366. pColumn->pADsValues[dwValuesBase+i].OctetString.lpValue = lpByte;
  1367. }
  1368. else
  1369. {
  1370. pColumn->pADsValues[dwValuesBase+i].OctetString.dwLength = 0;
  1371. pColumn->pADsValues[dwValuesBase+i].OctetString.lpValue = NULL;
  1372. }
  1373. dwValuesAllocated++;
  1374. }
  1375. break;
  1376. // BOOLEAN
  1377. case NDS_SYNTAX_ID_7:
  1378. for (i=0; i < dwValues; i++) {
  1379. lpNDS_ASN1_7 = (LPNDS_ASN1_TYPE_7) &((lpNdsObject + i)->NdsValue);
  1380. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1381. pColumn->pADsValues[dwValuesBase+i].Boolean = lpNDS_ASN1_7->Boolean;
  1382. }
  1383. dwValuesAllocated += dwValues; // no intermediate failures possible
  1384. break;
  1385. // INTEGER
  1386. case NDS_SYNTAX_ID_8:
  1387. case NDS_SYNTAX_ID_22:
  1388. case NDS_SYNTAX_ID_27:
  1389. for (i=0; i < dwValues; i++) {
  1390. lpNDS_ASN1_8 = (LPNDS_ASN1_TYPE_8) &((lpNdsObject + i)->NdsValue);
  1391. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1392. pColumn->pADsValues[dwValuesBase+i].Integer = lpNDS_ASN1_8->Integer;
  1393. }
  1394. dwValuesAllocated += dwValues; // no intermediate failures possible
  1395. break;
  1396. // TIME
  1397. case NDS_SYNTAX_ID_24 :
  1398. for (i=0; i < dwValues; i++) {
  1399. lpNDS_ASN1_24 = (LPNDS_ASN1_TYPE_24) &((lpNdsObject + i)->NdsValue);
  1400. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  1401. hr = ConvertDWORDtoSYSTEMTIME(
  1402. lpNDS_ASN1_24->Time,
  1403. &(pColumn->pADsValues[dwValuesBase+i].UTCTime)
  1404. );
  1405. BAIL_ON_FAILURE(hr);
  1406. dwValuesAllocated++;
  1407. }
  1408. break;
  1409. // FAX NUMBER
  1410. case NDS_SYNTAX_ID_11 :
  1411. for (i=0; i < dwValues; i++) {
  1412. lpNDS_ASN1_11 = (LPNDS_ASN1_TYPE_11) &((lpNdsObject + i)->NdsValue);
  1413. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1414. pColumn->pADsValues[dwValuesBase+i].pFaxNumber = (PADS_FAXNUMBER)AllocADsMem(sizeof(ADS_FAXNUMBER));
  1415. if (!pColumn->pADsValues[dwValuesBase+i].pFaxNumber) {
  1416. hr = E_OUTOFMEMORY;
  1417. BAIL_ON_FAILURE(hr);
  1418. }
  1419. pColumn->pADsValues[dwValuesBase+i].pFaxNumber->TelephoneNumber =
  1420. AllocADsStr(lpNDS_ASN1_11->TelephoneNumber);
  1421. if (!pColumn->pADsValues[dwValuesBase+i].pFaxNumber->TelephoneNumber) {
  1422. FreeADsMem(pColumn->pADsValues[dwValuesBase+i].pFaxNumber);
  1423. hr = E_OUTOFMEMORY;
  1424. BAIL_ON_FAILURE(hr);
  1425. }
  1426. hr = CopyOctetString(lpNDS_ASN1_11->NumberOfBits,
  1427. lpNDS_ASN1_11->Parameters,
  1428. &pColumn->pADsValues[dwValuesBase+i].pFaxNumber->NumberOfBits,
  1429. &pColumn->pADsValues[dwValuesBase+i].pFaxNumber->Parameters);
  1430. if (FAILED(hr)) {
  1431. FreeADsStr(pColumn->pADsValues[dwValuesBase+i].pFaxNumber->TelephoneNumber);
  1432. FreeADsMem(pColumn->pADsValues[dwValuesBase+i].pFaxNumber);
  1433. BAIL_ON_FAILURE(hr);
  1434. }
  1435. dwValuesAllocated++;
  1436. }
  1437. break;
  1438. // POSTAL ADDRESS
  1439. case NDS_SYNTAX_ID_18 :
  1440. for (i=0; i<dwValues; i++) {
  1441. lpNDS_ASN1_18 = (LPNDS_ASN1_TYPE_18) &((lpNdsObject + i)->NdsValue);
  1442. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1443. pColumn->pADsValues[dwValuesBase+i].pPostalAddress = (PADS_POSTALADDRESS)AllocADsMem(sizeof(ADS_POSTALADDRESS));
  1444. if (!pColumn->pADsValues[dwValuesBase+i].pPostalAddress) {
  1445. hr = E_OUTOFMEMORY;
  1446. BAIL_ON_FAILURE(hr);
  1447. }
  1448. for (j=0;j<6;j++) {
  1449. if (lpNDS_ASN1_18->PostalAddress[j]) {
  1450. pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j] =
  1451. AllocADsStr(
  1452. lpNDS_ASN1_18->PostalAddress[j]
  1453. );
  1454. }
  1455. else {
  1456. pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j] =
  1457. AllocADsStr(
  1458. L""
  1459. );
  1460. }
  1461. if (!pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j]) {
  1462. hr = E_OUTOFMEMORY;
  1463. while (j>0) {
  1464. FreeADsStr(pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j-1]);
  1465. j--;
  1466. }
  1467. FreeADsMem(pColumn->pADsValues[dwValuesBase+i].pPostalAddress);
  1468. BAIL_ON_FAILURE(hr);
  1469. }
  1470. }
  1471. dwValuesAllocated++;
  1472. }
  1473. break;
  1474. case NDS_SYNTAX_ID_6 :
  1475. case NDS_SYNTAX_ID_12 :
  1476. case NDS_SYNTAX_ID_13 :
  1477. case NDS_SYNTAX_ID_15 :
  1478. case NDS_SYNTAX_ID_16 :
  1479. case NDS_SYNTAX_ID_17 :
  1480. case NDS_SYNTAX_ID_19 :
  1481. case NDS_SYNTAX_ID_21 :
  1482. case NDS_SYNTAX_ID_23 :
  1483. case NDS_SYNTAX_ID_25 :
  1484. case NDS_SYNTAX_ID_26 :
  1485. default:
  1486. for (i=0; i < dwValues; i++) {
  1487. pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
  1488. pColumn->pADsValues[dwValuesBase+i].ProviderSpecific.dwLength =0;
  1489. pColumn->pADsValues[dwValuesBase+i].ProviderSpecific.lpValue = NULL;
  1490. }
  1491. dwValuesAllocated += dwValues;
  1492. break;
  1493. }
  1494. pColumn->dwNumValues = pColumn->dwNumValues + dwValues;
  1495. RRETURN(hr);
  1496. error:
  1497. if (pColumn->pADsValues) {
  1498. AdsFreeAdsValues(pColumn->pADsValues, dwValuesAllocated);
  1499. FreeADsMem(pColumn->pADsValues);
  1500. pColumn->pADsValues = NULL;
  1501. pColumn->dwNumValues = 0;
  1502. }
  1503. RRETURN(hr);
  1504. }