/
DirectoryEntries.cs
168 lines (150 loc) · 6.11 KB
/
DirectoryEntries.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Runtime.InteropServices;
namespace System.DirectoryServices
{
/// <devdoc>
/// Contains the children (child entries) of an entry in the Active Directory.
/// </devdoc>
public class DirectoryEntries : IEnumerable
{
// the parent of the children in this collection
private readonly DirectoryEntry _container;
internal DirectoryEntries(DirectoryEntry parent)
{
_container = parent;
}
/// <devdoc>
/// Gets the schemas that specify which children are shown.
/// </devdoc>
public SchemaNameCollection SchemaFilter
{
get
{
CheckIsContainer();
SchemaNameCollection.FilterDelegateWrapper filter = new SchemaNameCollection.FilterDelegateWrapper(_container.ContainerObject);
return new SchemaNameCollection(filter.Getter, filter.Setter);
}
}
private void CheckIsContainer()
{
if (!_container.IsContainer)
throw new InvalidOperationException(SR.Format(SR.DSNotAContainer, _container.Path));
}
/// <devdoc>
/// Creates a request to create a new entry in the container.
/// </devdoc>
public DirectoryEntry Add(string name, string schemaClassName)
{
CheckIsContainer();
object newChild = _container.ContainerObject.Create(schemaClassName, name);
DirectoryEntry entry = new DirectoryEntry(newChild, _container.UsePropertyCache, _container.GetUsername(), _container.GetPassword(), _container.AuthenticationType);
entry.JustCreated = true; // suspend writing changes until CommitChanges() is called
return entry;
}
/// <devdoc>
/// Returns the child with the given name.
/// </devdoc>
public DirectoryEntry Find(string name)
{
// For IIS: and WinNT: providers schemaClassName == "" does general search.
return Find(name, null);
}
/// <devdoc>
/// Returns the child with the given name and of the given type.
/// </devdoc>
public DirectoryEntry Find(string name, string? schemaClassName)
{
CheckIsContainer();
// Note: schemaClassName == null does not work for IIS: provider.
object? o = null;
try
{
o = _container.ContainerObject.GetObject(schemaClassName, name);
}
catch (COMException e)
{
throw COMExceptionHelper.CreateFormattedComException(e);
}
return new DirectoryEntry(o, _container.UsePropertyCache, _container.GetUsername(), _container.GetPassword(), _container.AuthenticationType);
}
/// <devdoc>
/// Deletes a child <see cref='System.DirectoryServices.DirectoryEntry'/> from this collection.
/// </devdoc>
public void Remove(DirectoryEntry entry)
{
CheckIsContainer();
try
{
_container.ContainerObject.Delete(entry.SchemaClassName, entry.Name);
}
catch (COMException e)
{
throw COMExceptionHelper.CreateFormattedComException(e);
}
}
public IEnumerator GetEnumerator() => new ChildEnumerator(_container);
/// <devdoc>
/// Supports a simple ForEach-style iteration over a collection and defines
/// enumerators, size, and synchronization methods.
/// </devdoc>
private sealed class ChildEnumerator : IEnumerator
{
private readonly DirectoryEntry _container;
private SafeNativeMethods.EnumVariant? _enumVariant;
private DirectoryEntry? _currentEntry;
internal ChildEnumerator(DirectoryEntry container)
{
_container = container;
if (container.IsContainer)
{
_enumVariant = new SafeNativeMethods.EnumVariant((SafeNativeMethods.IEnumVariant)container.ContainerObject._NewEnum);
}
}
/// <devdoc>
/// Gets the current element in the collection.
/// </devdoc>
public DirectoryEntry Current
{
get
{
if (_enumVariant == null)
throw new InvalidOperationException(SR.DSNoCurrentChild);
return _currentEntry ??= new DirectoryEntry(_enumVariant.GetValue(), _container.UsePropertyCache, _container.GetUsername(), _container.GetPassword(), _container.AuthenticationType);
}
}
/// <devdoc>
/// Advances the enumerator to the next element of the collection
/// and returns a Boolean value indicating whether a valid element is available.
/// </devdoc>
public bool MoveNext()
{
if (_enumVariant == null)
return false;
_currentEntry = null;
return _enumVariant.GetNext();
}
/// <devdoc>
/// Resets the enumerator back to its initial position before the first element in the collection.
/// </devdoc>
public void Reset()
{
if (_enumVariant != null)
{
try
{
_enumVariant.Reset();
}
catch (NotImplementedException)
{
//Some providers might not implement Reset, workaround the problem.
_enumVariant = new SafeNativeMethods.EnumVariant((SafeNativeMethods.IEnumVariant)_container.ContainerObject._NewEnum);
}
_currentEntry = null;
}
}
object IEnumerator.Current => Current;
}
}
}