Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / TrustUi / MS / Internal / documents / PeoplePickerWrapper.cs / 1 / PeoplePickerWrapper.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
//
// Description: PeoplePickerWrapper provides a managed wrapper around
// the unmanaged ActiveDirectory ICommonQuery COM object.
//
//
// History:
// 8/16/2005 - [....] created
//
//---------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security; // for SecurityCritical attributes
using System.Security.Permissions;
using System.Windows.TrustUI;
using MS.Internal.PresentationUI;
namespace MS.Internal.Documents
{
///
/// PeoplePickerWrapper provides a managed wrapper around
/// the unmanaged ActiveDirectory ICommonQuery COM object
///
internal partial class PeoplePickerWrapper
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
///
/// Constructs a new PeoplePickerWrapper object.
///
internal PeoplePickerWrapper()
{
}
#endregion Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
///
/// Invokes the "People Picker" dialog and returns a list of strings
/// representing the email address of the users and groups selected therein.
///
/// Critical: - This method is the "public" (internal) entry point for invoking
/// the unmanaged ActiveDirectory directory service query dialog and
/// thus calls several SecurityCritical methods.
/// - It also returns "critical" data - a list of e-mail addresses
/// selected by the user.
/// - Asserts for UIPermission to call ValidateHWnd.
///
///
/// The parent window for this dialog. If null, window will
/// be shown non-modally.
[SecurityCritical]
internal String[] Show(IntPtr hWndParent)
{
(new UIPermission(UIPermissionWindow.AllWindows))
.Assert(); // BlessedAssert
try
{
ValidateHWnd(hWndParent);
}
finally
{
UIPermission.RevertAssert();
}
IDataObject data = OpenQueryWindow(hWndParent);
//If the data returned from OpenQueryWindow is null,
//it means no data was entered in the dialog so we will
//return null. Otherwise we need to extract the data
//from the returned IDataObject object.
if (data != null)
{
//Get a MemoryStream that contains the data contained in the
//IDataObject (which is a raw form of a DsObjects struct).
System.IO.MemoryStream dsObjectStream = null;
System.Windows.DataObject dataObject;
//We need UIPermissionClipboard.AllClipboard and UnmanagedCode permissions
//to call the DataObject.ctor and DataObject.GetData() method:
PermissionSet permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new UIPermission(UIPermissionClipboard.AllClipboard));
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
//Assert these permissions
permissions.Assert(); //BlessedAssert
try
{
dataObject = new System.Windows.DataObject(data);
dsObjectStream =
dataObject.GetData(
UnsafeNativeMethods.CFSTR_DSOBJECTNAMES) as System.IO.MemoryStream;
}
finally
{
PermissionSet.RevertAssert();
}
//Extract the data from that memory stream. These will come back as
//ActiveDirectory paths in the form 'LDAP://CN=...'
String[] ldapPaths = new String[0];
//Get a wrapper for the DsObjectNames object our pointer points to.
DsObjectNamesWrapper dsObjects = new DsObjectNamesWrapper(dsObjectStream);
try
{
//Get the names from the DsObjectNamesWrapper (these are AD paths)
ldapPaths = dsObjects.Names;
}
finally
{
dsObjects.Dispose();
dsObjectStream.Close();
}
//Get a set of e-mail addresses from the paths using AD and return them.
return GetEmailAddressesFromPaths(ldapPaths);
}
else
{
return new String[0];
}
}
#endregion Internal Methods
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
///
/// Instantiates an ICommonQuery COM object and invokes OpenQueryWindow on it
/// with the necessary parameters to bring up the "people picker" portion of
/// the dialog.
///
///
/// Critical: We are creating an instance of an unmanaged COM object
/// (ICommonQuery) in this method and invoking a method
/// (OpenQueryWindow) on it and thus need to assert
/// UnmanagedCode permissions.
///
///
///
/// The HWND for the ICommonQuery.OpenQueryWindow call which
/// defines the parent of the dialog.
[SecurityCritical]
private IDataObject OpenQueryWindow(IntPtr hWndParent)
{
UnsafeNativeMethods.ICommonQuery commonQueryInstance = null;
Type commonQueryType = Type.GetTypeFromCLSID(UnsafeNativeMethods.CLSID_CommonQuery);
//Assert for UnmanagedCode permission, which is necessary for Activator.CreateInstance
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //BlessedAssert
try
{
//Get an instance of the ICommonQuery COM object.
commonQueryInstance = Activator.CreateInstance(commonQueryType)
as UnsafeNativeMethods.ICommonQuery;
}
finally
{
//Revert the assert
SecurityPermission.RevertAssert();
}
Invariant.Assert(commonQueryInstance != null, "Unable to create an instance of ICommonQuery.");
//Set up the QueryInitParams -- this is essentially empty as we require no special flags,
//default usernames, passwords or server information for our purposes.
UnsafeNativeMethods.QueryInitParams queryInitParams =
new UnsafeNativeMethods.QueryInitParams();
queryInitParams.cbStruct =
(uint)Marshal.SizeOf(typeof(UnsafeNativeMethods.QueryInitParams));
queryInitParams.dwFlags = 0;
queryInitParams.pDefaultScope = null;
queryInitParams.pDefaultSaveLocation = null;
queryInitParams.pUserName = null;
queryInitParams.pPassword = null;
queryInitParams.pServer = null;
//Allocate memory for our QueryInitParams structure that will be used in the
//OpenQueryWindowParams structure.
IntPtr queryInitParamsPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(queryInitParams));
//Now try to invoke the OpenQueryWindow method
uint hresult = UnsafeNativeMethods.E_FAIL;
IDataObject data = null;
try
{
//Stuff the queryInitParams into a pointer (that we can assign to
//OpenQueryWindowParams.pHandlerParameters below).
Marshal.StructureToPtr(queryInitParams, queryInitParamsPtr, false /*fDeleteOld*/);
//Set up the OpenQueryWindowParams.
//We require the default form with:
// - The specified "Find Users" default form
// - "OK and Cancel" buttons shown
// - Options enabled
// - No "Find:" dropdown (for things other than users)
// - No menus
// - Single item selection
UnsafeNativeMethods.OpenQueryWindowParams openQueryWindowParams =
new UnsafeNativeMethods.OpenQueryWindowParams();
openQueryWindowParams.cbStruct =
(uint)Marshal.SizeOf(typeof(UnsafeNativeMethods.OpenQueryWindowParams));
openQueryWindowParams.dwFlags = UnsafeNativeMethods.OQWF_DEFAULTFORM |
UnsafeNativeMethods.OQWF_OKCANCEL |
UnsafeNativeMethods.OQWF_SHOWOPTIONAL |
UnsafeNativeMethods.OQWF_REMOVEFORMS |
UnsafeNativeMethods.OQWF_HIDEMENUS;
openQueryWindowParams.clsidHandler = UnsafeNativeMethods.CLSID_DsQuery;
openQueryWindowParams.pHandlerParameters = queryInitParamsPtr;
openQueryWindowParams.clsidDefaultForm =
UnsafeNativeMethods.CLSID_DsFindPeople; //Bring up the people picker
openQueryWindowParams.pPersistQuery = IntPtr.Zero; //We aren't persisting this query anywhere
openQueryWindowParams.pFormParameters = IntPtr.Zero; //We aren't pre-populating the form
//Invoke the OpenQueryWindow method on the ICommonQuery object,
//which will invoke the dialog and return any entered data in the
//"data" field.
//OpenQueryWindow will not return until the dialog is closed.
hresult = commonQueryInstance.OpenQueryWindow(hWndParent,
ref openQueryWindowParams,
out data);
}
finally
{
//Free the memory used for our QueryInitParams structure.
Marshal.FreeCoTaskMem(queryInitParamsPtr);
commonQueryInstance = null;
}
if (hresult == UnsafeNativeMethods.S_OK)
{
//The user pressed "OK," so we can return the selected data
return data;
}
else if (hresult == UnsafeNativeMethods.S_FALSE)
{
//The user canceled out, so we just return null.
return null;
}
else
{
//An error condition was reported, we throw an exception with the
//hresult included.
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture,
SR.Get(SRID.PeoplePickerErrorConditionFromOpenQueryWindow), hresult));
}
}
///
/// Turns a set of AD paths (in the form 'LDAP://CN=...') into a set of
/// e-mail addresses by looking up the paths in the Directory and retrieving
/// the 'mail' property, if it exists for the given AD object.
///
///
/// Critical: We assert DirectoryServices Permissions here in order to
/// get information about a DirectoryEntry.
///
///
///
[SecurityCritical]
private String[] GetEmailAddressesFromPaths(String[] paths)
{
List addresses = new List(paths.Length);
for (int i = 0; i < paths.Length; i++)
{
PropertyValueCollection emailCollection = null;
DirectoryEntry directoryEntry = null;
//Assert for DirectoryServicesPermissions.
//This unfortunately must be for Unrestricted permissions because the
//DirectoryEntry ctor makes a demand for Unrestricted permissions.
new DirectoryServicesPermission(
PermissionState.Unrestricted).Assert(); //BlessedAssert
try
{
//Create a DirectoryEntry pointing to the current path;
//Attempt to retrieve the "mail" field.
directoryEntry = new DirectoryEntry(paths[i]);
}
finally
{
//Revert the DirectoryServicesPermission assert
DirectoryServicesPermission.RevertAssert();
}
emailCollection =
directoryEntry.Properties[_adEmailAddressKey];
if (emailCollection != null && emailCollection.Count > 0)
{
//We have a non-empty e-mail collection; we will add the
//first available e-mail address.
String address = emailCollection[0] as String;
if (address != null)
{
addresses.Add(address);
}
}
}
return addresses.ToArray();
}
///
/// Verifies that the given parent HWND is either null or an RMPublishingDialog
/// Windows Form.
///
///
///
///
/// Critical: - Takes a pointer to an HWnd which it uses to validate.
///
[SecurityCritical]
private void ValidateHWnd(IntPtr hWndParent)
{
if( hWndParent != IntPtr.Zero )
{
System.Windows.Forms.Control rmPublishingDialog =
System.Windows.Forms.Control.FromHandle(hWndParent) as RMPublishingDialog;
if (rmPublishingDialog == null)
{
throw new InvalidOperationException(SR.Get(SRID.PeoplePickerInvalidParentWindow));
}
}
}
#endregion Private Methods
//-----------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
#region Private Fields
//The key name for the ActiveDirectory E-Mail address property
private const String _adEmailAddressKey = "mail";
#region DsObjectNamesWrapper Class
///
/// The DsObjectNamesWrapper class wraps a DsObjectNames Struct thus hiding
/// the complexity of the unmanaged->managed mangling that's necessary to
/// retrieve the object names we need therein.
///
/// This is used in PeoplePickerWrapper.ParseDataFromHandle to simplify the code.
///
private class DsObjectNamesWrapper : IDisposable
{
///
/// Static constructor for DsObjectNamesWrapper.
///
///
/// Critical:
/// 1) We have non-critical static constants that make use of Marshal.SizeOf() to
/// calculate sizes and offsets, which cause a link demand when invoked.
/// Having a Critical static constructor allows these demands to be satisfied.
///
[SecurityCritical]
static DsObjectNamesWrapper()
{
// Do not remove! (See above Security comment)
}
///
/// Constructs a new DsObjectNamesWrapper given a MemoryStream containing
/// a raw representation of a DsObjectNames object.
///
///
/// Critical:
/// 1) Manipulates critical data fields
///
/// A pointer to a valid DsObjectNames struct
[SecurityCritical]
internal DsObjectNamesWrapper(System.IO.MemoryStream dataStream)
{
if (dataStream == null)
{
throw new ArgumentNullException("dataStream");
}
//We need to get a pointer to this data for our DsObjectNamesWrapper
//to wrap.
//First we convert the stream to an array of bytes.
byte[] data = dataStream.ToArray();
//Allocate memory to store an unmanaged copy of this data
_ptrToDsObjectNames = Marshal.AllocHGlobal(data.Length);
Invariant.Assert(_ptrToDsObjectNames != IntPtr.Zero, "Invalid pointer to DsObjectNames data.");
//Marshal the data over to the unmanaged side
Marshal.Copy(data, 0, _ptrToDsObjectNames, data.Length);
//Get a DsObjectNames structure out of the pointer we
//were handed.
_dsObjectNames =
(UnsafeNativeMethods.DsObjectNames)Marshal.PtrToStructure(
_ptrToDsObjectNames, typeof(UnsafeNativeMethods.DsObjectNames));
}
///
/// Finalizer for DsObjectNamesWrapper, ensures that unmanaged resources are properly
/// cleaned up.
///
///
/// Critical:
/// 1) Invokes the Dispose method which is Critical.
///
[SecurityCritical]
~DsObjectNamesWrapper()
{
this.Dispose();
}
///
/// The number of names in the DsObjectNames struct this class is wrapping.
///
///
/// Critical:
/// 1) Manipulates critical data fields
///
internal uint Count
{
[SecurityCritical]
get
{
ThrowIfDisposed();
return _dsObjectNames.cItems;
}
}
///
/// An array of names contained within the DsObjectNames struct.
///
///
/// Critical:
/// 1) Manipulates critical data fields
///
internal String[] Names
{
[SecurityCritical]
get
{
ThrowIfDisposed();
if (_names == null)
{
_names = GetNamesFromDsObjectStruct();
}
return _names;
}
}
///
/// Gets the list of names from the struct.
///
///
///
/// Critical:
/// 1) Manipulates critical data fields
///
///
[SecurityCritical]
private String[] GetNamesFromDsObjectStruct()
{
ThrowIfDisposed();
String[] names = new string[Count];
for (int i = 0; i < Count; i++)
{
names[i] = BuildStringForItemName(i);
}
return names;
}
///
/// Extracts the name for the specified entry number from the DsObjectNames data
///
///
/// Critical:
/// 1) Manipulates critical data fields
///
/// The index of the name to retrieve
///
[SecurityCritical]
private String BuildStringForItemName(int index)
{
ThrowIfDisposed();
//Ensure we're within proper bounds.
if (index < 0 || index >= Count)
{
throw new ArgumentOutOfRangeException("index");
}
//First we have to get a DsObject out of the array (aObjects) of DsObjects.
//The information in this struct will tell us where to find the name data
//we want.
UnsafeNativeMethods.DsObject dsObject = GetDsObjectForIndex(index);
//The offset of the name from the start of the DsObjectNames structure is stored in
//the corresponding DsObject's offsetName field, so the pointer to the beginning of the
//string can be computed as:
//
// offset = StartOfStructAddress + dsObject.offsetName;
IntPtr nameOffset = new IntPtr(_ptrToDsObjectNames.ToInt64() + dsObject.offsetName);
//We marshal this pointer to a string and return it.
return Marshal.PtrToStringAuto(nameOffset);
}
///
/// Retrieves a DsObject structure from the "array" in our DsObjectNames structure.
/// Because marshalling cannot properly marshal a nested, variable sized
/// array in a struct, we have to do this the hard way.
/// That is, the "array" of DsObjects that's in our managed DsObjectNames structure
/// definition is merely a pointer to a big chunk of data that we have to manually
/// retrieve DsObjects from by manipulating pointers, rather than doing aObjects[i].
///
///
/// Critical:
/// 1) Manipulates critical data fields
///
/// The index of the DsObject to retrieve
///
[SecurityCritical]
private UnsafeNativeMethods.DsObject GetDsObjectForIndex(int index)
{
ThrowIfDisposed();
//Ensure we're within proper bounds.
if (index < 0 || index >= Count)
{
throw new ArgumentOutOfRangeException("index");
}
//Now we calculate the offset of the specified array index.
//This is the address of the first element in the array, plus
//the number of entries past that times the size of an entry, or:
//offset = StartOfStructAddress + FirstArrayEntryOffset + index * SizeOfEntry
IntPtr offset = new IntPtr(_ptrToDsObjectNames.ToInt64() +
_dsObjectArrayFieldOffset +
index * _sizeOfDsObject);
//Marshal that to a DsObject structure.
UnsafeNativeMethods.DsObject dsObject =
(UnsafeNativeMethods.DsObject)Marshal.PtrToStructure(offset,
typeof(UnsafeNativeMethods.DsObject));
return dsObject;
}
///
/// Implemented to deal with FxCop rule UseSafeHandleToEncapsulateNativeResources
/// We can now assert that the code will not allow methods to be called after
/// we are disposed.
///
private void ThrowIfDisposed()
{
if (_isDisposed) throw new ObjectDisposedException("DsObjectNamesWrapper");
}
///
/// Cleans up the unmanaged memory allocations made by this object.
///
///
/// Critical:
/// 1) Frees unmanaged memory
///
[SecurityCritical]
public void Dispose()
{
lock (this)
{
if (!_isDisposed)
{
Marshal.FreeHGlobal(_ptrToDsObjectNames);
_isDisposed = true;
GC.SuppressFinalize(this);
}
}
}
#region Private Fields
//-----------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
///
/// Pointer to the DsObjectNames struct we're wrapping.
/// We use this to calculate pointers to field offsets.
///
///
/// This is critical data both for set and get.
///
[SecurityCritical]
private IntPtr _ptrToDsObjectNames;
///
/// The list of names in the DsObjectNames struct
///
///
/// This is critical data both for set and get.
///
[SecurityCritical]
private String[] _names;
///
/// The DsObjectNames struct we're wrapping.
///
///
/// This is critical data both for set and get.
///
[SecurityCritical]
private UnsafeNativeMethods.DsObjectNames _dsObjectNames;
private bool _isDisposed;
/// Useful constants:
///
/// The offset from the start of a DsObjectNames structure to the
/// DsObjects array.
///
private static readonly int _dsObjectArrayFieldOffset =
Marshal.SizeOf(typeof(Guid)) + Marshal.SizeOf(typeof(UInt32));
///
/// The size of a DsObject.
///
private static readonly int _sizeOfDsObject =
Marshal.SizeOf(typeof(UnsafeNativeMethods.DsObject));
#endregion Private Fields
}
#endregion DsObjectNamesWrapper Class
#endregion Private Fields
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MetadataException.cs
- WindowsGraphics.cs
- ParserStreamGeometryContext.cs
- DetailsViewInsertEventArgs.cs
- SizeAnimationBase.cs
- TraceListeners.cs
- MemberHolder.cs
- UserMapPath.cs
- WebPartDescriptionCollection.cs
- CollectionViewGroupRoot.cs
- DropDownList.cs
- CachedBitmap.cs
- OleDbException.cs
- GroupQuery.cs
- HandlerFactoryCache.cs
- ConnectionConsumerAttribute.cs
- JsonServiceDocumentSerializer.cs
- DBBindings.cs
- EventDescriptor.cs
- ObjectSerializerFactory.cs
- ObjectDataSourceStatusEventArgs.cs
- FlowDecisionLabelFeature.cs
- SHA1.cs
- SemanticResultValue.cs
- CodeConditionStatement.cs
- ConsoleEntryPoint.cs
- WebPartZoneCollection.cs
- _UriSyntax.cs
- RenderData.cs
- WindowsEditBox.cs
- __ConsoleStream.cs
- EdmMember.cs
- ProfessionalColorTable.cs
- MetadataArtifactLoader.cs
- ContainerControlDesigner.cs
- AdornerHitTestResult.cs
- MenuBindingsEditorForm.cs
- CharStorage.cs
- ResourceSetExpression.cs
- SerializableAttribute.cs
- XmlToDatasetMap.cs
- RegexParser.cs
- SrgsRuleRef.cs
- CircleEase.cs
- SQLResource.cs
- StringExpressionSet.cs
- DiscoveryReferences.cs
- AcceptorSessionSymmetricTransportSecurityProtocol.cs
- DataFormat.cs
- HandleRef.cs
- EmptyStringExpandableObjectConverter.cs
- DrawItemEvent.cs
- PanningMessageFilter.cs
- EventLogEntryCollection.cs
- ServiceContractViewControl.cs
- RijndaelManagedTransform.cs
- InterleavedZipPartStream.cs
- Vector3dCollection.cs
- ProgramNode.cs
- ProxyWebPartConnectionCollection.cs
- ManagedFilter.cs
- EdmComplexPropertyAttribute.cs
- ProfileSettingsCollection.cs
- RelationHandler.cs
- FixedLineResult.cs
- EventPrivateKey.cs
- ConnectorDragDropGlyph.cs
- DynamicILGenerator.cs
- GatewayDefinition.cs
- XmlWriterSettings.cs
- TimeoutHelper.cs
- DecimalConstantAttribute.cs
- WindowsListViewItem.cs
- TextBounds.cs
- WebPartActionVerb.cs
- ObfuscationAttribute.cs
- RequestCacheValidator.cs
- XMLSchema.cs
- DataSourceXmlSerializer.cs
- XmlNamespaceMapping.cs
- ChildrenQuery.cs
- XmlSchemaSimpleTypeList.cs
- SqlFunctionAttribute.cs
- PolyBezierSegmentFigureLogic.cs
- _AutoWebProxyScriptEngine.cs
- PeerNearMe.cs
- MachineSettingsSection.cs
- ServiceHostFactory.cs
- DataGridParentRows.cs
- TouchDevice.cs
- SourceExpressionException.cs
- SettingsAttributeDictionary.cs
- PenThreadWorker.cs
- ChannelPool.cs
- CodeMethodMap.cs
- CallbackValidatorAttribute.cs
- Models.cs
- TdsValueSetter.cs
- TextStore.cs
- DataGridTemplateColumn.cs