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() & " 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