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.

2278 lines
44 KiB

  1. #include "nwcompat.hxx"
  2. #pragma hdrstop
  3. FILTERS Filters[] = {
  4. {L"computer", NWCOMPAT_COMPUTER_ID},
  5. {L"user", NWCOMPAT_USER_ID},
  6. {L"group", NWCOMPAT_GROUP_ID},
  7. {L"service", NWCOMPAT_SERVICE_ID},
  8. {L"printqueue", NWCOMPAT_PRINTER_ID},
  9. {L"fileshare", NWCOMPAT_FILESHARE_ID},
  10. {L"class", NWCOMPAT_CLASS_ID},
  11. {L"syntax", NWCOMPAT_SYNTAX_ID},
  12. {L"property", NWCOMPAT_PROPERTY_ID}
  13. };
  14. #define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS))
  15. HRESULT
  16. CreatePropEntry(
  17. LPWSTR szPropName,
  18. ADSTYPE dwADsType,
  19. VARIANT varData,
  20. REFIID riid,
  21. LPVOID * ppDispatch
  22. );
  23. PFILTERS gpFilters = Filters;
  24. DWORD gdwMaxFilters = MAX_FILTERS;
  25. extern WCHAR * szProviderName;
  26. //+------------------------------------------------------------------------
  27. //
  28. // Class: Common
  29. //
  30. // Purpose: Contains NWCOMPAT routines and properties that are common to
  31. // all NWCOMPAT objects. NWCOMPAT objects get the routines and
  32. // properties through C++ inheritance.
  33. //
  34. //-------------------------------------------------------------------------
  35. HRESULT
  36. MakeUncName(
  37. LPWSTR szSrcBuffer,
  38. LPWSTR szTargBuffer
  39. )
  40. {
  41. ADsAssert(szSrcBuffer && *szSrcBuffer);
  42. wcscpy(szTargBuffer, L"\\\\");
  43. wcscat(szTargBuffer, szSrcBuffer);
  44. RRETURN(S_OK);
  45. }
  46. HRESULT
  47. ValidateOutParameter(
  48. BSTR * retval
  49. )
  50. {
  51. if (!retval) {
  52. RRETURN(E_ADS_BAD_PARAMETER);
  53. }
  54. RRETURN(S_OK);
  55. }
  56. HRESULT
  57. BuildADsPath(
  58. BSTR Parent,
  59. BSTR Name,
  60. BSTR *pADsPath
  61. )
  62. {
  63. WCHAR ADsPath[MAX_PATH];
  64. WCHAR ProviderName[MAX_PATH];
  65. HRESULT hr = S_OK;
  66. LPWSTR pszDisplayName = NULL;
  67. //
  68. // We will assert if bad parameters are passed to us.
  69. // This is because this should never be the case. This
  70. // is an internal call
  71. //
  72. ADsAssert(Parent && Name);
  73. ADsAssert(pADsPath);
  74. hr = GetDisplayName(
  75. Name,
  76. &pszDisplayName
  77. );
  78. BAIL_ON_FAILURE(hr);
  79. //
  80. // Special case the Namespace object; if
  81. // the parent is L"ADs:", then Name = ADsPath
  82. //
  83. if (!_wcsicmp(Parent, L"ADs:")) {
  84. hr = ADsAllocString(Name, pADsPath);
  85. BAIL_ON_FAILURE(hr);
  86. goto cleanup;
  87. }
  88. //
  89. // The rest of the cases we expect valid data,
  90. // Path, Parent and Name are read-only, the end-user
  91. // cannot modify this data
  92. //
  93. //
  94. // For the first object, the domain object we do not add
  95. // the first backslash; so we examine that the parent is
  96. // L"NWCOMPAT:" and skip the slash otherwise we start with
  97. // the slash
  98. //
  99. wsprintf(ProviderName, L"%s:", szProviderName);
  100. wcscpy(ADsPath, Parent);
  101. if (_wcsicmp(ADsPath, ProviderName)) {
  102. wcscat(ADsPath, L"/");
  103. }
  104. else {
  105. wcscat(ADsPath, L"//");
  106. }
  107. wcscat(ADsPath, Name);
  108. hr = ADsAllocString(ADsPath, pADsPath);
  109. cleanup:
  110. error:
  111. if (pszDisplayName) {
  112. FreeADsMem(pszDisplayName);
  113. }
  114. RRETURN(hr);
  115. }
  116. HRESULT
  117. BuildSchemaPath(
  118. BSTR Parent,
  119. BSTR Name,
  120. BSTR Schema,
  121. BSTR *pSchemaPath
  122. )
  123. {
  124. WCHAR SchemaPath[MAX_PATH];
  125. WCHAR ProviderName[MAX_PATH];
  126. HRESULT hr = S_OK;
  127. long i;
  128. OBJECTINFO ObjectInfo;
  129. POBJECTINFO pObjectInfo = &ObjectInfo;
  130. CLexer Lexer(Parent);
  131. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  132. //
  133. // We will assert if bad parameters are passed to us.
  134. // This is because this should never be the case. This
  135. // is an internal call
  136. //
  137. ADsAssert(Parent);
  138. ADsAssert(pSchemaPath);
  139. //
  140. // If no schema name is passed in, then there is no schema path
  141. //
  142. if ( Schema == NULL || *Schema == 0 ){
  143. RRETURN(ADsAllocString(L"", pSchemaPath));
  144. }
  145. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  146. hr = Object(&Lexer, pObjectInfo);
  147. BAIL_ON_FAILURE(hr);
  148. wsprintf(SchemaPath, L"%s://", szProviderName);
  149. if (!pObjectInfo->NumComponents) {
  150. wcscat(SchemaPath, Name);
  151. }else{
  152. wcscat(SchemaPath, pObjectInfo->DisplayComponentArray[0]);
  153. }
  154. wcscat( SchemaPath, L"/");
  155. wcscat( SchemaPath, SCHEMA_NAME );
  156. wcscat( SchemaPath, L"/");
  157. wcscat( SchemaPath, Schema );
  158. hr = ADsAllocString(SchemaPath, pSchemaPath);
  159. error:
  160. FreeObjectInfo( &ObjectInfo, TRUE );
  161. RRETURN(hr);
  162. }
  163. HRESULT
  164. BuildADsGuid(
  165. REFCLSID clsid,
  166. BSTR *pADsClass
  167. )
  168. {
  169. WCHAR ADsClass[MAX_PATH];
  170. if (!StringFromGUID2(clsid, ADsClass, MAX_PATH)) {
  171. //
  172. // MAX_PATH should be more than enough for the GUID.
  173. //
  174. ADsAssert(!"GUID too big !!!");
  175. RRETURN(E_FAIL);
  176. }
  177. RRETURN(ADsAllocString(ADsClass, pADsClass));
  178. }
  179. HRESULT
  180. BuildObjectInfo(
  181. BSTR ADsParent,
  182. BSTR Name,
  183. POBJECTINFO * ppObjectInfo
  184. )
  185. {
  186. WCHAR szBuffer[MAX_PATH];
  187. HRESULT hr;
  188. POBJECTINFO pObjectInfo = NULL;
  189. memset(szBuffer, 0, sizeof(szBuffer));
  190. wcscpy(szBuffer, ADsParent);
  191. wcscat(szBuffer, L"/");
  192. wcscat(szBuffer, Name);
  193. CLexer Lexer(szBuffer);
  194. pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
  195. if (!pObjectInfo) {
  196. hr = E_OUTOFMEMORY;
  197. BAIL_ON_FAILURE(hr);
  198. }
  199. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  200. hr = Object(&Lexer, pObjectInfo);
  201. BAIL_ON_FAILURE(hr);
  202. *ppObjectInfo = pObjectInfo;
  203. RRETURN(hr);
  204. error:
  205. if (pObjectInfo) {
  206. FreeObjectInfo(pObjectInfo);
  207. }
  208. *ppObjectInfo = NULL;
  209. RRETURN(hr);
  210. }
  211. HRESULT
  212. BuildObjectInfo(
  213. BSTR ADsPath,
  214. POBJECTINFO * ppObjectInfo
  215. )
  216. {
  217. HRESULT hr;
  218. POBJECTINFO pObjectInfo = NULL;
  219. CLexer Lexer(ADsPath);
  220. pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
  221. if (!pObjectInfo) {
  222. hr = E_OUTOFMEMORY;
  223. BAIL_ON_FAILURE(hr);
  224. }
  225. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  226. hr = Object(&Lexer, pObjectInfo);
  227. BAIL_ON_FAILURE(hr);
  228. *ppObjectInfo = pObjectInfo;
  229. RRETURN(hr);
  230. error:
  231. if (pObjectInfo) {
  232. FreeObjectInfo(pObjectInfo);
  233. }
  234. *ppObjectInfo = NULL;
  235. RRETURN(hr);
  236. }
  237. VOID
  238. FreeObjectInfo(
  239. POBJECTINFO pObjectInfo,
  240. BOOL fStatic
  241. )
  242. {
  243. DWORD i = 0;
  244. if (!pObjectInfo) {
  245. return;
  246. }
  247. FreeADsStr(pObjectInfo->ProviderName);
  248. for (i = 0; i < pObjectInfo->NumComponents; i++ ) {
  249. FreeADsStr(pObjectInfo->ComponentArray[i]);
  250. FreeADsStr(pObjectInfo->DisplayComponentArray[i]);
  251. }
  252. if ( !fStatic ) {
  253. FreeADsMem(pObjectInfo);
  254. }
  255. }
  256. HRESULT
  257. ValidateObject(
  258. DWORD dwObjectType,
  259. POBJECTINFO pObjectInfo
  260. )
  261. {
  262. switch (dwObjectType) {
  263. case NWCOMPAT_USER_ID:
  264. RRETURN(ValidateUserObject(pObjectInfo));
  265. case NWCOMPAT_GROUP_ID:
  266. RRETURN(ValidateGroupObject(pObjectInfo));
  267. case NWCOMPAT_PRINTER_ID:
  268. RRETURN(ValidatePrinterObject(pObjectInfo));
  269. default:
  270. RRETURN(E_FAIL);
  271. }
  272. }
  273. HRESULT
  274. GetObjectType(
  275. PFILTERS pFilters,
  276. DWORD dwMaxFilters,
  277. BSTR ClassName,
  278. PDWORD pdwObjectType
  279. )
  280. {
  281. DWORD i = 0;
  282. ADsAssert(pdwObjectType);
  283. for (i = 0; i < dwMaxFilters; i++) {
  284. if (!_wcsicmp(ClassName, (pFilters + i)->szObjectName)) {
  285. *pdwObjectType = (pFilters + i)->dwFilterId;
  286. RRETURN(S_OK);
  287. }
  288. }
  289. *pdwObjectType = 0;
  290. RRETURN(E_FAIL);
  291. }
  292. HRESULT
  293. ValidateProvider(
  294. POBJECTINFO pObjectInfo
  295. )
  296. {
  297. //
  298. // The provider name is case-sensitive. This is a restriction that OLE
  299. // has put on us.
  300. //
  301. if (!(wcscmp(pObjectInfo->ProviderName, szProviderName))) {
  302. RRETURN(S_OK);
  303. }
  304. RRETURN(E_FAIL);
  305. }
  306. HRESULT
  307. ConvertSystemTimeToDATE(
  308. SYSTEMTIME Time,
  309. DATE * pdaTime
  310. )
  311. {
  312. FILETIME ft;
  313. BOOL fRetval = FALSE;
  314. USHORT wDosDate;
  315. USHORT wDosTime;
  316. //
  317. // System Time To File Time.
  318. //
  319. fRetval = SystemTimeToFileTime(&Time,
  320. &ft);
  321. if(!fRetval){
  322. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  323. }
  324. //
  325. // File Time to DosDateTime.
  326. //
  327. fRetval = FileTimeToDosDateTime(&ft,
  328. &wDosDate,
  329. &wDosTime);
  330. if(!fRetval){
  331. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  332. }
  333. //
  334. // DosDateTime to VariantTime.
  335. //
  336. fRetval = DosDateTimeToVariantTime(wDosDate,
  337. wDosTime,
  338. pdaTime );
  339. if(!fRetval){
  340. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  341. }
  342. RRETURN(S_OK);
  343. }
  344. HRESULT
  345. ConvertDATEToSYSTEMTIME(
  346. DATE daDate,
  347. SYSTEMTIME *pSysTime
  348. )
  349. {
  350. HRESULT hr;
  351. FILETIME ft;
  352. BOOL fRetval = FALSE;
  353. USHORT wDosDate;
  354. USHORT wDosTime;
  355. fRetval = VariantTimeToDosDateTime(daDate,
  356. &wDosDate,
  357. &wDosTime );
  358. if(!fRetval){
  359. hr = HRESULT_FROM_WIN32(GetLastError());
  360. RRETURN(hr);
  361. }
  362. fRetval = DosDateTimeToFileTime(wDosDate,
  363. wDosTime,
  364. &ft);
  365. if(!fRetval){
  366. hr = HRESULT_FROM_WIN32(GetLastError());
  367. RRETURN(hr);
  368. }
  369. fRetval = FileTimeToSystemTime(&ft,
  370. pSysTime );
  371. if(!fRetval){
  372. hr = HRESULT_FROM_WIN32(GetLastError());
  373. RRETURN(hr);
  374. }
  375. RRETURN(S_OK);
  376. }
  377. HRESULT
  378. ConvertDATEToDWORD(
  379. DATE daDate,
  380. DWORD *pdwDate
  381. )
  382. {
  383. BOOL fBool = TRUE;
  384. WORD wDOSDate = 0;
  385. WORD wDOSTime = 0;
  386. WORD wHour = 0;
  387. WORD wMinute = 0;
  388. //
  389. // Break up Variant date.
  390. //
  391. fBool = VariantTimeToDosDateTime(
  392. (DOUBLE) daDate,
  393. &wDOSDate,
  394. &wDOSTime
  395. );
  396. if (fBool == FALSE) {
  397. goto error;
  398. }
  399. //
  400. // Convert DOS time into DWORD time which expresses time as the number of
  401. // minutes elapsed since mid-night.
  402. //
  403. wHour = wDOSTime >> 11;
  404. wMinute = (wDOSTime >> 5) - (wHour << 6);
  405. //
  406. // Return.
  407. //
  408. *pdwDate = wHour * 60 + wMinute;
  409. error:
  410. RRETURN(S_OK);
  411. }
  412. HRESULT
  413. ConvertDWORDToDATE(
  414. DWORD dwTime,
  415. DATE * pdaTime
  416. )
  417. {
  418. BOOL fBool = TRUE;
  419. DOUBLE vTime = 0;
  420. SYSTEMTIME SysTime = {1980,1,0,1,0,0,0,0};
  421. SYSTEMTIME LocalTime = {1980,1,0,1,0,0,0,0};
  422. WORD wDOSDate = 0;
  423. WORD wDOSTime = 0;
  424. WORD wHour = 0;
  425. WORD wMinute = 0;
  426. WORD wSecond = 0;
  427. //
  428. // Get Hour and Minute from DWORD.
  429. //
  430. SysTime.wHour = (WORD) (dwTime / 60);
  431. SysTime.wMinute = (WORD) (dwTime % 60);
  432. //
  433. // Get Time-zone specific local time.
  434. //
  435. fBool = SystemTimeToTzSpecificLocalTime(
  436. NULL,
  437. &SysTime,
  438. &LocalTime
  439. );
  440. if (fBool == FALSE) {
  441. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  442. }
  443. wHour = LocalTime.wHour;
  444. wMinute = LocalTime.wMinute;
  445. wSecond = LocalTime.wSecond;
  446. //
  447. // Set a dummy date.
  448. //
  449. wDOSDate = DATE_1980_JAN_1;
  450. //
  451. // Shift data to correct bit as required by the DOS date & time format.
  452. //
  453. wHour = wHour << 11;
  454. wMinute = wMinute << 5;
  455. //
  456. // Put them in DOS format.
  457. //
  458. wDOSTime = wHour | wMinute | wSecond;
  459. //
  460. // Convert into VariantTime.
  461. //
  462. fBool = DosDateTimeToVariantTime(
  463. wDOSDate,
  464. wDOSTime,
  465. &vTime
  466. );
  467. //
  468. // Return.
  469. //
  470. if (fBool == TRUE) {
  471. *pdaTime = vTime;
  472. RRETURN(S_OK);
  473. }
  474. else {
  475. RRETURN(E_FAIL);
  476. }
  477. }
  478. HRESULT
  479. DelimitedStringToVariant(
  480. LPTSTR pszString,
  481. VARIANT *pvar,
  482. TCHAR Delimiter
  483. )
  484. {
  485. SAFEARRAYBOUND sabound[1];
  486. DWORD dwElements;
  487. LPTSTR pszCurrPos = pszString;
  488. LPTSTR *rgszStrings = NULL;
  489. SAFEARRAY *psa = NULL;
  490. VARIANT v;
  491. HRESULT hr = S_OK;
  492. LONG i;
  493. //
  494. // This function converts a delimited string into a VARIANT of
  495. // safe arrays.
  496. //
  497. // Assumption: a valid string are passed to this function
  498. // note that the input string gets destroyed in the process
  499. //
  500. //
  501. // scan the delimited string once to find out the dimension
  502. //
  503. //
  504. // in order to filter for NULL input values do a sanity check for
  505. // length of input string.
  506. //
  507. //
  508. // take care of null case first for sanity's sake
  509. //
  510. if (!pszString){
  511. sabound[0].cElements = 0;
  512. sabound[0].lLbound = 0;
  513. psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  514. if (psa == NULL){
  515. hr = E_OUTOFMEMORY;
  516. goto error;
  517. }
  518. VariantInit(pvar);
  519. V_VT(pvar) = VT_ARRAY|VT_VARIANT;
  520. V_ARRAY(pvar) = psa;
  521. goto error;
  522. }
  523. dwElements = (wcslen(pszString) == 0) ? 0: 1 ;
  524. while(!(*pszCurrPos == TEXT('\0'))){
  525. if(*pszCurrPos == Delimiter){
  526. dwElements++;
  527. *pszCurrPos = TEXT('\0');
  528. }
  529. pszCurrPos++;
  530. }
  531. rgszStrings = (LPTSTR *)AllocADsMem(sizeof(LPTSTR)*dwElements);
  532. if(!rgszStrings){
  533. hr = E_OUTOFMEMORY;
  534. goto error;
  535. }
  536. //
  537. // scan string again and put the appropriate pointers
  538. //
  539. pszCurrPos = pszString;
  540. if(rgszStrings != NULL){
  541. (*rgszStrings) = pszCurrPos;
  542. }
  543. i = 1;
  544. while(i < (LONG)dwElements){
  545. if(*pszCurrPos == TEXT('\0')){
  546. *(rgszStrings+i) = ++pszCurrPos;
  547. i++;
  548. }
  549. pszCurrPos++;
  550. }
  551. //
  552. // create the safearray
  553. //
  554. sabound[0].cElements = dwElements;
  555. sabound[0].lLbound = 0;
  556. psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  557. if (psa == NULL){
  558. hr = E_OUTOFMEMORY;
  559. goto error;
  560. }
  561. for(i=0; i<(LONG)dwElements; i++){
  562. VariantInit(&v);
  563. V_VT(&v) = VT_BSTR;
  564. hr = ADsAllocString(*(rgszStrings+i), &(V_BSTR(&v)));
  565. BAIL_ON_FAILURE(hr);
  566. //
  567. // Stick the caller provided data into the end of the SafeArray
  568. //
  569. hr = SafeArrayPutElement(psa, &i, &v);
  570. VariantClear(&v);
  571. BAIL_ON_FAILURE(hr);
  572. }
  573. //
  574. // convert this safearray into a VARIANT
  575. //
  576. VariantInit(pvar);
  577. V_VT(pvar) = VT_ARRAY|VT_VARIANT;
  578. V_ARRAY(pvar) = psa;
  579. error:
  580. if(rgszStrings && dwElements != 0){
  581. FreeADsMem(rgszStrings);
  582. }
  583. RRETURN(hr);
  584. }
  585. HRESULT
  586. VariantToDelimitedString(
  587. VARIANT var,
  588. LPTSTR *ppszString,
  589. TCHAR Delimiter
  590. )
  591. {
  592. LONG lIndices;
  593. ULONG cElements;
  594. ULONG ulRequiredLength=0;
  595. SAFEARRAY *psa = NULL;
  596. VARIANT vElement;
  597. LPTSTR pszCurrPos = NULL;
  598. HRESULT hr = S_OK;
  599. ULONG i;
  600. //
  601. // converts the safearray in a variant to a delimited string
  602. //
  603. *ppszString = NULL;
  604. if(!(V_VT(&var) == (VT_VARIANT|VT_ARRAY))) {
  605. RRETURN(E_FAIL);
  606. }
  607. psa = V_ARRAY(&var);
  608. //
  609. // Check that there is only one dimension in this array
  610. //
  611. if (psa->cDims != 1) {
  612. hr = E_FAIL;
  613. BAIL_ON_FAILURE(hr);
  614. }
  615. //
  616. // Check that there is atleast one element in this array
  617. //
  618. cElements = psa->rgsabound[0].cElements;
  619. if (cElements == 0){
  620. hr = E_FAIL;
  621. goto error;
  622. }
  623. //
  624. // We know that this is a valid single dimension array
  625. //
  626. lIndices= 0;
  627. for(i=0; i< cElements; i++){
  628. lIndices = i;
  629. VariantInit(&vElement);
  630. hr = SafeArrayGetElement(psa, &lIndices, &vElement);
  631. BAIL_ON_FAILURE(hr);
  632. if(!(V_VT(&vElement) == VT_BSTR)){
  633. RRETURN(E_FAIL);
  634. }
  635. //
  636. // unpack the BSTR in the VARIANT
  637. //
  638. ulRequiredLength+= wcslen(vElement.bstrVal)+1;
  639. VariantClear(&vElement);
  640. }
  641. ulRequiredLength +=2;
  642. *ppszString = (LPTSTR)AllocADsMem( ulRequiredLength*sizeof(TCHAR));
  643. if(*ppszString == NULL){
  644. hr = E_OUTOFMEMORY;
  645. goto error;
  646. }
  647. lIndices= 0;
  648. pszCurrPos = *ppszString;
  649. for(i=0; i< cElements; i++){
  650. lIndices = i;
  651. VariantInit(&vElement);
  652. hr = SafeArrayGetElement(psa, &lIndices, &vElement);
  653. BAIL_ON_FAILURE(hr);
  654. if(!(V_VT(&vElement) == VT_BSTR)){
  655. RRETURN(E_FAIL);
  656. }
  657. //
  658. // unpack the BSTR in the VARIANT
  659. //
  660. wcscpy(pszCurrPos, (LPTSTR)vElement.bstrVal);
  661. pszCurrPos += wcslen(vElement.bstrVal);
  662. if(i < cElements-1){
  663. *pszCurrPos = Delimiter;
  664. }
  665. pszCurrPos++;
  666. VariantClear(&vElement);
  667. }
  668. *pszCurrPos = L'\0';
  669. RRETURN(S_OK);
  670. error:
  671. RRETURN(hr);
  672. }
  673. HRESULT
  674. VariantToNulledString(
  675. VARIANT var,
  676. LPTSTR *ppszString
  677. )
  678. {
  679. LONG lIndices;
  680. ULONG cElements;
  681. ULONG ulRequiredLength=0;
  682. SAFEARRAY *psa = NULL;
  683. VARIANT vElement;
  684. LPTSTR szCurrPos = NULL;
  685. HRESULT hr = S_OK;
  686. ULONG i;
  687. //
  688. //converts the safearray in a variant to a double nulled string
  689. //
  690. VariantInit(&vElement);
  691. *ppszString = NULL;
  692. if (!(V_VT(&var) == (VT_VARIANT|VT_ARRAY))) {
  693. RRETURN(E_FAIL);
  694. }
  695. psa = V_ARRAY(&var);
  696. //
  697. // Check that there is only one dimension in this array
  698. //
  699. if (psa->cDims != 1) {
  700. hr = E_FAIL;
  701. BAIL_ON_FAILURE(hr);
  702. }
  703. //
  704. // Check that there is atleast one element in this array
  705. //
  706. cElements = psa->rgsabound[0].cElements;
  707. if (cElements == 0){
  708. hr = E_FAIL;
  709. BAIL_ON_FAILURE(hr);
  710. }
  711. //
  712. // We know that this is a valid single dimension array
  713. //
  714. lIndices= 0;
  715. for(i=0; i< cElements; i++){
  716. lIndices = i;
  717. VariantInit(&vElement);
  718. hr = SafeArrayGetElement(psa, &lIndices, &vElement);
  719. BAIL_ON_FAILURE(hr);
  720. if(!(V_VT(&vElement) == VT_BSTR)){
  721. RRETURN(E_FAIL);
  722. }
  723. //
  724. // unpack the BSTR in the VARIANT
  725. //
  726. ulRequiredLength+= wcslen(vElement.bstrVal)+1;
  727. VariantClear(&vElement);
  728. }
  729. ulRequiredLength +=2;
  730. *ppszString = (LPTSTR)AllocADsMem( ulRequiredLength*sizeof(TCHAR));
  731. if(*ppszString == NULL){
  732. hr = E_OUTOFMEMORY;
  733. goto error;
  734. }
  735. lIndices= 0;
  736. szCurrPos = *ppszString;
  737. for(i=0; i< cElements; i++){
  738. lIndices = i;
  739. VariantInit(&vElement);
  740. hr = SafeArrayGetElement(psa, &lIndices, &vElement);
  741. BAIL_ON_FAILURE(hr);
  742. if(!(V_VT(&vElement) == VT_BSTR)){
  743. RRETURN(E_FAIL);
  744. }
  745. //
  746. // unpack the BSTR in the VARIANT
  747. //
  748. wcscpy(szCurrPos, (LPTSTR)vElement.bstrVal);
  749. szCurrPos += wcslen(vElement.bstrVal)+1;
  750. VariantClear(&vElement);
  751. }
  752. *szCurrPos = L'\0';
  753. RRETURN(S_OK);
  754. error:
  755. VariantClear(&vElement);
  756. RRETURN(hr);
  757. }
  758. HRESULT
  759. NulledStringToVariant(
  760. LPTSTR pszString,
  761. VARIANT *pvar
  762. )
  763. {
  764. SAFEARRAYBOUND sabound[1];
  765. DWORD dwElements = 0;
  766. LPTSTR pszCurrPos = pszString;
  767. BOOL foundNULL = FALSE;
  768. LPTSTR *rgszStrings = NULL;
  769. SAFEARRAY *psa = NULL;
  770. VARIANT v;
  771. HRESULT hr = S_OK;
  772. LONG i;
  773. //
  774. // This function converts a double nulled string into a VARIANT of
  775. // safe arrays.
  776. //
  777. // Assumption: Valid double nulled strings are passed to this function
  778. //
  779. //
  780. // scan the double nulled string once to find out the dimension
  781. //
  782. while(!(*pszCurrPos == L'\0' && foundNULL)){
  783. if(*pszCurrPos == L'\0'){
  784. dwElements++;
  785. foundNULL = TRUE;
  786. }
  787. else{
  788. foundNULL = FALSE;
  789. }
  790. pszCurrPos++;
  791. }
  792. if(dwElements){
  793. rgszStrings = (LPTSTR *)AllocADsMem(sizeof(LPTSTR)*dwElements);
  794. }
  795. //
  796. // scan string again and put the appropriate pointers
  797. //
  798. pszCurrPos = pszString;
  799. if(rgszStrings != NULL){
  800. (*rgszStrings) = pszCurrPos;
  801. }
  802. foundNULL = FALSE;
  803. i = 1;
  804. while(i < (LONG)dwElements){
  805. if(foundNULL){
  806. *(rgszStrings+i) = pszCurrPos;
  807. i++;
  808. }
  809. if(*pszCurrPos == L'\0'){
  810. foundNULL = TRUE;
  811. }
  812. else{
  813. foundNULL = FALSE;
  814. }
  815. pszCurrPos++;
  816. }
  817. //
  818. // create the safearray
  819. //
  820. sabound[0].cElements = dwElements;
  821. sabound[0].lLbound = 0;
  822. psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  823. if (psa == NULL){
  824. hr = E_OUTOFMEMORY;
  825. goto error;
  826. }
  827. for(i=0; i<(LONG)dwElements; i++){
  828. VariantInit(&v);
  829. V_VT(&v) = VT_BSTR;
  830. hr = ADsAllocString(*(rgszStrings+i), &(V_BSTR(&v)));
  831. BAIL_ON_FAILURE(hr);
  832. //
  833. // Stick the caller provided data into the end of the SafeArray
  834. //
  835. hr = SafeArrayPutElement(psa, &i, &v);
  836. VariantClear(&v);
  837. BAIL_ON_FAILURE(hr);
  838. }
  839. //
  840. // convert this safearray into a VARIANT
  841. //
  842. VariantInit(pvar);
  843. V_VT(pvar) = VT_ARRAY|VT_VARIANT;
  844. V_ARRAY(pvar) = psa;
  845. error:
  846. if(rgszStrings){
  847. FreeADsMem(rgszStrings);
  848. }
  849. RRETURN(hr);
  850. }
  851. STDMETHODIMP
  852. GenericGetPropertyManager(
  853. CPropertyCache * pPropertyCache,
  854. THIS_ BSTR bstrName,
  855. VARIANT FAR* pvProp
  856. )
  857. {
  858. HRESULT hr = S_OK;
  859. DWORD dwSyntaxId;
  860. DWORD dwNumValues;
  861. DWORD dwInfoLevel;
  862. LPNTOBJECT pNtSrcObjects = NULL;
  863. //
  864. // retrieve data object from cache; if one exists
  865. hr = pPropertyCache->getproperty(
  866. bstrName,
  867. &dwSyntaxId,
  868. &dwNumValues,
  869. &pNtSrcObjects
  870. );
  871. BAIL_ON_FAILURE(hr);
  872. //
  873. // translate the Nt objects to variants
  874. //
  875. if (dwNumValues == 1) {
  876. hr = NtTypeToVarTypeCopy(
  877. pNtSrcObjects,
  878. pvProp
  879. );
  880. }else {
  881. hr = NtTypeToVarTypeCopyConstruct(
  882. pNtSrcObjects,
  883. dwNumValues,
  884. pvProp
  885. );
  886. }
  887. BAIL_ON_FAILURE(hr);
  888. error:
  889. if (pNtSrcObjects) {
  890. NTTypeFreeNTObjects(
  891. pNtSrcObjects,
  892. dwNumValues
  893. );
  894. }
  895. RRETURN(hr);
  896. }
  897. STDMETHODIMP
  898. GenericPutPropertyManager(
  899. CPropertyCache * pPropertyCache,
  900. PPROPERTYINFO pSchemaProps,
  901. DWORD dwSchemaPropSize,
  902. THIS_ BSTR bstrName,
  903. VARIANT vProp
  904. )
  905. {
  906. HRESULT hr = S_OK;
  907. DWORD dwSyntaxId = 0;
  908. DWORD dwIndex = 0;
  909. LPNTOBJECT pNtDestObjects = NULL;
  910. //
  911. // Issue: How do we handle multi-valued support
  912. //
  913. DWORD dwNumValues = 1;
  914. //
  915. // check if this is a legal property for this object,
  916. //
  917. //
  918. hr = ValidatePropertyinSchemaClass(
  919. pSchemaProps,
  920. dwSchemaPropSize,
  921. bstrName,
  922. &dwSyntaxId
  923. );
  924. BAIL_ON_FAILURE(hr);
  925. //
  926. // check if this is a writeable property
  927. //
  928. hr = ValidateIfWriteableProperty(
  929. pSchemaProps,
  930. dwSchemaPropSize,
  931. bstrName
  932. );
  933. BAIL_ON_FAILURE(hr);
  934. //
  935. // check if the variant maps to the syntax of this property
  936. //
  937. hr = VarTypeToNtTypeCopyConstruct(
  938. dwSyntaxId,
  939. &vProp,
  940. 1,
  941. &pNtDestObjects
  942. );
  943. BAIL_ON_FAILURE(hr);
  944. //
  945. // Find this property in the cache
  946. //
  947. hr = pPropertyCache->findproperty(
  948. bstrName,
  949. &dwIndex
  950. );
  951. //
  952. // If this property does not exist in the
  953. // cache, add this property into the cache.
  954. //
  955. if (FAILED(hr)) {
  956. hr = pPropertyCache->addproperty(
  957. bstrName,
  958. dwSyntaxId
  959. );
  960. //
  961. // If the operation fails for some reason
  962. // move on to the next property
  963. //
  964. BAIL_ON_FAILURE(hr);
  965. }
  966. //
  967. // Now update the property in the cache
  968. // Should use putproperty, not updateproperty -> unmarshalling from svr only
  969. //
  970. hr = pPropertyCache->putproperty(
  971. bstrName,
  972. dwSyntaxId,
  973. dwNumValues,
  974. pNtDestObjects
  975. );
  976. BAIL_ON_FAILURE(hr);
  977. error:
  978. if (pNtDestObjects) {
  979. NTTypeFreeNTObjects(
  980. pNtDestObjects,
  981. dwNumValues
  982. );
  983. }
  984. RRETURN(hr);
  985. }
  986. HRESULT
  987. BuildPrinterNameFromADsPath(
  988. LPWSTR pszADsParent,
  989. LPWSTR pszPrinterName,
  990. LPWSTR pszUncPrinterName
  991. )
  992. {
  993. POBJECTINFO pObjectInfo = NULL;
  994. CLexer Lexer(pszADsParent);
  995. HRESULT hr;
  996. pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
  997. if (!pObjectInfo)
  998. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  999. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1000. hr = Object(&Lexer, pObjectInfo);
  1001. BAIL_ON_FAILURE(hr);
  1002. wsprintf(
  1003. pszUncPrinterName,
  1004. L"\\\\%s\\%s",
  1005. pObjectInfo->ComponentArray[0],
  1006. pszPrinterName
  1007. );
  1008. error:
  1009. if(pObjectInfo){
  1010. FreeObjectInfo(pObjectInfo);
  1011. }
  1012. RRETURN(hr);
  1013. }
  1014. STDMETHODIMP
  1015. GenericGetExPropertyManager(
  1016. DWORD dwObjectState,
  1017. CPropertyCache * pPropertyCache,
  1018. THIS_ BSTR bstrName,
  1019. VARIANT FAR* pvProp
  1020. )
  1021. {
  1022. HRESULT hr = S_OK;
  1023. DWORD dwSyntaxId;
  1024. DWORD dwNumValues;
  1025. LPNTOBJECT pNtSrcObjects = NULL;
  1026. //
  1027. // retrieve data object from cache; if one exis
  1028. //
  1029. if (dwObjectState == ADS_OBJECT_UNBOUND) {
  1030. hr = pPropertyCache->unboundgetproperty(
  1031. bstrName,
  1032. &dwSyntaxId,
  1033. &dwNumValues,
  1034. &pNtSrcObjects
  1035. );
  1036. BAIL_ON_FAILURE(hr);
  1037. }else {
  1038. hr = pPropertyCache->getproperty(
  1039. bstrName,
  1040. &dwSyntaxId,
  1041. &dwNumValues,
  1042. &pNtSrcObjects
  1043. );
  1044. BAIL_ON_FAILURE(hr);
  1045. }
  1046. //
  1047. // translate the Nds objects to variants
  1048. //
  1049. hr = NtTypeToVarTypeCopyConstruct(
  1050. pNtSrcObjects,
  1051. dwNumValues,
  1052. pvProp
  1053. );
  1054. BAIL_ON_FAILURE(hr);
  1055. error:
  1056. if (pNtSrcObjects) {
  1057. NTTypeFreeNTObjects(
  1058. pNtSrcObjects,
  1059. dwNumValues
  1060. );
  1061. }
  1062. RRETURN(hr);
  1063. }
  1064. STDMETHODIMP
  1065. GenericPutExPropertyManager(
  1066. CPropertyCache * pPropertyCache,
  1067. PPROPERTYINFO pSchemaProps,
  1068. DWORD dwSchemaPropSize,
  1069. THIS_ BSTR bstrName,
  1070. VARIANT vProp
  1071. )
  1072. {
  1073. HRESULT hr = S_OK;
  1074. DWORD dwSyntaxId = 0;
  1075. DWORD dwIndex = 0;
  1076. DWORD dwNumValues = 0;
  1077. LPNTOBJECT pNtDestObjects = NULL;
  1078. VARIANT * pVarArray = NULL;
  1079. VARIANT * pvProp = NULL;
  1080. //
  1081. // Issue: How do we handle multi-valued support
  1082. //
  1083. //
  1084. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1085. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1086. // what's inside.
  1087. //
  1088. pvProp = &vProp;
  1089. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1090. pvProp = V_VARIANTREF(&vProp);
  1091. }
  1092. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
  1093. (V_VT(&vProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
  1094. hr = ConvertByRefSafeArrayToVariantArray(
  1095. *pvProp,
  1096. &pVarArray,
  1097. &dwNumValues
  1098. );
  1099. BAIL_ON_FAILURE(hr);
  1100. pvProp = pVarArray;
  1101. }else {
  1102. hr = E_FAIL;
  1103. BAIL_ON_FAILURE(hr);
  1104. }
  1105. //
  1106. // check if this is a legal property for this object,
  1107. //
  1108. //
  1109. hr = ValidatePropertyinSchemaClass(
  1110. pSchemaProps,
  1111. dwSchemaPropSize,
  1112. bstrName,
  1113. &dwSyntaxId
  1114. );
  1115. BAIL_ON_FAILURE(hr);
  1116. //
  1117. // check if this is a writeable property
  1118. //
  1119. hr = ValidateIfWriteableProperty(
  1120. pSchemaProps,
  1121. dwSchemaPropSize,
  1122. bstrName
  1123. );
  1124. BAIL_ON_FAILURE(hr);
  1125. //
  1126. // check if the variant maps to the syntax of this property
  1127. //
  1128. hr = VarTypeToNtTypeCopyConstruct(
  1129. dwSyntaxId,
  1130. pvProp,
  1131. dwNumValues,
  1132. &pNtDestObjects
  1133. );
  1134. BAIL_ON_FAILURE(hr);
  1135. //
  1136. // Find this property in the cache
  1137. //
  1138. hr = pPropertyCache->findproperty(
  1139. bstrName,
  1140. &dwIndex
  1141. );
  1142. //
  1143. // If this property does not exist in the
  1144. // cache, add this property into the cache.
  1145. //
  1146. if (FAILED(hr)) {
  1147. hr = pPropertyCache->addproperty(
  1148. bstrName,
  1149. dwSyntaxId
  1150. );
  1151. //
  1152. // If the operation fails for some reason
  1153. // move on to the next property
  1154. //
  1155. BAIL_ON_FAILURE(hr);
  1156. }
  1157. //
  1158. // Now update the property in the cache
  1159. //
  1160. hr = pPropertyCache->putproperty(
  1161. bstrName,
  1162. dwSyntaxId,
  1163. dwNumValues,
  1164. pNtDestObjects
  1165. );
  1166. BAIL_ON_FAILURE(hr);
  1167. error:
  1168. if (pNtDestObjects) {
  1169. NTTypeFreeNTObjects(
  1170. pNtDestObjects,
  1171. dwNumValues
  1172. );
  1173. }
  1174. if (pVarArray) {
  1175. DWORD i = 0;
  1176. for (i = 0; i < dwNumValues; i++) {
  1177. VariantClear(pVarArray + i);
  1178. }
  1179. FreeADsMem(pVarArray);
  1180. }
  1181. RRETURN(hr);
  1182. }
  1183. HRESULT
  1184. GenericPropCountPropertyManager(
  1185. CPropertyCache * pPropertyCache,
  1186. PLONG plCount
  1187. )
  1188. {
  1189. HRESULT hr = E_FAIL;
  1190. if (pPropertyCache) {
  1191. hr = pPropertyCache->get_PropertyCount((PDWORD)plCount);
  1192. }
  1193. RRETURN(hr);
  1194. }
  1195. HRESULT
  1196. GenericNextPropertyManager(
  1197. CPropertyCache * pPropertyCache,
  1198. VARIANT FAR *pVariant
  1199. )
  1200. {
  1201. HRESULT hr = E_FAIL;
  1202. DWORD dwSyntaxId = 0;
  1203. DWORD dwNumValues = 0;
  1204. LPNTOBJECT pNtSrcObjects = NULL;
  1205. VARIANT varData;
  1206. IDispatch * pDispatch = NULL;
  1207. VariantInit(&varData);
  1208. hr = pPropertyCache->unboundgetproperty(
  1209. pPropertyCache->get_CurrentIndex(),
  1210. &dwSyntaxId,
  1211. &dwNumValues,
  1212. &pNtSrcObjects
  1213. );
  1214. BAIL_ON_FAILURE(hr);
  1215. //
  1216. // translate the Nt objects to variants
  1217. //
  1218. hr = ConvertNtValuesToVariant(
  1219. pPropertyCache->get_CurrentPropName(),
  1220. pNtSrcObjects,
  1221. dwNumValues,
  1222. pVariant
  1223. );
  1224. BAIL_ON_FAILURE(hr);
  1225. error:
  1226. //
  1227. // - goto next one even if error to avoid infinite looping at a property
  1228. // which we cannot convert (e.g. schemaless server property.)
  1229. // - do not return the result of Skip() as current operation does not
  1230. // depend on the sucess of Skip().
  1231. //
  1232. pPropertyCache->skip_propindex(
  1233. 1
  1234. );
  1235. if (pNtSrcObjects) {
  1236. NTTypeFreeNTObjects(
  1237. pNtSrcObjects,
  1238. dwNumValues
  1239. );
  1240. }
  1241. RRETURN(hr);
  1242. }
  1243. HRESULT
  1244. GenericSkipPropertyManager(
  1245. CPropertyCache * pPropertyCache,
  1246. ULONG cElements
  1247. )
  1248. {
  1249. HRESULT hr = E_FAIL;
  1250. hr = pPropertyCache->skip_propindex(
  1251. cElements
  1252. );
  1253. RRETURN(hr);
  1254. }
  1255. HRESULT
  1256. GenericResetPropertyManager(
  1257. CPropertyCache * pPropertyCache
  1258. )
  1259. {
  1260. pPropertyCache->reset_propindex();
  1261. RRETURN(S_OK);
  1262. }
  1263. HRESULT
  1264. GenericDeletePropertyManager(
  1265. CPropertyCache * pPropertyCache,
  1266. VARIANT varEntry
  1267. )
  1268. {
  1269. HRESULT hr = S_OK;
  1270. DWORD dwIndex = 0;
  1271. switch (V_VT(&varEntry)) {
  1272. case VT_BSTR:
  1273. hr = pPropertyCache->findproperty(
  1274. V_BSTR(&varEntry),
  1275. &dwIndex
  1276. );
  1277. BAIL_ON_FAILURE(hr);
  1278. break;
  1279. case VT_I4:
  1280. dwIndex = V_I4(&varEntry);
  1281. break;
  1282. case VT_I2:
  1283. dwIndex = V_I2(&varEntry);
  1284. break;
  1285. default:
  1286. hr = E_FAIL;
  1287. BAIL_ON_FAILURE(hr);
  1288. }
  1289. hr = pPropertyCache->deleteproperty(
  1290. dwIndex
  1291. );
  1292. error:
  1293. RRETURN(hr);
  1294. }
  1295. HRESULT
  1296. GenericPutPropItemPropertyManager(
  1297. CPropertyCache * pPropertyCache,
  1298. PPROPERTYINFO pSchemaProps,
  1299. DWORD dwSchemaPropSize,
  1300. VARIANT varData
  1301. )
  1302. {
  1303. HRESULT hr = S_OK;
  1304. DWORD dwSyntaxId = 0;
  1305. DWORD dwIndex = 0;
  1306. WCHAR szPropertyName[MAX_PATH];
  1307. LPNTOBJECT pNtDestObjects = NULL;
  1308. DWORD dwNumValues = 0;
  1309. DWORD dwControlCode = 0;
  1310. hr = ConvertVariantToNtValues(
  1311. varData,
  1312. pSchemaProps,
  1313. dwSchemaPropSize,
  1314. szPropertyName,
  1315. &pNtDestObjects,
  1316. &dwNumValues,
  1317. &dwSyntaxId,
  1318. &dwControlCode
  1319. );
  1320. BAIL_ON_FAILURE(hr);
  1321. if (dwControlCode != ADS_PROPERTY_UPDATE) {
  1322. RRETURN(E_ADS_BAD_PARAMETER);
  1323. }
  1324. //
  1325. // Find this property in the cache
  1326. //
  1327. hr = pPropertyCache->findproperty(
  1328. szPropertyName,
  1329. &dwIndex
  1330. );
  1331. //
  1332. // If this property does not exist in the
  1333. // cache, add this property into the cache.
  1334. //
  1335. if (FAILED(hr)) {
  1336. hr = pPropertyCache->addproperty(
  1337. szPropertyName,
  1338. dwSyntaxId
  1339. );
  1340. //
  1341. // If the operation fails for some reason
  1342. // move on to the next property
  1343. //
  1344. BAIL_ON_FAILURE(hr);
  1345. }
  1346. //
  1347. // Now update the property in the cache
  1348. //
  1349. hr = pPropertyCache->putproperty(
  1350. szPropertyName,
  1351. dwSyntaxId,
  1352. dwNumValues,
  1353. pNtDestObjects
  1354. );
  1355. BAIL_ON_FAILURE(hr);
  1356. error:
  1357. if (pNtDestObjects) {
  1358. NTTypeFreeNTObjects(
  1359. pNtDestObjects,
  1360. dwNumValues
  1361. );
  1362. }
  1363. RRETURN(hr);
  1364. }
  1365. HRESULT
  1366. GenericGetPropItemPropertyManager(
  1367. CPropertyCache * pPropertyCache,
  1368. DWORD dwObjectState,
  1369. BSTR bstrName,
  1370. LONG lnADsType,
  1371. VARIANT * pVariant
  1372. )
  1373. {
  1374. HRESULT hr = S_OK;
  1375. DWORD dwSyntaxId;
  1376. DWORD dwNumValues;
  1377. LPNTOBJECT pNtSrcObjects = NULL;
  1378. //
  1379. // retrieve data object from cache; if one exis
  1380. //
  1381. if (dwObjectState == ADS_OBJECT_UNBOUND) {
  1382. hr = pPropertyCache->unboundgetproperty(
  1383. bstrName,
  1384. &dwSyntaxId,
  1385. &dwNumValues,
  1386. &pNtSrcObjects
  1387. );
  1388. BAIL_ON_FAILURE(hr);
  1389. }else {
  1390. hr = pPropertyCache->getproperty(
  1391. bstrName,
  1392. &dwSyntaxId,
  1393. &dwNumValues,
  1394. &pNtSrcObjects
  1395. );
  1396. BAIL_ON_FAILURE(hr);
  1397. }
  1398. //
  1399. // translate the Nds objects to variants
  1400. //
  1401. hr = ConvertNtValuesToVariant(
  1402. bstrName,
  1403. pNtSrcObjects,
  1404. dwNumValues,
  1405. pVariant
  1406. );
  1407. BAIL_ON_FAILURE(hr);
  1408. error:
  1409. if (pNtSrcObjects) {
  1410. NTTypeFreeNTObjects(
  1411. pNtSrcObjects,
  1412. dwNumValues
  1413. );
  1414. }
  1415. RRETURN(hr);
  1416. }
  1417. HRESULT
  1418. GenericItemPropertyManager(
  1419. CPropertyCache * pPropertyCache,
  1420. DWORD dwObjectState,
  1421. VARIANT varIndex,
  1422. VARIANT *pVariant
  1423. )
  1424. {
  1425. HRESULT hr = S_OK;
  1426. DWORD dwSyntaxId;
  1427. DWORD dwNumValues;
  1428. LPNTOBJECT pNtSrcObjects = NULL;
  1429. LPWSTR szPropName = NULL;
  1430. VARIANT *pvVar = &varIndex;
  1431. //
  1432. // retrieve data object from cache; if one exis
  1433. //
  1434. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  1435. //
  1436. // The value is being passed in byref so we need to
  1437. // deref it for vbs stuff to work
  1438. //
  1439. pvVar = V_VARIANTREF(&varIndex);
  1440. }
  1441. switch (V_VT(pvVar)) {
  1442. case VT_BSTR:
  1443. if (dwObjectState == ADS_OBJECT_UNBOUND) {
  1444. hr = pPropertyCache->unboundgetproperty(
  1445. V_BSTR(pvVar),
  1446. &dwSyntaxId,
  1447. &dwNumValues,
  1448. &pNtSrcObjects
  1449. );
  1450. BAIL_ON_FAILURE(hr);
  1451. }else {
  1452. hr = pPropertyCache->getproperty(
  1453. V_BSTR(pvVar),
  1454. &dwSyntaxId,
  1455. &dwNumValues,
  1456. &pNtSrcObjects
  1457. );
  1458. BAIL_ON_FAILURE(hr);
  1459. }
  1460. hr = ConvertNtValuesToVariant(
  1461. V_BSTR(pvVar),
  1462. pNtSrcObjects,
  1463. dwNumValues,
  1464. pVariant
  1465. );
  1466. BAIL_ON_FAILURE(hr);
  1467. break;
  1468. case VT_I4:
  1469. hr = pPropertyCache->unboundgetproperty(
  1470. V_I4(pvVar),
  1471. &dwSyntaxId,
  1472. &dwNumValues,
  1473. &pNtSrcObjects
  1474. );
  1475. BAIL_ON_FAILURE(hr);
  1476. szPropName = pPropertyCache->get_PropName(V_I4(pvVar));
  1477. hr = ConvertNtValuesToVariant(
  1478. szPropName,
  1479. pNtSrcObjects,
  1480. dwNumValues,
  1481. pVariant
  1482. );
  1483. BAIL_ON_FAILURE(hr);
  1484. break;
  1485. case VT_I2:
  1486. hr = pPropertyCache->unboundgetproperty(
  1487. (DWORD)V_I2(pvVar),
  1488. &dwSyntaxId,
  1489. &dwNumValues,
  1490. &pNtSrcObjects
  1491. );
  1492. BAIL_ON_FAILURE(hr);
  1493. szPropName = pPropertyCache->get_PropName(V_I2(pvVar));
  1494. hr = ConvertNtValuesToVariant(
  1495. szPropName,
  1496. pNtSrcObjects,
  1497. dwNumValues,
  1498. pVariant
  1499. );
  1500. BAIL_ON_FAILURE(hr);
  1501. break;
  1502. default:
  1503. hr = E_FAIL;
  1504. BAIL_ON_FAILURE(hr);
  1505. }
  1506. error:
  1507. if (pNtSrcObjects) {
  1508. NTTypeFreeNTObjects(
  1509. pNtSrcObjects,
  1510. dwNumValues
  1511. );
  1512. }
  1513. RRETURN(hr);
  1514. }
  1515. HRESULT
  1516. GenericPurgePropertyManager(
  1517. CPropertyCache * pPropertyCache
  1518. )
  1519. {
  1520. pPropertyCache->flushpropcache();
  1521. RRETURN(S_OK);
  1522. }
  1523. HRESULT
  1524. CreatePropEntry(
  1525. LPWSTR szPropName,
  1526. ADSTYPE dwADsType,
  1527. VARIANT varData,
  1528. REFIID riid,
  1529. LPVOID * ppDispatch
  1530. )
  1531. {
  1532. HRESULT hr = S_OK;
  1533. IADsPropertyEntry * pPropEntry = NULL;
  1534. hr = CoCreateInstance(
  1535. CLSID_PropertyEntry,
  1536. NULL,
  1537. CLSCTX_INPROC_SERVER,
  1538. IID_IADsPropertyEntry,
  1539. (void **)&pPropEntry
  1540. );
  1541. BAIL_ON_FAILURE(hr);
  1542. hr = pPropEntry->put_Name(szPropName);
  1543. BAIL_ON_FAILURE(hr);
  1544. hr = pPropEntry->put_Values(varData);
  1545. BAIL_ON_FAILURE(hr);
  1546. hr = pPropEntry->put_ADsType(dwADsType);
  1547. BAIL_ON_FAILURE(hr);
  1548. hr = pPropEntry->QueryInterface(
  1549. riid,
  1550. ppDispatch
  1551. );
  1552. BAIL_ON_FAILURE(hr);
  1553. error:
  1554. if (pPropEntry) {
  1555. pPropEntry->Release();
  1556. }
  1557. RRETURN(hr);
  1558. }
  1559. HRESULT
  1560. ConvertNtValuesToVariant(
  1561. LPWSTR szPropertyName,
  1562. PNTOBJECT pNtSrcObject,
  1563. DWORD dwNumValues,
  1564. PVARIANT pVariant
  1565. )
  1566. {
  1567. HRESULT hr = S_OK;
  1568. VARIANT varData;
  1569. IDispatch * pDispatch = NULL;
  1570. PADSVALUE pAdsValues = NULL;
  1571. ADSTYPE dwADsType = ADSTYPE_INVALID;
  1572. VariantInit(&varData);
  1573. VariantInit(pVariant);
  1574. if (dwNumValues>0) {
  1575. hr = NTTypeToAdsTypeCopyConstruct(
  1576. pNtSrcObject,
  1577. dwNumValues,
  1578. &pAdsValues
  1579. );
  1580. if (SUCCEEDED(hr)){
  1581. hr = AdsTypeToPropVariant(
  1582. pAdsValues,
  1583. dwNumValues,
  1584. &varData
  1585. );
  1586. BAIL_ON_FAILURE(hr);
  1587. dwADsType = pAdsValues->dwType;
  1588. }
  1589. else if (hr==E_OUTOFMEMORY) {
  1590. BAIL_ON_FAILURE(hr);
  1591. }
  1592. // failed because of NTType is not supported yet (e.g. NulledString)
  1593. // in NTTypeToAdsTypeCopyConstruct() conversion yet
  1594. // -> use empty variant now.
  1595. else {
  1596. VariantInit(&varData);
  1597. }
  1598. }
  1599. hr = CreatePropEntry(
  1600. szPropertyName,
  1601. dwADsType,
  1602. varData,
  1603. IID_IDispatch,
  1604. (void **)&pDispatch
  1605. );
  1606. BAIL_ON_FAILURE(hr);
  1607. V_DISPATCH(pVariant) = pDispatch;
  1608. V_VT(pVariant) = VT_DISPATCH;
  1609. error:
  1610. VariantClear(&varData);
  1611. if (pAdsValues) {
  1612. AdsFreeAdsValues(
  1613. pAdsValues,
  1614. dwNumValues
  1615. );
  1616. FreeADsMem( pAdsValues);
  1617. }
  1618. RRETURN(hr);
  1619. }
  1620. HRESULT
  1621. ConvertVariantToVariantArray(
  1622. VARIANT varData,
  1623. VARIANT ** ppVarArray,
  1624. DWORD * pdwNumValues
  1625. )
  1626. {
  1627. DWORD dwNumValues = 0;
  1628. VARIANT * pVarArray = NULL;
  1629. HRESULT hr = S_OK;
  1630. VARIANT * pVarData = NULL;
  1631. *ppVarArray = NULL;
  1632. *pdwNumValues = 0;
  1633. //
  1634. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1635. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1636. // what's inside.
  1637. //
  1638. pVarData = &varData;
  1639. if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) {
  1640. pVarData = V_VARIANTREF(&varData);
  1641. }
  1642. if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  1643. (V_VT(pVarData) == (VT_VARIANT|VT_ARRAY))) {
  1644. hr = ConvertSafeArrayToVariantArray(
  1645. varData,
  1646. &pVarArray,
  1647. &dwNumValues
  1648. );
  1649. BAIL_ON_FAILURE(hr);
  1650. } else {
  1651. pVarArray = NULL;
  1652. dwNumValues = 0;
  1653. }
  1654. *ppVarArray = pVarArray;
  1655. *pdwNumValues = dwNumValues;
  1656. error:
  1657. RRETURN(hr);
  1658. }
  1659. void
  1660. FreeVariantArray(
  1661. VARIANT * pVarArray,
  1662. DWORD dwNumValues
  1663. )
  1664. {
  1665. if (pVarArray) {
  1666. DWORD i = 0;
  1667. for (i = 0; i < dwNumValues; i++) {
  1668. VariantClear(pVarArray + i);
  1669. }
  1670. FreeADsMem(pVarArray);
  1671. }
  1672. }
  1673. HRESULT
  1674. ConvertVariantToNtValues(
  1675. VARIANT varData,
  1676. PPROPERTYINFO pSchemaProps,
  1677. DWORD dwSchemaPropSize,
  1678. LPWSTR szPropertyName,
  1679. PNTOBJECT *ppNtDestObjects,
  1680. PDWORD pdwNumValues,
  1681. PDWORD pdwSyntaxId,
  1682. PDWORD pdwControlCode
  1683. )
  1684. {
  1685. HRESULT hr = S_OK;
  1686. IADsPropertyEntry * pPropEntry = NULL;
  1687. IDispatch * pDispatch = NULL;
  1688. BSTR bstrPropName = NULL;
  1689. DWORD dwControlCode = 0;
  1690. DWORD dwAdsType = 0;
  1691. VARIANT varValues;
  1692. VARIANT * pVarArray = NULL;
  1693. DWORD dwNumValues = 0;
  1694. PADSVALUE pAdsValues = NULL;
  1695. DWORD dwAdsValues = 0;
  1696. PNTOBJECT pNtDestObjects = 0;
  1697. DWORD dwNumNtObjects = 0;
  1698. DWORD dwNtSyntaxId = 0;
  1699. if (V_VT(&varData) != VT_DISPATCH) {
  1700. RRETURN (hr = DISP_E_TYPEMISMATCH);
  1701. }
  1702. pDispatch = V_DISPATCH(&varData);
  1703. hr = pDispatch->QueryInterface(
  1704. IID_IADsPropertyEntry,
  1705. (void **)&pPropEntry
  1706. );
  1707. BAIL_ON_FAILURE(hr);
  1708. VariantInit(&varValues);
  1709. VariantClear(&varValues);
  1710. hr = pPropEntry->get_Name(&bstrPropName);
  1711. BAIL_ON_FAILURE(hr);
  1712. wcscpy(szPropertyName, bstrPropName);
  1713. hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
  1714. BAIL_ON_FAILURE(hr);
  1715. *pdwControlCode = dwControlCode;
  1716. hr = pPropEntry->get_ADsType((long *)&dwAdsType);
  1717. BAIL_ON_FAILURE(hr);
  1718. hr = pPropEntry->get_Values(&varValues);
  1719. BAIL_ON_FAILURE(hr);
  1720. hr = ConvertVariantToVariantArray(
  1721. varValues,
  1722. &pVarArray,
  1723. &dwNumValues
  1724. );
  1725. BAIL_ON_FAILURE(hr);
  1726. if (dwNumValues) {
  1727. hr = PropVariantToAdsType(
  1728. pVarArray,
  1729. dwNumValues,
  1730. &pAdsValues,
  1731. &dwAdsValues
  1732. );
  1733. BAIL_ON_FAILURE(hr);
  1734. hr = AdsTypeToNTTypeCopyConstruct(
  1735. pAdsValues,
  1736. dwAdsValues,
  1737. &pNtDestObjects,
  1738. &dwNumNtObjects,
  1739. &dwNtSyntaxId
  1740. );
  1741. BAIL_ON_FAILURE(hr);
  1742. }
  1743. *pdwNumValues = dwNumValues;
  1744. *ppNtDestObjects = pNtDestObjects;
  1745. *pdwSyntaxId = dwNtSyntaxId;
  1746. error:
  1747. if (pVarArray) {
  1748. FreeVariantArray(
  1749. pVarArray,
  1750. dwNumValues
  1751. );
  1752. }
  1753. RRETURN(hr);
  1754. }
  1755. HRESULT
  1756. ConvertNtValuesToVariant(
  1757. BSTR bstrName,
  1758. LPNTOBJECT pNtSrcObjects,
  1759. DWORD dwNumValues,
  1760. VARIANT * pVariant
  1761. );
  1762. HRESULT
  1763. ConvertVariantToVariantArray(
  1764. VARIANT varData,
  1765. VARIANT ** ppVarArray,
  1766. DWORD * pdwNumValues
  1767. );
  1768. void
  1769. FreeVariantArray(
  1770. VARIANT * pVarArray,
  1771. DWORD dwNumValues
  1772. );
  1773. HRESULT
  1774. ConvertVariantToNtValues(
  1775. VARIANT varData,
  1776. PPROPERTYINFO pSchemaProps,
  1777. DWORD dwSchemaPropSize,
  1778. LPWSTR szPropertyName,
  1779. PNTOBJECT *ppNtDestObjects,
  1780. PDWORD pdwNumValues,
  1781. PDWORD pdwSyntaxId
  1782. );