Como os aplicativos devem usar especificadores de exibição
Para exibir objetos do Serviço de Domínio Active Directory, use especificadores de exibição para obter dados de exibição localizados para objetos de classe e atributo. Isso permite que nomes e ícones de exibição localizados sejam usados e evita a localização desnecessária dos dados de exibição.
Nomes de exibição
As propriedades classDisplayName e attributeDisplayNames dos objetos especificadores de exibição para a localidade apropriada devem ser usadas para obter texto de exibição para nomes de classe e atributo. Não use as propriedades cn, classDisplayName ou ldapDisplayName dos objetos classSchema ou attributeSchema para obter rótulos de texto de exibição porque esses valores não estão localizados. Para obter mais informações sobre como recuperar texto localizado para um objeto de classe, consulte o código de exemplo a seguir.
Ícones
A propriedade iconPath dos objetos especificadores de exibição para a localidade apropriada deve ser usada para obter o ícone a ser exibido para um objeto de classe. Para obter mais informações, consulte Ícones de classe. Se nenhum ícone localizado for especificado para um objeto de classe, um ícone padrão deverá ser exibido para o item.
Criando novos objetos
Quando possível, use os assistentes de criação de objetos apropriados para criar novos objetos. Para obter mais informações, consulte Invocando assistentes de criação de seu aplicativo.
O exemplo de código a seguir mostra como obter o texto de exibição para uma classe e um atributo de uma classe.
#include <atlbase.h>
/**************************************************************************
GetClassDisplaySpecifierContainer()
**************************************************************************/
HRESULT GetClassDisplaySpecifierContainer(LPWSTR pwszClass,
LCID locale,
IADs **ppads)
{
if((NULL == pwszClass) || (NULL == ppads))
{
return E_INVALIDARG;
}
*ppads = NULL;
// If no locale is specified, use the default system locale.
if(0 == locale)
{
locale = GetSystemDefaultLCID();
if(0 == locale)
{
return E_FAIL;
}
}
// Verify that it is a valid locale.
if(!IsValidLocale(locale, LCID_SUPPORTED))
{
return E_INVALIDARG;
}
HRESULT hr;
IADs *padsRoot = NULL;
hr = ADsOpenObject( L"LDAP://rootDSE",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)&padsRoot);
if(SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
// Get the DN to the configuration container.
hr = padsRoot->Get(CComBSTR(L"configurationNamingContext"), &var);
if(SUCCEEDED(hr))
{
WCHAR wszPath[MAX_PATH * 2];
// Build the string to bind to the container for the
// specified locale in the DisplaySpecifiers container.
swprintf_s(wszPath,
L"LDAP://cn=%s-Display,cn=%x,cn=DisplaySpecifiers,%s",
pwszClass,
locale,
var.bstrVal);
VariantClear(&var);
// Bind to the container.
hr = ADsOpenObject( wszPath,
NULL,
NULL,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)ppads);
}
padsRoot->Release();
}
return hr;
}
/**************************************************************************
GetClassDisplayLabel()
**************************************************************************/
HRESULT GetClassDisplayLabel(LPWSTR pwszClass,
LCID locale,
BSTR *pbstrClassLabel)
{
if((NULL == pwszClass) || (NULL == pbstrClassLabel))
{
return E_INVALIDARG;
}
*pbstrClassLabel = NULL;
HRESULT hr;
IADs *padsDispSpec;
hr = GetClassDisplaySpecifierContainer(pwszClass, locale, &padsDispSpec);
if(SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
// Get the classDisplayName property value.
hr = padsDispSpec->Get(CComBSTR(L"classDisplayName"), &var);
if(SUCCEEDED(hr))
{
if(VT_BSTR == var.vt)
{
// Do not free the BSTR. The caller will handle it.
*pbstrClassLabel = var.bstrVal;
}
else
{
VariantClear(&var);
hr = E_FAIL;
}
}
padsDispSpec->Release();
}
return hr;
}
/**************************************************************************
GetAttributeDisplayLabel()
**************************************************************************/
HRESULT GetAttributeDisplayLabel(LPWSTR pwszClass,
LPWSTR pwszAttribute,
LCID locale,
BSTR *pbstrAttributeLabel)
{
if( (NULL == pwszClass) ||
(NULL == pwszAttribute) ||
(NULL == pbstrAttributeLabel))
{
return E_INVALIDARG;
}
*pbstrAttributeLabel = NULL;
HRESULT hr;
IADs *padsDispSpec;
hr = GetClassDisplaySpecifierContainer(pwszClass, locale, &padsDispSpec);
if(SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
// Get the attributeDisplayNames property values
hr = padsDispSpec->GetEx(CComBSTR(L"attributeDisplayNames"), &var);
if(SUCCEEDED(hr))
{
LONG lStart,
lEnd,
i;
SAFEARRAY *psa;
VARIANT varItem;
VariantInit(&varItem);
psa = V_ARRAY(&var);
// Get the lower and upper bound.
hr = SafeArrayGetLBound(psa, 1, &lStart);
hr = SafeArrayGetUBound(psa, 1, &lEnd);
/*
The attributeDisplayNames values take the form
"<attribute name>,<display name>". Enumerate the values, looking
for the one that begins with the specified attribute name.
*/
for(i = lStart; i <= lEnd; i++)
{
hr = SafeArrayGetElement(psa, &i, &varItem);
if(SUCCEEDED(hr))
{
WCHAR wszTemp[MAX_PATH];
wcsncpy_s(wszTemp,
V_BSTR(&varItem),
lstrlenW(pwszAttribute) + 1);
if(0 == lstrcmpiW(pwszAttribute, wszTemp))
{
LPWSTR pwszDisplayLabel;
/*
The proper value was found. Now, parse the value, looking
for the first comma, which delimits the attribute name
from the display name.
*/
for( pwszDisplayLabel = V_BSTR(&varItem);
*pwszDisplayLabel;
pwszDisplayLabel = CharNextW(pwszDisplayLabel))
{
if(',' == *pwszDisplayLabel)
{
/*
The delimiter was found. Set the string
pointer to the next character, which is the
first character of the display name.
*/
pwszDisplayLabel = CharNextW(pwszDisplayLabel);
break;
}
}
if(*pwszDisplayLabel)
{
// Copy the display name to the output.
*pbstrAttributeLabel = CComBSTR(pwszDisplayLabel).Detach();
hr = S_OK;
}
/*
Release the item variant because the break prevents
it from getting released by the VariantClear call below.
*/
VariantClear(&varItem);
break;
}
VariantClear(&varItem);
}
}
}
padsDispSpec->Release();
}
return hr;
}