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
- Matrix3DValueSerializer.cs
- PasswordRecovery.cs
- SqlMetaData.cs
- MenuItem.cs
- LogSwitch.cs
- DataShape.cs
- LicFileLicenseProvider.cs
- TreeBuilderXamlTranslator.cs
- DependencyObjectType.cs
- TdsParserSessionPool.cs
- SourceCollection.cs
- Pen.cs
- BrowserCapabilitiesFactory.cs
- GridViewAutomationPeer.cs
- Overlapped.cs
- ObjectHandle.cs
- MeasurementDCInfo.cs
- CustomError.cs
- Quaternion.cs
- PeerCustomResolverBindingElement.cs
- ToolStripGripRenderEventArgs.cs
- DropDownButton.cs
- DateBoldEvent.cs
- ControlBuilder.cs
- TextSerializer.cs
- WebEncodingValidator.cs
- Regex.cs
- DataObjectAttribute.cs
- LayoutEditorPart.cs
- HelpProvider.cs
- StrokeSerializer.cs
- BookmarkUndoUnit.cs
- KeyGestureValueSerializer.cs
- SelectionList.cs
- DataGridViewRowHeightInfoNeededEventArgs.cs
- ValueConversionAttribute.cs
- StateMachineAction.cs
- ScaleTransform3D.cs
- ClaimTypeRequirement.cs
- TemplateBindingExpression.cs
- GroupDescription.cs
- EdmConstants.cs
- SqlParameterizer.cs
- XmlSchemaSimpleContentExtension.cs
- StdValidatorsAndConverters.cs
- UriTemplateTrieLocation.cs
- ClientData.cs
- FixedDocument.cs
- DbReferenceCollection.cs
- SigningCredentials.cs
- DiscreteKeyFrames.cs
- ToolTip.cs
- TypeUtil.cs
- CodeGeneratorAttribute.cs
- ImageClickEventArgs.cs
- ChangeProcessor.cs
- XmlSchemaCollection.cs
- SafeNativeMethods.cs
- XmlSchemaElement.cs
- ProtocolInformationReader.cs
- BoolExpression.cs
- SignedInfo.cs
- UnsafeNativeMethods.cs
- FormViewUpdateEventArgs.cs
- NumericUpDownAccelerationCollection.cs
- DetailsViewDeletedEventArgs.cs
- InfoCardUIAgent.cs
- PolyLineSegment.cs
- TemplateNodeContextMenu.cs
- GlyphCache.cs
- SizeAnimationUsingKeyFrames.cs
- XhtmlBasicListAdapter.cs
- DataControlFieldTypeEditor.cs
- ManipulationStartingEventArgs.cs
- Underline.cs
- BasicKeyConstraint.cs
- WebPartsPersonalizationAuthorization.cs
- MimeReturn.cs
- RightsManagementEncryptedStream.cs
- ExpressionWriter.cs
- dtdvalidator.cs
- SecurityElement.cs
- ServiceDescriptionReflector.cs
- ObsoleteAttribute.cs
- LayoutInformation.cs
- SharedStatics.cs
- SoapTypeAttribute.cs
- MenuCommands.cs
- DateTimeUtil.cs
- WSFederationHttpBindingCollectionElement.cs
- XmlDataCollection.cs
- SqlErrorCollection.cs
- HtmlButton.cs
- FontNamesConverter.cs
- DocumentEventArgs.cs
- TextElement.cs
- BrowserTree.cs
- EmbeddedObject.cs
- SafeThreadHandle.cs
- VariantWrapper.cs