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.Threading;
7 
8 namespace System.Management
9 {
10 
11     /// <summary>
12     /// <para>Represents the method that will handle the <see cref='E:System.Management.ManagementOperationObserver.ObjectReady'/> event.</para>
13     /// </summary>
ObjectReadyEventHandler(object sender, ObjectReadyEventArgs e)14     public delegate void ObjectReadyEventHandler(object sender, ObjectReadyEventArgs e);
15 
16     /// <summary>
17     /// <para>Represents the method that will handle the <see cref='E:System.Management.ManagementOperationObserver.Completed'/> event.</para>
18     /// </summary>
CompletedEventHandler(object sender, CompletedEventArgs e)19     public delegate void CompletedEventHandler (object sender, CompletedEventArgs e);
20 
21     /// <summary>
22     /// <para>Represents the method that will handle the <see cref='E:System.Management.ManagementOperationObserver.Progress'/> event.</para>
23     /// </summary>
ProgressEventHandler(object sender, ProgressEventArgs e)24     public delegate void ProgressEventHandler (object sender, ProgressEventArgs e);
25 
26     /// <summary>
27     /// <para>Represents the method that will handle the <see cref='E:System.Management.ManagementOperationObserver.ObjectPut'/> event.</para>
28     /// </summary>
ObjectPutEventHandler(object sender, ObjectPutEventArgs e)29     public delegate void ObjectPutEventHandler(object sender, ObjectPutEventArgs e);
30 
31     /// <summary>
32     ///    <para>Used to manage asynchronous operations and handle management information and events received asynchronously.</para>
33     /// </summary>
34     /// <example>
35     ///    <code lang='C#'>using System;
36     /// using System.Management;
37     ///
38     /// // This sample demonstrates how to read a ManagementObject asychronously
39     /// // using the ManagementOperationObserver object.
40     ///
41     /// class Sample_ManagementOperationObserver {
42     ///     public static int Main(string[] args) {
43     ///
44     ///         //Set up a handler for the asynchronous callback
45     ///         ManagementOperationObserver observer = new ManagementOperationObserver();
46     ///         MyHandler completionHandler = new MyHandler();
47     ///         observer.Completed += new CompletedEventHandler(completionHandler.Done);
48     ///
49     ///         //Invoke the asynchronous read of the object
50     ///         ManagementObject disk = new ManagementObject("Win32_logicaldisk='C:'");
51     ///         disk.Get(observer);
52     ///
53     ///         //For the purpose of this sample, we keep the main
54     ///         // thread alive until the asynchronous operation is completed.
55     ///
56     ///         while (!completionHandler.IsComplete) {
57     ///             System.Threading.Thread.Sleep(500);
58     ///         }
59     ///
60     ///         Console.WriteLine("Size= " + disk["Size"] + " bytes.");
61     ///
62     ///         return 0;
63     ///     }
64     ///
65     ///     public class MyHandler
66     ///     {
67     ///         private bool isComplete = false;
68     ///
69     ///         public void Done(object sender, CompletedEventArgs e) {
70     ///             isComplete = true;
71     ///         }
72     ///
73     ///         public bool IsComplete {
74     ///             get {
75     ///                 return isComplete;
76     ///             }
77     ///         }
78     ///     }
79     /// }
80     ///    </code>
81     ///    <code lang='VB'>Imports System
82     /// Imports System.Management
83     ///
84     /// ' This sample demonstrates how to read a ManagementObject asychronously
85     /// ' using the ManagementOperationObserver object.
86     ///
87     /// Class Sample_ManagementOperationObserver
88     ///     Overloads Public Shared Function Main(args() As String) As Integer
89     ///
90     ///         'Set up a handler for the asynchronous callback
91     ///         Dim observer As New ManagementOperationObserver()
92     ///         Dim completionHandler As New MyHandler()
93     ///         AddHandler observer.Completed, AddressOf completionHandler.Done
94     ///
95     ///         ' Invoke the object read asynchronously
96     ///         Dim disk As New ManagementObject("Win32_logicaldisk='C:'")
97     ///         disk.Get(observer)
98     ///
99     ///         ' For the purpose of this sample, we keep the main
100     ///         ' thread alive until the asynchronous operation is finished.
101     ///         While Not completionHandler.IsComplete Then
102     ///             System.Threading.Thread.Sleep(500)
103     ///         End While
104     ///
105     ///         Console.WriteLine("Size = " + disk("Size").ToString() &amp; " bytes")
106     ///
107     ///         Return 0
108     ///     End Function
109     ///
110     ///     Public Class MyHandler
111     ///         Private _isComplete As Boolean = False
112     ///
113     ///         Public Sub Done(sender As Object, e As CompletedEventArgs)
114     ///             _isComplete = True
115     ///         End Sub 'Done
116     ///
117     ///         Public ReadOnly Property IsComplete() As Boolean
118     ///             Get
119     ///                 Return _isComplete
120     ///             End Get
121     ///         End Property
122     ///     End Class
123     /// End Class
124     ///    </code>
125     /// </example>
126     public class ManagementOperationObserver
127     {
128         private Hashtable m_sinkCollection;
129         private WmiDelegateInvoker delegateInvoker;
130 
131         /// <summary>
132         ///    <para> Occurs when a new object is available.</para>
133         /// </summary>
134         public event ObjectReadyEventHandler        ObjectReady;
135 
136         /// <summary>
137         ///    <para> Occurs when an operation has completed.</para>
138         /// </summary>
139         public event CompletedEventHandler          Completed;
140 
141         /// <summary>
142         ///    <para> Occurs to indicate the progress of an ongoing operation.</para>
143         /// </summary>
144         public event ProgressEventHandler           Progress;
145 
146         /// <summary>
147         ///    <para> Occurs when an object has been successfully committed.</para>
148         /// </summary>
149         public event ObjectPutEventHandler          ObjectPut;
150 
151         /// <summary>
152         /// <para>Initializes a new instance of the <see cref='System.Management.ManagementOperationObserver'/> class. This is the default constructor.</para>
153         /// </summary>
ManagementOperationObserver()154         public ManagementOperationObserver ()
155         {
156             // We make our sink collection synchronized
157             m_sinkCollection = new Hashtable ();
158             delegateInvoker = new WmiDelegateInvoker (this);
159         }
160 
161         /// <summary>
162         ///    <para> Cancels all outstanding operations.</para>
163         /// </summary>
Cancel()164         public void Cancel ()
165         {
166             // Cancel all the sinks we have - make a copy to avoid things
167             // changing under our feet
168             Hashtable copiedSinkTable =  new Hashtable ();
169 
170             lock (m_sinkCollection)
171             {
172                 IDictionaryEnumerator sinkEnum = m_sinkCollection.GetEnumerator();
173 
174                 try
175                 {
176                     sinkEnum.Reset ();
177 
178                     while (sinkEnum.MoveNext ())
179                     {
180                         DictionaryEntry entry = (DictionaryEntry) sinkEnum.Current;
181                         copiedSinkTable.Add (entry.Key, entry.Value);
182                     }
183                 }
184                 catch
185                 {
186                 }
187             }
188 
189             // Now step through the copy and cancel everything
190             try
191             {
192                 IDictionaryEnumerator copiedSinkEnum = copiedSinkTable.GetEnumerator();
193                 copiedSinkEnum.Reset ();
194 
195                 while (copiedSinkEnum.MoveNext ())
196                 {
197                     DictionaryEntry entry = (DictionaryEntry) copiedSinkEnum.Current;
198                     WmiEventSink eventSink = (WmiEventSink) entry.Value;
199 
200                     try
201                     {
202                         eventSink.Cancel ();
203                     }
204                     catch
205                     {
206                     }
207                 }
208             }
209             catch
210             {
211             }
212         }
213 
GetNewSink( ManagementScope scope, object context)214         internal WmiEventSink GetNewSink (
215             ManagementScope scope,
216             object context)
217         {
218             try
219             {
220                 WmiEventSink eventSink = WmiEventSink.GetWmiEventSink(this, context, scope, null, null);
221 
222                 // Add it to our collection
223                 lock (m_sinkCollection)
224                 {
225                     m_sinkCollection.Add (eventSink.GetHashCode(), eventSink);
226                 }
227 
228                 return eventSink;
229             }
230             catch
231             {
232                 return null;
233             }
234         }
235 
236         internal bool HaveListenersForProgress
237         {
238             get
239             {
240                 bool result = false;
241 
242                 try
243                 {
244                     if (Progress != null)
245                         result = ((Progress.GetInvocationList ()).Length > 0);
246                 }
247                 catch
248                 {
249                 }
250 
251                 return result;
252             }
253         }
GetNewPutSink( ManagementScope scope, object context, string path, string className)254         internal WmiEventSink GetNewPutSink (
255             ManagementScope scope,
256             object context,
257             string path,
258             string className)
259         {
260             try
261             {
262                 WmiEventSink eventSink = WmiEventSink.GetWmiEventSink(this, context, scope, path, className);
263 
264                 // Add it to our collection
265                 lock (m_sinkCollection)
266                 {
267                     m_sinkCollection.Add (eventSink.GetHashCode(), eventSink);
268                 }
269 
270                 return eventSink;
271             }
272             catch
273             {
274                 return null;
275             }
276         }
277 
GetNewGetSink( ManagementScope scope, object context, ManagementObject managementObject)278         internal WmiGetEventSink GetNewGetSink (
279             ManagementScope scope,
280             object context,
281             ManagementObject managementObject)
282         {
283             try
284             {
285                 WmiGetEventSink eventSink = WmiGetEventSink.GetWmiGetEventSink(this,
286                     context, scope, managementObject);
287 
288                 // Add it to our collection
289                 lock (m_sinkCollection)
290                 {
291                     m_sinkCollection.Add (eventSink.GetHashCode(), eventSink);
292                 }
293 
294                 return eventSink;
295             }
296             catch
297             {
298                 return null;
299             }
300         }
301 
RemoveSink(WmiEventSink eventSink)302         internal void RemoveSink (WmiEventSink eventSink)
303         {
304             try
305             {
306                 lock (m_sinkCollection)
307                 {
308                     m_sinkCollection.Remove (eventSink.GetHashCode ());
309                 }
310 
311                 // Release the stub as we are now disconnected
312                 eventSink.ReleaseStub ();
313             }
314             catch
315             {
316             }
317         }
318 
319         /// <summary>
320         /// Fires the ObjectReady event to whomsoever is listening
321         /// </summary>
322         /// <param name="args"> </param>
FireObjectReady(ObjectReadyEventArgs args)323         internal void FireObjectReady (ObjectReadyEventArgs args)
324         {
325             try
326             {
327                 delegateInvoker.FireEventToDelegates (ObjectReady, args);
328             }
329             catch
330             {
331             }
332         }
333 
FireCompleted(CompletedEventArgs args)334         internal void FireCompleted (CompletedEventArgs args)
335         {
336             try
337             {
338                 delegateInvoker.FireEventToDelegates (Completed, args);
339             }
340             catch
341             {
342             }
343         }
344 
FireProgress(ProgressEventArgs args)345         internal void FireProgress (ProgressEventArgs args)
346         {
347             try
348             {
349                 delegateInvoker.FireEventToDelegates (Progress, args);
350             }
351             catch
352             {
353             }
354         }
355 
FireObjectPut(ObjectPutEventArgs args)356         internal void FireObjectPut (ObjectPutEventArgs args)
357         {
358             try
359             {
360                 delegateInvoker.FireEventToDelegates (ObjectPut, args);
361             }
362             catch
363             {
364             }
365         }
366     }
367 
368     internal class WmiEventState
369     {
370         private Delegate d;
371         private ManagementEventArgs args;
372         private AutoResetEvent h;
373 
WmiEventState(Delegate d, ManagementEventArgs args, AutoResetEvent h)374         internal WmiEventState (Delegate d, ManagementEventArgs args, AutoResetEvent h)
375         {
376             this.d = d;
377             this.args = args;
378             this.h = h;
379         }
380 
381         public Delegate Delegate
382         {
383             get { return d; }
384         }
385 
386         public ManagementEventArgs Args
387         {
388             get { return args; }
389         }
390 
391         public AutoResetEvent AutoResetEvent
392         {
393             get { return h; }
394         }
395     }
396 
397     /// <summary>
398     /// This class handles the posting of events to delegates. For each event
399     /// it queues a set of requests (one per target delegate) to the thread pool
400     /// to handle the event. It ensures that no single delegate can throw
401     /// an exception that prevents the event from reaching any other delegates.
402     /// It also ensures that the sender does not signal the processing of the
403     /// WMI event as "done" until all target delegates have signalled that they are
404     /// done.
405     /// </summary>
406     internal class WmiDelegateInvoker
407     {
408         internal object sender;
409 
WmiDelegateInvoker(object sender)410         internal WmiDelegateInvoker (object sender)
411         {
412             this.sender = sender;
413         }
414 
415         /// <summary>
416         /// Custom handler for firing a WMI event to a list of delegates. We use
417         /// the process thread pool to handle the firing.
418         /// </summary>
419         /// <param name="md">The MulticastDelegate representing the collection
420         /// of targets for the event</param>
421         /// <param name="args">The accompanying event arguments</param>
FireEventToDelegates(MulticastDelegate md, ManagementEventArgs args)422         internal void FireEventToDelegates (MulticastDelegate md, ManagementEventArgs args)
423         {
424             try
425             {
426                 if (null != md)
427                 {
428                     foreach (Delegate d in md.GetInvocationList())
429                     {
430                         try
431                         {
432                             d.DynamicInvoke (new object [] {this.sender, args});
433                         }
434                         catch
435                         {
436                         }
437                     }
438                 }
439             }
440             catch
441             {
442             }
443         }
444     }
445 
446 }
447