1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections;
6 using System.Runtime.InteropServices;
7 
8 namespace System.Management
9 {
10     //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//
11     /// <summary>
12     ///    <para> Represents the set of methods available in the collection.</para>
13     /// </summary>
14     /// <example>
15     ///    <code lang='C#'>using System;
16     /// using System.Management;
17     ///
18     /// // This sample demonstrates enumerate all methods in a ManagementClass object.
19     /// class Sample_MethodDataCollection
20     /// {
21     ///     public static int Main(string[] args) {
22     ///         ManagementClass diskClass = new ManagementClass("win32_logicaldisk");
23     ///         MethodDataCollection diskMethods = diskClass.Methods;
24     ///         foreach (MethodData method in diskMethods) {
25     ///             Console.WriteLine("Method = " + method.Name);
26     ///         }
27     ///         return 0;
28     ///     }
29     /// }
30     ///    </code>
31     ///    <code lang='VB'>Imports System
32     /// Imports System.Management
33     ///
34     /// ' This sample demonstrates enumerate all methods in a ManagementClass object.
35     /// Class Sample_MethodDataCollection
36     ///     Overloads Public Shared Function Main(args() As String) As Integer
37     ///         Dim diskClass As New ManagementClass("win32_logicaldisk")
38     ///         Dim diskMethods As MethodDataCollection = diskClass.Methods
39     ///         Dim method As MethodData
40     ///         For Each method In diskMethods
41     ///             Console.WriteLine("Method = " &amp; method.Name)
42     ///         Next method
43     ///         Return 0
44     ///     End Function
45     /// End Class
46     ///    </code>
47     /// </example>
48     //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//
49     public class MethodDataCollection : ICollection, IEnumerable
50     {
51         private ManagementObject parent;
52 
53         private class enumLock
54         {
55         } //used to lock usage of BeginMethodEnum/NextMethod
56 
MethodDataCollection(ManagementObject parent)57         internal MethodDataCollection(ManagementObject parent) : base()
58         {
59             this.parent = parent;
60         }
61 
62         //
63         //ICollection
64         //
65 
66         /// <summary>
67         /// <para>Represents the number of objects in the <see cref='System.Management.MethodDataCollection'/>.</para>
68         /// </summary>
69         /// <value>
70         /// <para> The number of objects in the <see cref='System.Management.MethodDataCollection'/>. </para>
71         /// </value>
72         public int Count
73         {
74             get
75             {
76                 int i = 0;
77                 IWbemClassObjectFreeThreaded inParameters = null, outParameters = null;
78                 string methodName;
79                 int status = (int)ManagementStatus.Failed;
80 
81 #pragma warning disable CA2002
82                 lock(typeof(enumLock))
83 #pragma warning restore CA2002
84                 {
85                     try
86                     {
87                         status = parent.wbemObject.BeginMethodEnumeration_(0);
88 
89                         if (status >= 0)
90                         {
91                             methodName = "";    // Condition primer to branch into the while loop.
92                             while (methodName != null && status >= 0 && status != (int)tag_WBEMSTATUS.WBEM_S_NO_MORE_DATA)
93                             {
94                                 methodName = null; inParameters = null; outParameters = null;
95                                 status = parent.wbemObject.NextMethod_(0, out methodName, out inParameters, out outParameters);
96                                 if (status >= 0 && status != (int)tag_WBEMSTATUS.WBEM_S_NO_MORE_DATA)
97                                     i++;
98                             }
99                             parent.wbemObject.EndMethodEnumeration_();  // Ignore status.
100                         }
101                     }
102                     catch (COMException e)
103                     {
104                         ManagementException.ThrowWithExtendedInfo(e);
105                     }
106                 } // lock
107 
108                 if ((status & 0xfffff000) == 0x80041000)
109                 {
110                     ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
111                 }
112                 else if ((status & 0x80000000) != 0)
113                 {
114                     Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
115                 }
116 
117                 return i;
118             }
119         }
120 
121         /// <summary>
122         ///    <para>Indicates whether the object is synchronized.</para>
123         /// </summary>
124         /// <value>
125         /// <para><see langword='true'/> if the object is synchronized;
126         ///    otherwise, <see langword='false'/>.</para>
127         /// </value>
128         public bool IsSynchronized { get { return false; }
129         }
130 
131         /// <summary>
132         ///    <para>Represents the object to be used for synchronization.</para>
133         /// </summary>
134         /// <value>
135         ///    <para>The object to be used for synchronization.</para>
136         /// </value>
137         public object SyncRoot { get { return this; }
138         }
139 
140         /// <overload>
141         /// <para>Copies the <see cref='System.Management.MethodDataCollection'/> into an array.</para>
142         /// </overload>
143         /// <summary>
144         /// <para> Copies the <see cref='System.Management.MethodDataCollection'/> into an array.</para>
145         /// </summary>
146         /// <param name='array'>The array to which to copy the collection. </param>
147         /// <param name='index'>The index from which to start. </param>
CopyTo(Array array, int index)148         public void CopyTo(Array array, int index)
149         {
150             //Use an enumerator to get the MethodData objects and attach them into the target array
151             foreach (MethodData m in this)
152                 array.SetValue(m, index++);
153         }
154 
155         /// <summary>
156         /// <para>Copies the <see cref='System.Management.MethodDataCollection'/> to a specialized <see cref='System.Management.MethodData'/>
157         /// array.</para>
158         /// </summary>
159         /// <param name='methodArray'>The destination array to which to copy the <see cref='System.Management.MethodData'/> objects.</param>
160         /// <param name=' index'>The index in the destination array from which to start the copy.</param>
CopyTo(MethodData[] methodArray, int index)161         public void CopyTo(MethodData[] methodArray, int index)
162         {
163             CopyTo((Array)methodArray, index);
164         }
165 
166         //
167         // IEnumerable
168         //
IEnumerable.GetEnumerator()169         IEnumerator IEnumerable.GetEnumerator()
170         {
171             return (IEnumerator)(new MethodDataEnumerator(parent));
172         }
173 
174         /// <summary>
175         /// <para>Returns an enumerator for the <see cref='System.Management.MethodDataCollection'/>.</para>
176         /// </summary>
177         /// <remarks>
178         ///    <para> Each call to this method
179         ///       returns a new enumerator on the collection. Multiple enumerators can be obtained
180         ///       for the same method collection. However, each enumerator takes a snapshot
181         ///       of the collection, so changes made to the collection after the enumerator was
182         ///       obtained are not reflected.</para>
183         /// </remarks>
184         /// <returns>An <see cref="System.Collections.IEnumerator"/> to enumerate through the collection.</returns>
GetEnumerator()185         public MethodDataEnumerator GetEnumerator()
186         {
187             return new MethodDataEnumerator(parent);
188         }
189 
190         //Enumerator class
191         /// <summary>
192         /// <para>Represents the enumerator for <see cref='System.Management.MethodData'/>
193         /// objects in the <see cref='System.Management.MethodDataCollection'/>.</para>
194         /// </summary>
195         /// <example>
196         ///    <code lang='C#'>using System;
197         /// using System.Management;
198         ///
199         /// // This sample demonstrates how to enumerate all methods in
200         /// // Win32_LogicalDisk class using MethodDataEnumerator object.
201         ///
202         /// class Sample_MethodDataEnumerator
203         /// {
204         ///  public static int Main(string[] args)
205         ///  {
206         ///   ManagementClass diskClass = new ManagementClass("win32_logicaldisk");
207         ///   MethodDataCollection.MethodDataEnumerator diskEnumerator =
208         ///    diskClass.Methods.GetEnumerator();
209         ///   while(diskEnumerator.MoveNext())
210         ///   {
211         ///    MethodData method = diskEnumerator.Current;
212         ///    Console.WriteLine("Method = " + method.Name);
213         ///   }
214         ///   return 0;
215         ///  }
216         /// }
217         ///    </code>
218         ///    <code lang='VB'>Imports System
219         /// Imports System.Management
220         ///
221         /// ' This sample demonstrates how to enumerate all methods in
222         /// ' Win32_LogicalDisk class using MethodDataEnumerator object.
223         ///
224         /// Class Sample_MethodDataEnumerator
225         ///  Overloads Public Shared Function Main(args() As String) As Integer
226         ///   Dim diskClass As New ManagementClass("win32_logicaldisk")
227         ///   Dim diskEnumerator As _
228         ///        MethodDataCollection.MethodDataEnumerator = _
229         ///       diskClass.Methods.GetEnumerator()
230         ///   While diskEnumerator.MoveNext()
231         ///    Dim method As MethodData = diskEnumerator.Current
232         ///    Console.WriteLine("Method = " &amp; method.Name)
233         ///   End While
234         ///   Return 0
235         ///  End Function
236         /// End Class
237         ///    </code>
238         /// </example>
239         public class MethodDataEnumerator : IEnumerator
240         {
241             private ManagementObject parent;
242             private ArrayList methodNames; //can't use simple array because we don't know the size...
243             private IEnumerator en;
244 
245             //Internal constructor
246             //Because WMI doesn't provide a "GetMethodNames" for methods similar to "GetNames" for properties,
247             //We have to walk the methods list and cache the names here.
248             //We lock to ensure that another thread doesn't interfere in the Begin/Next sequence.
MethodDataEnumerator(ManagementObject parent)249             internal MethodDataEnumerator(ManagementObject parent)
250             {
251                 this.parent = parent;
252                 methodNames = new ArrayList();
253                 IWbemClassObjectFreeThreaded inP = null, outP = null;
254                 string tempMethodName;
255                 int status = (int)ManagementStatus.Failed;
256 
257 #pragma warning disable CA2002
258                 lock(typeof(enumLock))
259 #pragma warning restore CA2002
260                 {
261                     try
262                     {
263                         status = parent.wbemObject.BeginMethodEnumeration_(0);
264 
265                         if (status >= 0)
266                         {
267                             tempMethodName = "";    // Condition primer to branch into the while loop.
268                             while (tempMethodName != null && status >= 0 && status != (int)tag_WBEMSTATUS.WBEM_S_NO_MORE_DATA)
269                             {
270                                 tempMethodName = null;
271                                 status = parent.wbemObject.NextMethod_(0, out tempMethodName, out inP, out outP);
272                                 if (status >= 0 && status != (int)tag_WBEMSTATUS.WBEM_S_NO_MORE_DATA)
273                                     methodNames.Add(tempMethodName);
274                             }
275                             parent.wbemObject.EndMethodEnumeration_();  // Ignore status.
276                         }
277                     }
278                     catch (COMException e)
279                     {
280                         ManagementException.ThrowWithExtendedInfo(e);
281                     }
282                     en = methodNames.GetEnumerator();
283                 }
284 
285                 if ((status & 0xfffff000) == 0x80041000)
286                 {
287                     ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
288                 }
289                 else if ((status & 0x80000000) != 0)
290                 {
291                     Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
292                 }
293             }
294 
295             /// <internalonly/>
296             object IEnumerator.Current { get { return (object)this.Current; } }
297 
298             /// <summary>
299             /// <para>Returns the current <see cref='System.Management.MethodData'/> in the <see cref='System.Management.MethodDataCollection'/>
300             /// enumeration.</para>
301             /// </summary>
302             /// <value>The current <see cref='System.Management.MethodData'/> item in the collection.</value>
303             public MethodData Current
304             {
305                 get
306                 {
307                         return new MethodData(parent, (string)en.Current);
308                 }
309             }
310 
311             /// <summary>
312             /// <para>Moves to the next element in the <see cref='System.Management.MethodDataCollection'/> enumeration.</para>
313             /// </summary>
314             /// <returns><see langword='true'/> if the enumerator was successfully advanced to the next method; <see langword='false'/> if the enumerator has passed the end of the collection.</returns>
MoveNext()315             public bool MoveNext ()
316             {
317                 return en.MoveNext();
318             }
319 
320             /// <summary>
321             /// <para>Resets the enumerator to the beginning of the <see cref='System.Management.MethodDataCollection'/> enumeration.</para>
322             /// </summary>
Reset()323             public void Reset()
324             {
325                 en.Reset();
326             }
327 
328         }//MethodDataEnumerator
329 
330 
331         //
332         //Methods
333         //
334 
335         /// <summary>
336         /// <para>Returns the specified <see cref='System.Management.MethodData'/> from the <see cref='System.Management.MethodDataCollection'/>.</para>
337         /// </summary>
338         /// <param name='methodName'>The name of the method requested.</param>
339         /// <value>A <see cref='System.Management.MethodData'/> instance containing all information about the specified method.</value>
340         public virtual MethodData this[string methodName]
341         {
342             get
343             {
344                 if (null == methodName)
345                     throw new ArgumentNullException ("methodName");
346 
347                 return new MethodData(parent, methodName);
348             }
349         }
350 
351 
352         /// <summary>
353         /// <para>Removes a <see cref='System.Management.MethodData'/> from the <see cref='System.Management.MethodDataCollection'/>.</para>
354         /// </summary>
355         /// <param name='methodName'>The name of the method to remove from the collection.</param>
356         /// <remarks>
357         ///    <para>
358         ///       Removing <see cref='System.Management.MethodData'/> objects from the <see cref='System.Management.MethodDataCollection'/>
359         ///       can only be done when the class has no
360         ///       instances. Any other case will result in an exception.</para>
361         /// </remarks>
Remove(string methodName)362         public virtual void Remove(string methodName)
363         {
364             if (parent.GetType() == typeof(ManagementObject)) //can't remove methods from instance
365                 throw new InvalidOperationException();
366 
367             int status = (int)ManagementStatus.Failed;
368 
369             try
370             {
371                 status = parent.wbemObject.DeleteMethod_(methodName);
372             }
373             catch (COMException e)
374             {
375                 ManagementException.ThrowWithExtendedInfo(e);
376             }
377 
378             if ((status & 0xfffff000) == 0x80041000)
379             {
380                 ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
381             }
382             else if ((status & 0x80000000) != 0)
383             {
384                 Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
385             }
386         }
387 
388         //This variant takes only a method name and assumes a void method with no in/out parameters
389         /// <overload>
390         /// <para>Adds a <see cref='System.Management.MethodData'/> to the <see cref='System.Management.MethodDataCollection'/>.</para>
391         /// </overload>
392         /// <summary>
393         /// <para>Adds a <see cref='System.Management.MethodData'/> to the <see cref='System.Management.MethodDataCollection'/>. This overload will
394         ///    add a new method with no parameters to the collection.</para>
395         /// </summary>
396         /// <param name='methodName'>The name of the method to add.</param>
397         /// <remarks>
398         /// <para> Adding <see cref='System.Management.MethodData'/> objects to the <see cref='System.Management.MethodDataCollection'/> can only
399         ///    be done when the class has no instances. Any other case will result in an
400         ///    exception.</para>
401         /// </remarks>
Add(string methodName)402         public virtual void Add(string methodName)
403         {
404             Add(methodName, null, null);
405         }
406 
407 
408 
409         //This variant takes the full information, i.e. the method name and in & out param objects
410         /// <summary>
411         /// <para>Adds a <see cref='System.Management.MethodData'/> to the <see cref='System.Management.MethodDataCollection'/>. This overload will add a new method with the
412         ///    specified parameter objects to the collection.</para>
413         /// </summary>
414         /// <param name='methodName'>The name of the method to add.</param>
415         /// <param name=' inParameters'>The <see cref='System.Management.ManagementBaseObject'/> holding the input parameters to the method.</param>
416         /// <param name=' outParameters'>The <see cref='System.Management.ManagementBaseObject'/> holding the output parameters to the method.</param>
417         /// <remarks>
418         /// <para> Adding <see cref='System.Management.MethodData'/> objects to the <see cref='System.Management.MethodDataCollection'/> can only be
419         ///    done when the class has no instances. Any other case will result in an
420         ///    exception.</para>
421         /// </remarks>
Add(string methodName, ManagementBaseObject inParameters, ManagementBaseObject outParameters)422         public virtual void Add(string methodName, ManagementBaseObject inParameters, ManagementBaseObject outParameters)
423         {
424             IWbemClassObjectFreeThreaded wbemIn = null, wbemOut = null;
425 
426             if (parent.GetType() == typeof(ManagementObject)) //can't add methods to instance
427                 throw new InvalidOperationException();
428 
429             if (inParameters != null)
430                 wbemIn = inParameters.wbemObject;
431             if (outParameters != null)
432                 wbemOut = outParameters.wbemObject;
433 
434             int status = (int)ManagementStatus.Failed;
435 
436             try
437             {
438                 status = parent.wbemObject.PutMethod_(methodName, 0, wbemIn, wbemOut);
439             }
440             catch (COMException e)
441             {
442                 ManagementException.ThrowWithExtendedInfo(e);
443             }
444 
445             if ((status & 0xfffff000) == 0x80041000)
446             {
447                 ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
448             }
449             else if ((status & 0x80000000) != 0)
450             {
451                 Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
452             }
453         }
454 
455     }//MethodDataCollection
456 }
457