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. /// /// 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 ////// 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. /// ////// 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
- Activator.cs
- WebSysDefaultValueAttribute.cs
- Crypto.cs
- XPathNodePointer.cs
- DecodeHelper.cs
- DeviceContext2.cs
- MorphHelper.cs
- ConditionCollection.cs
- SessionPageStateSection.cs
- RoleManagerModule.cs
- UnsafeNativeMethods.cs
- ComplexType.cs
- WindowsSysHeader.cs
- OledbConnectionStringbuilder.cs
- BitHelper.cs
- ObjectFullSpanRewriter.cs
- EntitySqlQueryCacheEntry.cs
- DefaultEvaluationContext.cs
- NamespaceTable.cs
- GenericsNotImplementedException.cs
- OleDbPermission.cs
- Utils.cs
- webeventbuffer.cs
- DecimalAnimation.cs
- AvtEvent.cs
- ProviderSettings.cs
- HandleDictionary.cs
- MulticastDelegate.cs
- MultipartContentParser.cs
- TextContainerChangeEventArgs.cs
- Parameter.cs
- AppliedDeviceFiltersDialog.cs
- ConfigurationValidatorBase.cs
- EditingCommands.cs
- ListViewGroupItemCollection.cs
- TranslateTransform3D.cs
- Metafile.cs
- TrackBarDesigner.cs
- PostBackOptions.cs
- TransformerInfoCollection.cs
- SqlRowUpdatingEvent.cs
- XmlBinaryReader.cs
- DataGridHeadersVisibilityToVisibilityConverter.cs
- BrowserDefinition.cs
- Util.cs
- Environment.cs
- ZoneLinkButton.cs
- CollectionViewGroupRoot.cs
- MDIControlStrip.cs
- Html32TextWriter.cs
- ReflectionTypeLoadException.cs
- TimeSpanValidatorAttribute.cs
- Int16Storage.cs
- CodeEntryPointMethod.cs
- HttpWebResponse.cs
- StateBag.cs
- StyleTypedPropertyAttribute.cs
- MoveSizeWinEventHandler.cs
- DataServices.cs
- Lease.cs
- GreenMethods.cs
- FocusChangedEventArgs.cs
- AuthenticationModuleElementCollection.cs
- DeclaredTypeElement.cs
- ValueHandle.cs
- Int16KeyFrameCollection.cs
- AutomationAttributeInfo.cs
- ContentElementAutomationPeer.cs
- WebCategoryAttribute.cs
- CharConverter.cs
- ControlCachePolicy.cs
- HostProtectionException.cs
- ManagedIStream.cs
- VerificationException.cs
- DataGridViewAutoSizeColumnsModeEventArgs.cs
- TypeUsageBuilder.cs
- ForeignConstraint.cs
- Merger.cs
- ConnectionsZone.cs
- SHA256CryptoServiceProvider.cs
- StrongTypingException.cs
- VerticalAlignConverter.cs
- DataContext.cs
- SiteOfOriginPart.cs
- HostingEnvironmentSection.cs
- DataGridLinkButton.cs
- AttributeCollection.cs
- PromptBuilder.cs
- MaskedTextBox.cs
- StorageTypeMapping.cs
- MessageDecoder.cs
- DefaultAssemblyResolver.cs
- ConnectionString.cs
- DataGridViewToolTip.cs
- AuthorizationRule.cs
- ContextBase.cs
- ObjectIDGenerator.cs
- _NativeSSPI.cs
- WebBrowserBase.cs
- EventSinkHelperWriter.cs