Pber
asked on
ADSI multi-valued attribute with one value not returning data
I have modified the following code from MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/iads_getex.asp)
The code works ok except for one situation. If the attribute only contains one value it would seem lstart and lend are wrong. Instead of them being 0:0 respectively, they are huge like 7471215:15073473
e.g. If the user is a member of two groups, it will display data. If the user is a member of one group, it screws up
Should this example not work with a single value in a multi-valued attribute? If not, what do I need to do to return the data if only one value exists?
////////////////////////// ////////// ////////// /////////
// Get a multi-valued attribute from a User attribute.
////////////////////////// ////////// ////////// /////////
IADs *pSvc = NULL;
hr = ADsGetObject(L"LDAP://DC1. test.dom,c n=test,ou= test,dc-te st,dc=dom" , IID_IADs, (void**) &pSvc );
if ( !SUCCEEDED(hr) )
{
return hr;
}
hr = pSvc->Get(CComBSTR("member Of"), &var );
if ( SUCCEEDED(hr) )
{
LONG lstart, lend;
SAFEARRAY *sa = V_ARRAY( &var );
VARIANT varItem;
// Get the lower and upper bound.
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
printf("%d:%d",lstart,lend );
// Iterate and print the content.
VariantInit(&varItem);
printf("Getting memberOF via IADs :\n");
for ( long idx=lstart; idx <= lend; idx++ )
{
hr = SafeArrayGetElement( sa, &idx, &varItem );
printf("%S ", V_BSTR(&varItem));
VariantClear(&varItem);
}
printf("\n");
VariantClear(&var);
}
// Cleanup.
if ( pSvc )
{
pSvc->Release();
}
The code works ok except for one situation. If the attribute only contains one value it would seem lstart and lend are wrong. Instead of them being 0:0 respectively, they are huge like 7471215:15073473
e.g. If the user is a member of two groups, it will display data. If the user is a member of one group, it screws up
Should this example not work with a single value in a multi-valued attribute? If not, what do I need to do to return the data if only one value exists?
//////////////////////////
// Get a multi-valued attribute from a User attribute.
//////////////////////////
IADs *pSvc = NULL;
hr = ADsGetObject(L"LDAP://DC1.
if ( !SUCCEEDED(hr) )
{
return hr;
}
hr = pSvc->Get(CComBSTR("member
if ( SUCCEEDED(hr) )
{
LONG lstart, lend;
SAFEARRAY *sa = V_ARRAY( &var );
VARIANT varItem;
// Get the lower and upper bound.
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
printf("%d:%d",lstart,lend
// Iterate and print the content.
VariantInit(&varItem);
printf("Getting memberOF via IADs :\n");
for ( long idx=lstart; idx <= lend; idx++ )
{
hr = SafeArrayGetElement( sa, &idx, &varItem );
printf("%S ", V_BSTR(&varItem));
VariantClear(&varItem);
}
printf("\n");
VariantClear(&var);
}
// Cleanup.
if ( pSvc )
{
pSvc->Release();
}
ASKER
Both results are returning 0.
Everything seems to be working.
On a different computer instead of 7471215:15073473 it's 0:-1
ASKER
A little clarification on that last message, it's still not returning the valid data. the SafeArrayGetUBound and Lbound seem to be working.
ASKER
I tried a few other multivalued attributes and they all seem to product wierd numbers whenever there is only a single value assigned to a multivalued attribute. I can get around it by using the code below, but that doesn't seem right.
// Get the lower and upper bound.
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
if (lstart != 0) //single value assigned
{
printf("%S ", V_BSTR(&var));
}
else
{
for ( long idx=lstart; idx <= lend; idx++ )
{
hr = SafeArrayGetElement( sa, &idx, &varItem );
printf("%S ", V_BSTR(&varItem));
VariantClear(&varItem);
}
}
// Get the lower and upper bound.
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
if (lstart != 0) //single value assigned
{
printf("%S ", V_BSTR(&var));
}
else
{
for ( long idx=lstart; idx <= lend; idx++ )
{
hr = SafeArrayGetElement( sa, &idx, &varItem );
printf("%S ", V_BSTR(&varItem));
VariantClear(&varItem);
}
}
ASKER
Maybe I should read MSDN a little better:
Remark (from IADS::Get):
The IADs::Get method requires the caller to handle the single- and multi-valued property values differently. Thus, if you know that the property of interest is either single- or multi-valued, use the IADs::Get method to retrieve the property value. The following code example shows how you, as a caller, can handle single- and multi-valued properties when calling this method.
...
You can also use IADs::GetEx to retrieve property values from the property cache. However, the values are returned as a variant array of VARIANTs, regardless of whether they are single-valued or multi-valued. That is, ADSI attempts to package the returned property values in consistent data formats. This saves you, as a caller, the effort of validating the data types when unsure that the returned data has single or multiple values.
Remark (from IADS::GetEx):
The IADs::Get and IADs::GetEx methods return a different variant structure for a single-valued property value. If the property is a string, IADs::Get returns a variant of string (VT_BSTR), whereas IADs::GetEx returns a variant array of a VARIANT type string with a single element. Thus, if you are not sure that a multi-valued attribute will return a single value or multiple values, use IADs::GetEx. As it does not require you to validate the result's data structures, you may want to use IADs::GetEx to retrieve a property when you are not sure whether it has single or multiple values.
Remark (from IADS::Get):
The IADs::Get method requires the caller to handle the single- and multi-valued property values differently. Thus, if you know that the property of interest is either single- or multi-valued, use the IADs::Get method to retrieve the property value. The following code example shows how you, as a caller, can handle single- and multi-valued properties when calling this method.
...
You can also use IADs::GetEx to retrieve property values from the property cache. However, the values are returned as a variant array of VARIANTs, regardless of whether they are single-valued or multi-valued. That is, ADSI attempts to package the returned property values in consistent data formats. This saves you, as a caller, the effort of validating the data types when unsure that the returned data has single or multiple values.
Remark (from IADS::GetEx):
The IADs::Get and IADs::GetEx methods return a different variant structure for a single-valued property value. If the property is a string, IADs::Get returns a variant of string (VT_BSTR), whereas IADs::GetEx returns a variant array of a VARIANT type string with a single element. Thus, if you are not sure that a multi-valued attribute will return a single value or multiple values, use IADs::GetEx. As it does not require you to validate the result's data structures, you may want to use IADs::GetEx to retrieve a property when you are not sure whether it has single or multiple values.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
lstart = lend = 0;
// Get the lower and upper bound.
hr = SafeArrayGetLBound( sa, 1, &lstart );
if (FAILED(hr)) printf("LBound failed with %d\n", hr);
hr = SafeArrayGetUBound( sa, 1, &lend );
if (FAILED(hr)) printf("UBound failed with %d\n", hr);
printf("%d:%d",lstart,lend
to see if there's something going wrong.