Active Directory objects contain a lot of data. Just a single user object has over 200 possible attributes. Presenting information about an Active Directory object to end users and administrators is quite a challenge. Each object class in Active Directory has a number of user interface elements you can use when working with objects of that class. They include the following:
Network administrators have probably already worked with some of these components when setting up Active Directory. These components are also part of various Active Directory Microsoft Management Console (MMC) snap-ins such as Active Directory Users and Computers. Figures 8-5 and 8-6 illustrate how Active Directory objects are presented and manipulated using the MMC snap-ins.
Figure 8-5 Active Directory Users and Computers console showing various user interface elements for objects.
Figure 8-6 User object properties page.
Administrators and developers are not the only users who can view the contents of the directory. Active Directory extends Windows to enable viewing the directory by end users. For example, users can use tools such as Windows Explorer and the common dialog boxes to browse and search the directory. The following illustration shows the same directory location as Figure 8-5 does, but this view is in Windows Explorer.
Property pages for directory objects are displayed differently in the Windows shell from what they are in MMC. Here's a property page presented by the Windows shell. It's for the same user as shown in Figure 8-6, but the information is presented in a form more suitable for end users than administrators. Of course, an end user cannot change anything that he or she does not have access to.
Each object class in Active Directory has a schema object that defines the properties of the class. However, information about the user interface elements associated with objects of a class are not stored in the schema. Instead, information about the user interface elements available for a particular object class (including property pages, context menus, and creation wizards) is stored in objects known as display specifiers. The displaySpecifier class contains a number of attributes, listed in Table 8-3, that allow applications to load property pages, display icons and context menus, and map displayable field labels and attribute names.
displaySpecifier Attribute | Description |
---|---|
adminContextMenu | Context menus for administrative tools. Each value is the CLSID of a COM context menu object and the loading order. Each context menu object can supply one or more menu items. Alternatively, a command line can be used to launch an application. (This attribute is multivalued.) |
adminPropertyPages | Property pages for administrative tools. Each value is the CLSID of a COM property page object. Can also specify the position number and optional data to be passed to a property page. (This attribute is multivalued.) |
attributeDisplayNames | Display names for class attributes. Each value is a Unicode string with the attribute name and the localized, friendly display name. (This attribute is multivalued.) |
classDisplayName | Unicode string with localized, friendly display name of the class. |
contextMenu | Context menus for shell and nonadministrative tools. Each value is the loading order number and CLSID of a COM object supporting the IContextMenu and IShellExtInit interfaces. Each context menu object can supply one or more menu items. Alternatively, a command line can be used to launch an application. (This attribute is multivalued.) |
createDialog | Used to control how the User and Contact creation wizards format the Full Name field and thus the cn attribute for new objects. |
createWizardExt | Creation wizards for objects of this class. Each value is the CLSID of a COM object supporting the IDsAdminNewObjExt interface. |
creationWizard | Primary creation wizard for objects of this class. Value is the CLSID of a COM object supporting the IDsAdminNewObjExt interface. |
iconPath | Icons representing this class. Each value contains the state of the icon, the path to the resource file, and the resource index. |
queryFilter | Unknown |
scopeFlags | Unknown |
shellContextMenu | Not used and incorrectly documented. Use contextMenu instead. |
shellPropertyPages | Property pages for shell and nonadministrative tools. Each value is the CLSID of a COM property page object. Can also specify the position number and optional data to be passed to property page. (This attribute is multivalued.) |
treatAsLeaf | This attribute indicates that although the class might be defined in the schema as a container, it should not be shown as one by the user interface. The computer class has this attribute set. |
Table 8-3 Attributes of the displaySpecifier class.
The purpose of the createDialog attribute is not described in the Active Directory documentation and none of the default display specifiers use it. However, Microsoft Knowledge Base article Q250455 explains that you can use this attribute to control how the User and Contact creation wizards format the Full Name field and thus the cn attribute for new objects. The createDialog attribute isn't set by default, and this results in an order of first name, middle initials, and last name. To set a different format, modify the createDialog attribute of the display specifier. For example, to use the order last name, first name, use the following string:
%<sn>, %<givenName> %<initials>
The angle brackets are required and any attribute of the user or contact class can be used.
Each class has one or more instances of the displaySpecifier class that contains information about how to display objects of that class.
The user class, for example, includes a user-Display displaySpecifier object, located in a container in the configuration partition of Active Directory. The name of the object is derived by taking the name of the class object and appending "-Display."
An important part of the displaySpecifier object is something we abbreviated as I18N at Microsoft—internationalization. Windows 2000 is available in dozens of languages and Active Directory must support each of those languages. The process of converting a software product into other languages is known as localization. All the Active Directory user interface elements are localized in each of the languages that Windows 2000 supports. Technically, "languages" is misleading; the correct term is locale, which is a term specifying a particular language and optional settings for a certain geographical or geopolitical region or cultural group.
Active Directory in Windows 2000 comes with support for 24 locales, which are listed in Table 8-4.
Locale | Language |
---|---|
0x0401 | Arabic (Saudi Arabia) |
0x0404 | Chinese (Taiwan) |
0x0405 | Czech |
0x0406 | Danish |
0x0407 | German (Standard) |
0x0408 | Greek |
0x0409 | English (United States) |
0x040B | Finnish |
0x040C | French (Standard) |
0x040D | Hebrew |
0x040E | Hungarian |
0x0410 | Italian (Standard) |
0x0411 | Japanese |
0x0412 | Korean |
0x413 | Dutch |
0x414 | Norwegian |
0x0415 | Polish |
0x0416 | Portuguese (Brazil) |
0x0419 | Russian |
0x041D | Swedish |
0x041F | Turkish |
0x0804 | Chinese (PRC) |
0x0816 | Portuguese (Standard) |
0x0C0A | Spanish (Modern Sort) |
Table 8-4 Locales supported in Active Directory.
The IDsDisplaySpecifier interface is available to help applications work with objects of the displaySpecifier class. You use IDsDisplaySpecifier to avoid having to get the displaySpecifier object manually and figuring out its location based on the current locale.
The IDsDisplaySpecifier interface represents a DsDisplaySpecifier object, which must be instantiated using the COM CoCreateInstance function. Unlike the IADsXXX interfaces, IDsDisplaySpecifier is a utility interface and isn't bound to any particular object. In reality, it's a thin wrapper around Win32 API–style functions and not very COM-like in its implementation.
IDsDisplaySpecifier does not inherit from IDispatch and there is no type library available for it. This means it cannot be used from Visual Basic or the scripting languages. However, the regular IADs interface can be substituted to bind to the xxx-Display object and retrieve attribute values.
Table 8-5 lists the methods for the IDsDisplaySpecifier interface.
IDsDisplaySpecifier Method | Description |
---|---|
EnumClassAttributes | Uses a supplied callback function to enumerate each attribute of the class in order to retrieve the friendly attribute name. |
GetAttributeADsType | Returns the ADSTYPE of a specified attribute. |
GetClassCreationInfo | Retrieves the property pages of a class creation wizard. |
GetDisplaySpecifier | Binds to a locale-dependent displaySpecifier object for the class specified. Must call the SetServer method beforehand to indicate where to find the object. |
GetFriendlyAttributeName | Returns the localized version of the specified attribute name. |
GetFriendlyClassName | Returns a localized name of the specified class. |
GetIcon | Loads the resource containing the icon and returns a HICON handle to it. |
GetIconLocation | Retrieves the filename and resource ID of the icon for the specified object class. |
IsClassContainer | Tests whether a class is a container. |
SetLanguageID | Sets the locale to use when retrieving display specifier information. |
SetServer | Sets the preferred server to be used to gather display specifier information. |
Table 8-5 Methods of the IDsDisplaySpecifier interface.
Listing 8-5 shows some sample code that puts display specifiers to work. In it, I gather information about an object class using the IDsDisplaySpecifier interface.
int WINAPI _tWinMain( HINSTANCE/*hInstance*/,
HINSTANCE/*hPrevInstance*/,
LPSTR/*lpCmdLine*/, int/*nCmdShow*/)
{
// Initialize COM
HRESULT hResult;
CoInitialize( NULL );
//-------------------------------------------
// Browse to an object
//-------------------------------------------
// Set options for browsing dialog
DSBROWSEINFO dsbInfo = { 0 };
dsbInfo.cbStruct = sizeof( dsbInfo ); // Set size for version purpose dsbInfo.hwndOwner = NULL; // Window handle
dsbInfo.pszCaption = _TEXT("Browse for object"); // Text for title bar
dsbInfo.pszTitle =
_TEXT("Choose an object to display class information.");
dsbInfo.pszRoot = NULL; // No root
dsbInfo.dwFlags = // Option flags
// DSBI_CHECKBOXES | // Not currently used
DSBI_ENTIREDIRECTORY | // Include all trusted domains
DSBI_EXPANDONOPEN | // Expand tree to pszPath
DSBI_IGNORETREATASLEAF | // Show all possible containers
DSBI_INCLUDEHIDDEN | // Show hidden objects
// DSBI_NOBUTTONS | // Remove [+] [-] in tree view
// DSBI_NOLINES | // Don't draw lines
// DSBI_NOLINESATROOT | // Don't draw lines from root down
// DSBI_NOROOT | // Don't show the root object
// DSBI_RETURN_FORMAT | // Format paths based on ADS_FORMAT_*
DSBI_RETURNOBJECTCLASS ; // Fill in pszObject class
// DSBI_SIMPLEAUTHENTICATE // Don't use secure authenication
// Function to call back
dsbInfo.pfnCallback = NULL;
// Initialize message-specific data to 0
dsbInfo.lParam = 0;
// Format ADsPaths using X.500
dsbInfo.dwReturnFormat = ADS_FORMAT_X500;
// Specify current user name
dsbInfo.pUserName = NULL;
// Specify current user password
dsbInfo.pPassword = NULL;
// Must be wide string, not TCHAR
WCHAR pszObjectClass[MAX_PATH];
// Buffer to hold class name
dsbInfo.pszObjectClass = pszObjectClass;
// Size of classname buffer
dsbInfo.cchObjectClass = MAX_PATH;
// ADsPath to hold results
WCHAR pszResult[MAX_PATH] = { NULL };
// Place result in here
dsbInfo.pszPath = pszResult;
// Size of path buffer
dsbInfo.cchPath = MAX_PATH;
// Display browser dialog
hResult = DsBrowseForContainer( &dsbInfo ); if ( hResult == IDOK )
{
//-------------------------------------------
// Create an instance of the DsDisplaySpecifier
//-------------------------------------------
IDsDisplaySpecifier *pobjDSDSpecifier = NULL;
HRESULT hResult = CoCreateInstance( CLSID_DsDisplaySpecifier,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsDisplaySpecifier,
(void **) &pobjDSDSpecifier);
// Ensure object was created
if ( SUCCEEDED( hResult ) )
{
//-------------------------------------------
// Initialize DsDisplaySpecifier parameters
//-------------------------------------------
// Set default locale to look up display specifiers.
// 0=Current locale
// Note: Shown for example only, normally redundant.
hResult = pobjDSDSpecifier->SetLanguageID( 0 );
//-------------------------------------------
// Get class information
//-------------------------------------------
// Get Friendly Class Name
const int cchFriendlyName = 100;
unsigned short pszFriendlyName[ cchFriendlyName ] = { NULL };
hResult = pobjDSDSpecifier->GetFriendlyClassName(
pszObjectClass, // Name of class to look up
pszFriendlyName, // Buffer to store friendly name
cchFriendlyName); // Number of characters available
// Get icon location
// Must use GetIconLocation and LoadLibraryEx to
// load the icon for use by MessageBoxIndirect
INT residIcon;
const int cchIconPathname = MAX_PATH;
_TCHAR pszIconPathname[cchIconPathname] = { NULL };
hResult = pobjDSDSpecifier->GetIconLocation(
pszObjectClass, // Name of class to look up
DSGIF_ISNORMAL, // Get the normal icon
pszIconPathname, // Pathname of file containing icon
cchIconPathname, // Number of characters available
&residIcon); // Resource ID of icon in file HINSTANCE hInstance = NULL;
if ( SUCCEEDED ( hResult ) )
{
// Load the file with the icon resource
hInstance = LoadLibraryEx ( pszIconPathname,
NULL,
LOAD_LIBRARY_AS_DATAFILE);
}
// Is Container?
_TCHAR *prgszBooleanText[2] = { _T("No"), _T("Yes") };
BOOL bIsContainer = FALSE;
bIsContainer = pobjDSDSpecifier->IsClassContainer(
pszObjectClass, // Name of class to lookup
NULL, // ???
0 ); // Or DSICCF_IGNORETREATASLEAF
if (bIsContainer)
bIsContainer = 1;
else
bIsContainer = 0;
//-------------------------------------------
// Display class information
//-------------------------------------------
// Format information string
_TCHAR pszMessage[1024] = { NULL };
_stprintf( pszMessage,
_T("ADsPath: \t%ws \nClass Name: \t%ws \nFriendly Name:
\t%ws \nContainer: \t%ws \nIcon Location: \t%ws \nIcon
ResID: \t%d"),
pszResult,
pszObjectClass,
pszFriendlyName,
prgszBooleanText[bIsContainer],
pszIconPathname,
-residIcon);
// Parameters for message box
MSGBOXPARAMS mbParameters;
mbParameters.cbSize = sizeof( MSGBOXPARAMS );
mbParameters.hwndOwner = NULL;
mbParameters.hInstance = hInstance;
mbParameters.lpszText = pszMessage;
mbParameters.lpszCaption = _T("Display Specifier Information");
mbParameters.dwStyle = MB_USERICON | MB_OK; mbParameters.lpszIcon = MAKEINTRESOURCE( -residIcon );
mbParameters.dwContextHelpId = 0;
mbParameters.lpfnMsgBoxCallback = NULL;
mbParameters.dwLanguageId = 0;
// Display message box with icon
MessageBoxIndirect( &mbParameters );
}
}
// Uninitialize COM
CoUninitialize ();
// Exit with any lingering hResult
return ( hResult );
}
Listing 8-5 DsDisplaySpecifier.cpp showing how to use display specifiers.
When you run this sample, select an object, and click OK, the display specifier information, along with the corresponding class icon, is displayed in a dialog box as shown in Figure 8-7.
Figure 8-7 Output of the DsDisplaySpecifier sample for a selected object.