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
- FormDocumentDesigner.cs
- PlacementWorkspace.cs
- SerializationAttributes.cs
- GetPageCompletedEventArgs.cs
- SamlAuthenticationStatement.cs
- ServerValidateEventArgs.cs
- DataSourceBooleanViewSchemaConverter.cs
- SiteMapProvider.cs
- NumberFunctions.cs
- IndexObject.cs
- ObservableDictionary.cs
- ManagementBaseObject.cs
- ItemsControlAutomationPeer.cs
- SetUserLanguageRequest.cs
- ClientConvert.cs
- NameTable.cs
- InvokeMethodActivityDesigner.cs
- DataGridPagerStyle.cs
- ContextInformation.cs
- httpstaticobjectscollection.cs
- InputElement.cs
- OpenFileDialog.cs
- TimeSpanMinutesConverter.cs
- ViewUtilities.cs
- GenericUriParser.cs
- BaseValidatorDesigner.cs
- EnvironmentPermission.cs
- CodeDelegateCreateExpression.cs
- ToolStripEditorManager.cs
- RelationshipConstraintValidator.cs
- SubMenuStyle.cs
- Bezier.cs
- WindowsTreeView.cs
- ValidatorCompatibilityHelper.cs
- WinFormsUtils.cs
- ScrollChrome.cs
- XmlReaderDelegator.cs
- ColorInterpolationModeValidation.cs
- ContentFilePart.cs
- SecureStringHasher.cs
- PropertyGrid.cs
- PersianCalendar.cs
- DispatchWrapper.cs
- ScrollProperties.cs
- ITextView.cs
- Compiler.cs
- Section.cs
- HandlerMappingMemo.cs
- PackageProperties.cs
- PropertyChangingEventArgs.cs
- Utilities.cs
- Int64AnimationUsingKeyFrames.cs
- BeginStoryboard.cs
- DrawingServices.cs
- ZipPackagePart.cs
- PermissionSetEnumerator.cs
- NativeMethods.cs
- QueryProcessor.cs
- XPathQilFactory.cs
- AttributeUsageAttribute.cs
- Rotation3DAnimation.cs
- ShutDownListener.cs
- ExpressionBuilder.cs
- EnumMemberAttribute.cs
- IFlowDocumentViewer.cs
- ScriptingAuthenticationServiceSection.cs
- ProfilePropertySettingsCollection.cs
- ResourceManagerWrapper.cs
- Options.cs
- WindowsGrip.cs
- HttpCapabilitiesSectionHandler.cs
- GroupBox.cs
- EventProvider.cs
- login.cs
- IOThreadTimer.cs
- HttpContextWrapper.cs
- UnionCqlBlock.cs
- VirtualPath.cs
- UriParserTemplates.cs
- XAMLParseException.cs
- StateBag.cs
- Int32CollectionConverter.cs
- QilPatternVisitor.cs
- OleDbErrorCollection.cs
- DataBindingCollection.cs
- Compress.cs
- ServerValidateEventArgs.cs
- BridgeDataReader.cs
- nulltextnavigator.cs
- AnnotationHighlightLayer.cs
- TextFragmentEngine.cs
- TransportConfigurationTypeElementCollection.cs
- SafeProcessHandle.cs
- QilInvoke.cs
- SchemaMapping.cs
- SelectionItemPattern.cs
- CertificateReferenceElement.cs
- BlobPersonalizationState.cs
- SoapConverter.cs
- AsyncCallback.cs