aa8e4a77b3cc57c160447e55d8b041901d9e6a96
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Administration / WbemProvider.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.ServiceModel.Administration
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Diagnostics;
10     using System.Globalization;
11     using System.Runtime;
12     using System.Runtime.Diagnostics;
13     using System.Runtime.InteropServices;
14     using System.Security;
15     using System.ServiceModel;
16     using System.ServiceModel.Diagnostics;
17     using System.Text.RegularExpressions;
18     using System.Threading;
19
20     class WbemProvider : WbemNative.IWbemProviderInit, WbemNative.IWbemServices
21     {
22         object syncRoot = new object();
23         WbemNative.IWbemDecoupledRegistrar wbemRegistrar = null;
24         WbemNative.IWbemServices wbemServices = null;
25         Dictionary<string, IWmiProvider> wmiProviders = new Dictionary<string, IWmiProvider>(StringComparer.OrdinalIgnoreCase);
26         string nameSpace;
27         string appName;
28         bool initialized = false;
29
30         internal WbemProvider(string nameSpace, string appName)
31         {
32             this.nameSpace = nameSpace;
33             this.appName = appName;
34         }
35
36         internal void Initialize()
37         {
38             try
39             {
40                 AppDomain.CurrentDomain.DomainUnload += new EventHandler(ExitOrUnloadEventHandler);
41                 AppDomain.CurrentDomain.ProcessExit += new EventHandler(ExitOrUnloadEventHandler);
42                 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ExitOrUnloadEventHandler);
43                 MTAExecute(new WaitCallback(RegisterWbemProvider), null);
44                 this.initialized = true;
45             }
46             catch (SecurityException)
47             {
48                 // WMI is not supported in PT, rethrow a meaningful exception (will fail the service activation)
49                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
50                     new InvalidOperationException(SR.GetString(SR.PartialTrustWMINotEnabled)));
51             }
52         }
53
54         void RegisterWbemProvider(object state)
55         {
56             this.wbemRegistrar = (WbemNative.IWbemDecoupledRegistrar)new WbemNative.WbemDecoupledRegistrar();
57             int hr = this.wbemRegistrar.Register(0, null, null, null,
58                 this.nameSpace, this.appName, this);
59             if ((int)WbemNative.WbemStatus.WBEM_S_NO_ERROR != hr)
60             {
61                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
62                     (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
63                     (uint)System.Runtime.Diagnostics.EventLogEventId.WmiRegistrationFailed,
64                     TraceUtility.CreateSourceString(this),
65                     hr.ToString("x", CultureInfo.InvariantCulture));
66
67                 this.wbemRegistrar = null;
68             }
69         }
70
71         void UnRegisterWbemProvider(object state)
72         {
73             if (this.wbemRegistrar != null)
74             {
75                 int hr = this.wbemRegistrar.UnRegister();
76                 if ((int)WbemNative.WbemStatus.WBEM_S_NO_ERROR != hr)
77                 {
78                     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
79                         (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
80                         (uint)System.Runtime.Diagnostics.EventLogEventId.WmiUnregistrationFailed,
81                         TraceUtility.CreateSourceString(this),
82                         hr.ToString("x", CultureInfo.InvariantCulture));
83                 }
84                 this.wbemRegistrar = null;
85             }
86         }
87
88         void ExitOrUnloadEventHandler(object sender, EventArgs e)
89         {
90             if (this.wbemRegistrar != null)
91             {
92                 MTAExecute(new WaitCallback(UnRegisterWbemProvider), null);
93             }
94         }
95
96         public void Register(string className, IWmiProvider wmiProvider)
97         {
98             lock (this.syncRoot)
99             {
100                 if (!this.initialized)
101                 {
102                     Initialize();
103                 }
104
105                 this.wmiProviders.Add(className, wmiProvider);
106             }
107         }
108
109         IWmiProvider GetProvider(string className)
110         {
111             IWmiProvider wmiProvider;
112             lock (this.wmiProviders)
113             {
114                 if (!this.wmiProviders.TryGetValue(className, out wmiProvider))
115                 {
116                     wmiProvider = NoInstanceWMIProvider.Default;
117                 }
118             }
119             return wmiProvider;
120         }
121
122         int WbemNative.IWbemProviderInit.Initialize(
123             string wszUser,
124             Int32 lFlags,
125             string wszNamespace,
126             string wszLocale,
127             WbemNative.IWbemServices wbemServices,
128             WbemNative.IWbemContext wbemContext,
129             WbemNative.IWbemProviderInitSink wbemSink
130             )
131         {
132             if (wbemServices == null || wbemContext == null || wbemSink == null)
133                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
134
135             try
136             {
137                 MTAExecute(new WaitCallback(this.RelocateWbemServicesRCWToMTA), wbemServices);
138                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_EXTRA_RETURN_CODES.WBEM_S_INITIALIZED, 0);
139             }
140             catch (WbemException e)
141             {
142                 wbemSink.SetStatus(e.ErrorCode, 0);
143                 return e.ErrorCode;
144             }
145 #pragma warning suppress 56500 // covered by FxCOP
146             catch (Exception)
147             {
148                 wbemSink.SetStatus((int)WbemNative.WbemStatus.WBEM_E_FAILED, 0);
149                 return (int)WbemNative.WbemStatus.WBEM_E_FAILED;
150             }
151             finally
152             {
153                 // WMI relies on destructor of this interface to perform certain task
154                 // explicitly release this so that the GC won't hold on to the ref of 
155                 // this after the function
156                 Marshal.ReleaseComObject(wbemSink);
157             }
158
159             return (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
160         }
161
162         void RelocateWbemServicesRCWToMTA(object comObject)
163         {
164             IntPtr pUnk = Marshal.GetIUnknownForObject(comObject);
165             Marshal.ReleaseComObject(comObject);
166             this.wbemServices = (WbemNative.IWbemServices)Marshal.GetObjectForIUnknown(pUnk);
167             Marshal.Release(pUnk);
168         }
169
170         int WbemNative.IWbemServices.OpenNamespace(
171             string nameSpace,
172             Int32 flags,
173             WbemNative.IWbemContext wbemContext,
174             ref WbemNative.IWbemServices wbemServices,
175             IntPtr wbemCallResult
176             )
177         {
178             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
179         }
180
181         int WbemNative.IWbemServices.CancelAsyncCall(
182             WbemNative.IWbemObjectSink wbemSink
183             )
184         {
185             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
186         }
187
188         int WbemNative.IWbemServices.QueryObjectSink(
189             Int32 flags,
190             out WbemNative.IWbemObjectSink wbemSink
191             )
192         {
193             wbemSink = null;
194             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
195         }
196
197         int WbemNative.IWbemServices.GetObject(
198             string objectPath,
199             Int32 flags,
200             WbemNative.IWbemContext wbemContext,
201             ref WbemNative.IWbemClassObject wbemObject,
202             IntPtr wbemResult
203             )
204         {
205             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
206         }
207
208         int WbemNative.IWbemServices.GetObjectAsync(
209             string objectPath,
210             Int32 flags,
211             WbemNative.IWbemContext wbemContext,
212             WbemNative.IWbemObjectSink wbemSink)
213         {
214             if (wbemContext == null || wbemSink == null || this.wbemServices == null)
215                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
216
217             using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ?
218                 ServiceModelActivity.CreateActivity(true, SR.GetString(SR.WmiGetObject, string.IsNullOrEmpty(objectPath) ? string.Empty : objectPath), ActivityType.WmiGetObject) : null)
219             {
220                 try
221                 {
222                     ObjectPathRegex objPathRegex = new ObjectPathRegex(objectPath);
223                     ParameterContext parms = new ParameterContext(objPathRegex.ClassName, this.wbemServices, wbemContext, wbemSink);
224                     WbemInstance wbemInstance = new WbemInstance(parms, objPathRegex);
225                     IWmiProvider wmiProvider = this.GetProvider(parms.ClassName);
226                     if (wmiProvider.GetInstance(new InstanceContext(wbemInstance)))
227                     {
228                         wbemInstance.Indicate();
229                     }
230
231                     WbemException.ThrowIfFail(wbemSink.SetStatus(
232                         (int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
233                         (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR,
234                         null,
235                         null));
236                 }
237                 catch (WbemException e)
238                 {
239                     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error, (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi, (uint)System.Runtime.Diagnostics.EventLogEventId.WmiGetObjectFailed,
240                         TraceUtility.CreateSourceString(this), e.ToString());
241                     wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
242                         e.ErrorCode, null, null);
243                     return e.ErrorCode;
244                 }
245 #pragma warning suppress 56500 // covered by FxCOP
246                 catch (Exception e)
247                 {
248                     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error, (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi, (uint)System.Runtime.Diagnostics.EventLogEventId.WmiGetObjectFailed,
249                         TraceUtility.CreateSourceString(this), e.ToString());
250                     wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
251                         (int)WbemNative.WbemStatus.WBEM_E_FAILED, null, null);
252                     return (int)WbemNative.WbemStatus.WBEM_E_FAILED;
253                 }
254                 finally
255                 {
256                     Marshal.ReleaseComObject(wbemSink);
257                 }
258             }
259             return (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
260         }
261
262         int WbemNative.IWbemServices.PutClass(
263             WbemNative.IWbemClassObject wbemObject,
264             Int32 flags,
265             WbemNative.IWbemContext wbemContext,
266             IntPtr wbemCallResult)
267         {
268             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
269         }
270
271         int WbemNative.IWbemServices.PutClassAsync(
272             WbemNative.IWbemClassObject wbemObject,
273             Int32 flags,
274             WbemNative.IWbemContext wbemContext,
275             WbemNative.IWbemObjectSink wbemSink)
276         {
277             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
278         }
279
280         int WbemNative.IWbemServices.DeleteClass(
281             string className,
282             Int32 flags,
283             WbemNative.IWbemContext wbemContext,
284             IntPtr wbemCallResult)
285         {
286             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
287         }
288
289         int WbemNative.IWbemServices.DeleteClassAsync(
290             string className,
291             Int32 lFlags,
292             WbemNative.IWbemContext wbemContext,
293             WbemNative.IWbemObjectSink wbemSink)
294         {
295             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
296         }
297
298         int WbemNative.IWbemServices.CreateClassEnum(
299             string superClassName,
300             Int32 flags,
301             WbemNative.IWbemContext wbemContext,
302             out WbemNative.IEnumWbemClassObject wbemEnum)
303         {
304             wbemEnum = null;
305             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
306         }
307
308         int WbemNative.IWbemServices.CreateClassEnumAsync(
309             string superClassName,
310             Int32 flags,
311             WbemNative.IWbemContext wbemContext,
312             WbemNative.IWbemObjectSink wbemSink)
313         {
314             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
315         }
316
317         int WbemNative.IWbemServices.PutInstance(
318             WbemNative.IWbemClassObject pInst,
319             Int32 lFlags,
320             WbemNative.IWbemContext wbemContext,
321             IntPtr wbemCallResult)
322         {
323             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
324         }
325
326         int WbemNative.IWbemServices.PutInstanceAsync(
327             WbemNative.IWbemClassObject wbemObject,
328             Int32 lFlags,
329             WbemNative.IWbemContext wbemContext,
330             WbemNative.IWbemObjectSink wbemSink
331             )
332         {
333             if (wbemObject == null || wbemContext == null || wbemSink == null || this.wbemServices == null)
334                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
335
336             using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
337             {
338                 try
339                 {
340                     object val = null;
341                     int type = 0;
342                     int favor = 0;
343                     WbemException.ThrowIfFail(wbemObject.Get("__CLASS", 0, ref val, ref type, ref favor));
344                     string className = (string)val;
345                     ServiceModelActivity.Start(activity, SR.GetString(SR.WmiPutInstance, string.IsNullOrEmpty(className) ? string.Empty : className), ActivityType.WmiPutInstance);
346
347                     ParameterContext parms = new ParameterContext(className, this.wbemServices, wbemContext, wbemSink);
348                     WbemInstance wbemInstance = new WbemInstance(parms, wbemObject);
349                     IWmiProvider wmiProvider = this.GetProvider(parms.ClassName);
350                     if (wmiProvider.PutInstance(new InstanceContext(wbemInstance)))
351                     {
352                         wbemInstance.Indicate();
353                     }
354
355                     WbemException.ThrowIfFail(wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
356                         (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR, null, null));
357                 }
358                 catch (WbemException e)
359                 {
360                     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error, (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi, (uint)System.Runtime.Diagnostics.EventLogEventId.WmiPutInstanceFailed,
361                         TraceUtility.CreateSourceString(this), e.ToString());
362                     wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
363                         e.ErrorCode, null, null);
364                     return e.ErrorCode;
365                 }
366 #pragma warning suppress 56500 // covered by FxCOP
367                 catch (Exception e)
368                 {
369                     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error, (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi, (uint)System.Runtime.Diagnostics.EventLogEventId.WmiPutInstanceFailed,
370                         TraceUtility.CreateSourceString(this), e.ToString());
371                     wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
372                         (int)WbemNative.WbemStatus.WBEM_E_FAILED, null, null);
373                     return (int)WbemNative.WbemStatus.WBEM_E_FAILED;
374                 }
375                 finally
376                 {
377                     Marshal.ReleaseComObject(wbemSink);
378                 }
379             }
380             return (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
381         }
382
383         int WbemNative.IWbemServices.DeleteInstance(
384             string objectPath,
385             Int32 flags,
386             WbemNative.IWbemContext wbemContext,
387             IntPtr wbemCallResult)
388         {
389             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
390         }
391
392         int WbemNative.IWbemServices.DeleteInstanceAsync(
393             string objectPath,
394             Int32 lFlags,
395             WbemNative.IWbemContext wbemContext,
396             WbemNative.IWbemObjectSink wbemSink)
397         {
398             if (wbemContext == null || wbemSink == null || this.wbemServices == null)
399                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
400
401             try
402             {
403                 ObjectPathRegex objPathRegex = new ObjectPathRegex(objectPath);
404                 ParameterContext parms = new ParameterContext(objPathRegex.ClassName, this.wbemServices, wbemContext, wbemSink);
405                 WbemInstance wbemInstance = new WbemInstance(parms, objPathRegex);
406                 IWmiProvider wmiProvider = this.GetProvider(parms.ClassName);
407                 if (wmiProvider.DeleteInstance(new InstanceContext(wbemInstance)))
408                 {
409                     wbemInstance.Indicate();
410                 }
411
412                 WbemException.ThrowIfFail(wbemSink.SetStatus(
413                     (int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
414                     (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR, null, null));
415             }
416             catch (WbemException e)
417             {
418                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
419                     (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
420                     (uint)System.Runtime.Diagnostics.EventLogEventId.WmiDeleteInstanceFailed,
421                     e.ToString());
422                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
423                     e.ErrorCode, null, null);
424                 return e.ErrorCode;
425             }
426 #pragma warning suppress 56500 // covered by FxCOP
427             catch (Exception e)
428             {
429                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
430                     (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
431                     (uint)System.Runtime.Diagnostics.EventLogEventId.WmiDeleteInstanceFailed,
432                     e.ToString());
433                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
434                     (int)WbemNative.WbemStatus.WBEM_E_FAILED, null, null);
435                 return (int)WbemNative.WbemStatus.WBEM_E_FAILED;
436             }
437             finally
438             {
439                 Marshal.ReleaseComObject(wbemSink);
440             }
441             return (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
442         }
443
444         int WbemNative.IWbemServices.CreateInstanceEnum(
445             string filter,
446             Int32 flags,
447             WbemNative.IWbemContext wbemContext,
448             out WbemNative.IEnumWbemClassObject wbemEnum
449             )
450         {
451             wbemEnum = null;
452             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
453         }
454
455         int WbemNative.IWbemServices.CreateInstanceEnumAsync(
456             string className,
457             Int32 flags,
458             WbemNative.IWbemContext wbemContext,
459             WbemNative.IWbemObjectSink wbemSink)
460         {
461             if (wbemContext == null || wbemSink == null || this.wbemServices == null)
462                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
463
464             try
465             {
466                 ParameterContext parms = new ParameterContext(className, this.wbemServices, wbemContext, wbemSink);
467                 IWmiProvider wmiProvider = this.GetProvider(parms.ClassName);
468                 wmiProvider.EnumInstances(new InstancesContext(parms));
469
470                 WbemException.ThrowIfFail(wbemSink.SetStatus(
471                     (int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
472                     (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR,
473                     null,
474                     null));
475             }
476             catch (WbemException e)
477             {
478                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
479                     e.ErrorCode, null, null);
480                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
481                     (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
482                     (uint)System.Runtime.Diagnostics.EventLogEventId.WmiCreateInstanceFailed,
483                     className,
484                     e.ToString());
485                 return e.ErrorCode;
486             }
487 #pragma warning suppress 56500 // covered by FxCOP
488             catch (Exception e)
489             {
490                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
491                     (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
492                     (uint)System.Runtime.Diagnostics.EventLogEventId.WmiCreateInstanceFailed,
493                     className,
494                     e.ToString());
495                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
496                     (int)WbemNative.WbemStatus.WBEM_E_FAILED, null, null);
497                 return (int)WbemNative.WbemStatus.WBEM_E_FAILED;
498             }
499             finally
500             {
501                 Marshal.ReleaseComObject(wbemSink);
502             }
503             return (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
504         }
505
506         int WbemNative.IWbemServices.ExecQuery(
507             string queryLanguage,
508             string query,
509             Int32 flags,
510             WbemNative.IWbemContext wbemContext,
511             out WbemNative.IEnumWbemClassObject wbemEnum)
512         {
513             wbemEnum = null;
514             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
515         }
516
517         int WbemNative.IWbemServices.ExecQueryAsync(
518             string queryLanguage,
519             string query,
520             Int32 flags,
521             WbemNative.IWbemContext wbemContext,
522             WbemNative.IWbemObjectSink wbemSink)
523         {
524             if (wbemContext == null || wbemSink == null || this.wbemServices == null)
525                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
526
527             try
528             {
529                 QueryRegex queryRegex = new QueryRegex(query);
530                 ParameterContext parms = new ParameterContext(queryRegex.ClassName, this.wbemServices, wbemContext, wbemSink);
531                 IWmiProvider wmiProvider = this.GetProvider(parms.ClassName);
532                 //we let WMI to parse WQL to filter results from appropriate provider
533                 wmiProvider.EnumInstances(new InstancesContext(parms));
534
535                 WbemException.ThrowIfFail(wbemSink.SetStatus(
536                     (int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
537                     (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR, null, null));
538             }
539             catch (WbemException e)
540             {
541                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
542                    (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
543                    (uint)System.Runtime.Diagnostics.EventLogEventId.WmiExecQueryFailed,
544                    e.ToString());
545                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
546                     e.ErrorCode, null, null);
547                 return e.ErrorCode;
548             }
549 #pragma warning suppress 56500 // covered by FxCOP
550             catch (Exception e)
551             {
552                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
553                    (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
554                    (uint)System.Runtime.Diagnostics.EventLogEventId.WmiExecQueryFailed,
555                    e.ToString());
556                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
557                     (int)WbemNative.WbemStatus.WBEM_E_FAILED, null, null);
558                 return (int)WbemNative.WbemStatus.WBEM_E_FAILED;
559             }
560             finally
561             {
562                 Marshal.ReleaseComObject(wbemSink);
563             }
564             return (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
565         }
566
567         int WbemNative.IWbemServices.ExecNotificationQuery(
568             string queryLanguage,
569             string query,
570             Int32 flags,
571             WbemNative.IWbemContext wbemContext,
572             out WbemNative.IEnumWbemClassObject wbemEnum)
573         {
574             wbemEnum = null;
575             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
576         }
577
578         int WbemNative.IWbemServices.ExecNotificationQueryAsync(
579             string queryLanguage,
580             string query,
581             Int32 flags,
582             WbemNative.IWbemContext wbemContext,
583             WbemNative.IWbemObjectSink wbemSink)
584         {
585             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
586         }
587         int WbemNative.IWbemServices.ExecMethod(
588             string objectPath,
589             string methodName,
590             Int32 flags,
591             WbemNative.IWbemContext wbemContext,
592             WbemNative.IWbemClassObject wbemInParams,
593             ref WbemNative.IWbemClassObject wbemOutParams,
594             IntPtr wbemCallResult)
595         {
596             return (int)WbemNative.WbemStatus.WBEM_E_NOT_SUPPORTED;
597         }
598
599         int WbemNative.IWbemServices.ExecMethodAsync(
600             string objectPath,
601             string methodName,
602             Int32 flags,
603             WbemNative.IWbemContext wbemContext,
604             WbemNative.IWbemClassObject wbemInParams,
605             WbemNative.IWbemObjectSink wbemSink)
606         {
607             if (wbemContext == null || wbemInParams == null || wbemSink == null || this.wbemServices == null)
608                 return (int)WbemNative.WbemStatus.WBEM_E_INVALID_PARAMETER;
609
610             int result = (int)WbemNative.WbemStatus.WBEM_S_NO_ERROR;
611
612             try
613             {
614                 ObjectPathRegex objPathRegex = new ObjectPathRegex(objectPath);
615                 ParameterContext parms = new ParameterContext(objPathRegex.ClassName, this.wbemServices, wbemContext, wbemSink);
616                 WbemInstance wbemInstance = new WbemInstance(parms, objPathRegex);
617
618                 MethodContext methodContext = new MethodContext(parms, methodName, wbemInParams, wbemInstance);
619                 IWmiProvider wmiProvider = this.GetProvider(parms.ClassName);
620                 if (!wmiProvider.InvokeMethod(methodContext))
621                 {
622                     result = (int)WbemNative.WbemStatus.WBEM_E_NOT_FOUND;
623                 }
624
625                 WbemException.ThrowIfFail(wbemSink.SetStatus(
626                     (int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
627                     (int)result,
628                     null,
629                     null));
630             }
631             catch (WbemException e)
632             {
633                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
634                    (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
635                    (uint)System.Runtime.Diagnostics.EventLogEventId.WmiExecMethodFailed,
636                    e.ToString());
637                 result = e.ErrorCode;
638                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
639                     result, null, null);
640             }
641 #pragma warning suppress 56500 // covered by FxCOP
642             catch (Exception e)
643             {
644                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
645                    (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
646                    (uint)System.Runtime.Diagnostics.EventLogEventId.WmiExecMethodFailed,
647                    e.ToString());
648                 result = (int)WbemNative.WbemStatus.WBEM_E_FAILED;
649                 wbemSink.SetStatus((int)WbemNative.tag_WBEM_STATUS_TYPE.WBEM_STATUS_COMPLETE,
650                     (int)result, null, null);
651             }
652             finally
653             {
654                 Marshal.ReleaseComObject(wbemSink);
655             }
656             return result;
657         }
658
659         class InstancesContext : IWmiInstances
660         {
661             ParameterContext parms;
662
663             internal InstancesContext(ParameterContext parms)
664             {
665                 this.parms = parms;
666             }
667
668             IWmiInstance IWmiInstances.NewInstance(string className)
669             {
670                 return new InstanceContext(new WbemInstance(this.parms, className));
671             }
672
673             void IWmiInstances.AddInstance(IWmiInstance inst)
674             {
675                 WbemException.ThrowIfFail(this.parms.WbemSink.Indicate(1,
676                     new WbemNative.IWbemClassObject[] { ((InstanceContext)inst).WbemObject }));
677             }
678         }
679
680         class InstanceContext : IWmiInstance
681         {
682             WbemInstance wbemInstance;
683
684             internal InstanceContext(WbemInstance wbemInstance)
685             {
686                 this.wbemInstance = wbemInstance;
687             }
688
689             internal WbemNative.IWbemClassObject WbemObject
690             {
691                 get { return this.wbemInstance.WbemObject; }
692             }
693
694             IWmiInstance IWmiInstance.NewInstance(string className)
695             {
696                 return new InstanceContext(new WbemInstance(this.wbemInstance, className));
697             }
698
699             object IWmiInstance.GetProperty(string name)
700             {
701                 return wbemInstance.GetProperty(name);
702             }
703
704             void IWmiInstance.SetProperty(string name, object val)
705             {
706                 this.wbemInstance.SetProperty(name, val);
707             }
708         }
709
710         class MethodContext : IWmiMethodContext
711         {
712             ParameterContext parms;
713             string methodName;
714             WbemNative.IWbemClassObject wbemInParms;
715             WbemNative.IWbemClassObject wbemOutParms;
716             IWmiInstance instance;
717
718             internal MethodContext(ParameterContext parms, string methodName, WbemNative.IWbemClassObject wbemInParms, WbemInstance wbemInstance)
719             {
720                 this.parms = parms;
721                 this.methodName = methodName;
722                 this.wbemInParms = wbemInParms;
723                 this.instance = new InstanceContext(wbemInstance);
724
725                 WbemNative.IWbemClassObject wbemObject = null;
726                 WbemException.ThrowIfFail(parms.WbemServices.GetObject(parms.ClassName, 0, parms.WbemContext,
727                     ref wbemObject, IntPtr.Zero));
728
729                 WbemNative.IWbemClassObject wbemMethod = null;
730                 WbemException.ThrowIfFail(wbemObject.GetMethod(methodName, 0, IntPtr.Zero, out wbemMethod));
731                 WbemException.ThrowIfFail(wbemMethod.SpawnInstance(0, out this.wbemOutParms));
732             }
733
734             string IWmiMethodContext.MethodName
735             {
736                 get { return this.methodName; }
737             }
738
739             IWmiInstance IWmiMethodContext.Instance
740             {
741                 get { return this.instance; }
742             }
743
744             object IWmiMethodContext.ReturnParameter
745             {
746                 set
747                 {
748                     object val = value;
749                     WbemException.ThrowIfFail(this.wbemOutParms.Put("ReturnValue",
750                         0, ref val, 0));
751                     WbemException.ThrowIfFail(this.parms.WbemSink.Indicate(1,
752                         new WbemNative.IWbemClassObject[] { this.wbemOutParms }));
753                 }
754             }
755
756             object IWmiMethodContext.GetParameter(string name)
757             {
758                 Fx.Assert(null != this.wbemInParms, "");
759                 object val = null;
760                 int type = 0;
761                 int favor = 0;
762                 WbemException.ThrowIfFail(this.wbemInParms.Get(name, 0, ref val, ref type, ref favor));
763                 return val;
764             }
765
766             void IWmiMethodContext.SetParameter(string name, object value)
767             {
768                 WbemException.ThrowIfFail(this.wbemOutParms.Put(name, 0, ref value, 0));
769             }
770         }
771
772         class ObjectPathRegex
773         {
774             //No support for boolean keys
775             static Regex nsRegEx = new Regex("^(?<namespace>[^\"]*?:)(?<path>.*)");
776             static Regex classRegEx = new Regex("^(?<className>.*?)\\.(?<keys>.*)");
777             static Regex keysRegEx = new Regex("(?<key>.*?)=((?<ival>[\\d]+)|\"(?<sval>.*?)\"),?");
778
779             string className;
780             Dictionary<string, object> keys = new Dictionary<string, object>();
781
782             public ObjectPathRegex(string objectPath)
783             {
784                 //WMI infrastructure will double all backslashes. We need to get back to the originals
785                 objectPath = objectPath.Replace("\\\\", "\\");
786                 Match match = nsRegEx.Match(objectPath);
787                 if (match.Success)
788                 {
789                     objectPath = match.Groups["path"].Value;
790                 }
791                 match = classRegEx.Match(objectPath);
792                 this.className = match.Groups["className"].Value;
793                 string keyValues = match.Groups["keys"].Value;
794                 match = keysRegEx.Match(keyValues);
795                 if (!match.Success)
796                 {
797                     WbemException.Throw(WbemNative.WbemStatus.WBEM_E_INVALID_OBJECT_PATH);
798                 }
799                 while (match.Success)
800                 {
801                     if (!String.IsNullOrEmpty(match.Groups["ival"].Value))
802                     {
803                         this.keys.Add(match.Groups["key"].Value, Int32.Parse(match.Groups["ival"].Value, CultureInfo.CurrentCulture));
804                     }
805                     else
806                     {
807                         this.keys.Add(match.Groups["key"].Value, match.Groups["sval"].Value);
808                     }
809                     match = match.NextMatch();
810                 }
811             }
812
813             internal string ClassName { get { return this.className; } }
814             internal Dictionary<string, object> Keys { get { return this.keys; } }
815         }
816
817         class QueryRegex
818         {
819             static Regex regEx = new Regex("\\bfrom\\b\\s+(?<className>\\w+)", RegexOptions.IgnoreCase);
820             string className;
821
822             internal QueryRegex(string query)
823             {
824                 Match match = regEx.Match(query);
825                 if (!match.Success)
826                 {
827                     WbemException.Throw(WbemNative.WbemStatus.WBEM_E_INVALID_QUERY);
828                 }
829                 this.className = match.Groups["className"].Value;
830             }
831
832             internal string ClassName { get { return this.className; } }
833         }
834
835         class ParameterContext
836         {
837             string className;
838             WbemNative.IWbemServices wbemServices;
839             WbemNative.IWbemContext wbemContext;
840             WbemNative.IWbemObjectSink wbemSink;
841
842             internal ParameterContext(
843                 string className,
844                 WbemNative.IWbemServices wbemServices,
845                 WbemNative.IWbemContext wbemContext,
846                 WbemNative.IWbemObjectSink wbemSink)
847             {
848                 this.className = className;
849                 this.wbemServices = wbemServices;
850                 this.wbemContext = wbemContext;
851                 this.wbemSink = wbemSink;
852             }
853
854             internal string ClassName
855             {
856                 get { return this.className; }
857             }
858             internal WbemNative.IWbemServices WbemServices
859             {
860                 get { return this.wbemServices; }
861             }
862             internal WbemNative.IWbemContext WbemContext
863             {
864                 get { return this.wbemContext; }
865             }
866             internal WbemNative.IWbemObjectSink WbemSink
867             {
868                 get { return this.wbemSink; }
869             }
870         };
871
872         class WbemInstance
873         {
874             string className;
875             ParameterContext parms;
876             WbemNative.IWbemClassObject wbemObject;
877
878             internal WbemInstance(ParameterContext parms, ObjectPathRegex objPathRegex)
879                 : this(parms, objPathRegex.ClassName)
880             {
881                 foreach (KeyValuePair<string, object> kv in objPathRegex.Keys)
882                 {
883                     this.SetProperty(kv.Key, kv.Value);
884                 }
885             }
886
887             internal WbemInstance(WbemInstance wbemInstance, string className)
888                 : this(wbemInstance.parms, className)
889             {
890             }
891
892             internal WbemInstance(ParameterContext parms, string className)
893             {
894                 this.parms = parms;
895                 if (String.IsNullOrEmpty(className))
896                 {
897                     className = parms.ClassName;
898                 }
899                 this.className = className;
900                 WbemNative.IWbemClassObject tempObj = null;
901                 WbemException.ThrowIfFail(
902                     parms.WbemServices.GetObject(className, 0, parms.WbemContext, ref tempObj, IntPtr.Zero)
903                 );
904
905
906                 if (null != tempObj)
907                 {
908                     WbemException.ThrowIfFail(tempObj.SpawnInstance(0, out this.wbemObject));
909                 }
910             }
911
912             internal WbemInstance(ParameterContext parms, WbemNative.IWbemClassObject wbemObject)
913             {
914                 this.parms = parms;
915                 this.wbemObject = wbemObject;
916             }
917
918             internal WbemNative.IWbemClassObject WbemObject
919             {
920                 get
921                 {
922                     Fx.Assert(null != this.wbemObject, "");
923                     return this.wbemObject;
924                 }
925             }
926
927             internal void SetProperty(string name, object val)
928             {
929                 Fx.Assert(null != this.wbemObject, name + " may not be available to WMI");
930                 if (null != val)
931                 {
932                     WbemNative.CIMTYPE type = 0;
933                     if (val is DateTime)
934                     {
935                         val = ((DateTime)val).ToString("yyyyMMddhhmmss.ffffff", CultureInfo.InvariantCulture) + "+000";
936                     }
937                     else if (val is TimeSpan)
938                     {
939                         TimeSpan ts = (TimeSpan)val;
940                         long microSeconds = (ts.Ticks % 1000) / 10;
941                         val = string.Format(CultureInfo.InvariantCulture, "{0:00000000}{1:00}{2:00}{3:00}.{4:000}{5:000}:000",
942                             new object[] { ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds, microSeconds });
943                     }
944                     else if (val is InstanceContext)
945                     {
946                         InstanceContext inst = (InstanceContext)val;
947                         val = inst.WbemObject;
948                     }
949                     else if (val is Array)
950                     {
951                         Array objs = (Array)val;
952                         if (objs.GetLength(0) > 0 && objs.GetValue(0) is InstanceContext)
953                         {
954                             WbemNative.IWbemClassObject[] insts = new WbemNative.IWbemClassObject[objs.GetLength(0)];
955                             for (int i = 0; i < insts.Length; ++i)
956                             {
957                                 insts[i] = ((InstanceContext)objs.GetValue(i)).WbemObject;
958                             }
959                             val = insts;
960                         }
961                     }
962                     else if (val is Int64)
963                     {
964                         val = ((Int64)val).ToString(CultureInfo.InvariantCulture);
965                         type = WbemNative.CIMTYPE.CIM_SINT64;
966                     }
967
968                     int hResult = this.wbemObject.Put(name, 0, ref val, (int)type);
969                     if ((int)WbemNative.WbemStatus.WBEM_E_TYPE_MISMATCH == hResult || (int)WbemNative.WbemStatus.WBEM_E_NOT_FOUND == hResult)
970                     {
971                         //This would be most likely a product 
972                         System.Runtime.Diagnostics.EventLogEventId eventId;
973                         if ((int)WbemNative.WbemStatus.WBEM_E_TYPE_MISMATCH == hResult)
974                         {
975                             eventId = System.Runtime.Diagnostics.EventLogEventId.WmiAdminTypeMismatch;
976                         }
977                         else
978                         {
979                             eventId = System.Runtime.Diagnostics.EventLogEventId.WmiPropertyMissing;
980                         }
981                         DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
982                             (ushort)System.Runtime.Diagnostics.EventLogCategory.Wmi,
983                             (uint)eventId,
984                             this.className,
985                             name,
986                             val.GetType().ToString());
987                     }
988                     else
989                     {
990                         WbemException.ThrowIfFail(hResult);
991                     }
992                 }
993             }
994
995             internal object GetProperty(string name)
996             {
997                 object val = null;
998                 int type = 0;
999                 int favor = 0;
1000                 WbemException.ThrowIfFail(this.wbemObject.Get(name, 0, ref val, ref type, ref favor));
1001                 return val;
1002             }
1003
1004             internal void Indicate()
1005             {
1006                 WbemException.ThrowIfFail(this.parms.WbemSink.Indicate(1,
1007                     new WbemNative.IWbemClassObject[] { this.wbemObject }));
1008             }
1009         }
1010
1011         class ThreadJob : IDisposable
1012         {
1013             WaitCallback callback;
1014             object state;
1015             ManualResetEvent evtDone = new ManualResetEvent(false);
1016             Exception exception = null;
1017
1018             public ThreadJob(WaitCallback callback, object state)
1019             {
1020                 this.callback = callback;
1021                 this.state = state;
1022             }
1023
1024             public void Run()
1025             {
1026                 try
1027                 {
1028                     this.callback(this.state);
1029                 }
1030 #pragma warning suppress 56500 // covered by FxCOP
1031                 catch (Exception e)
1032                 {
1033                     this.exception = e;
1034                 }
1035                 finally
1036                 {
1037                     this.evtDone.Set();
1038                 }
1039             }
1040
1041             public Exception Wait()
1042             {
1043                 this.evtDone.WaitOne();
1044                 return exception;
1045             }
1046
1047             public void Dispose()
1048             {
1049                 if (null != this.evtDone)
1050                 {
1051                     this.evtDone.Close();
1052                     this.evtDone = null;
1053                 }
1054             }
1055         }
1056
1057         internal static void MTAExecute(WaitCallback callback, object state)
1058         {
1059             if (Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
1060             {
1061                 using (ThreadJob job = new ThreadJob(callback, state))
1062                 {
1063                     Thread thread = new Thread(new ThreadStart(job.Run));
1064                     thread.SetApartmentState(ApartmentState.MTA);
1065                     thread.IsBackground = true;
1066                     thread.Start();
1067                     Exception exception = job.Wait();
1068                     if (null != exception)
1069                     {
1070                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ApplicationException(SR.GetString(SR.AdminMTAWorkerThreadException), exception));
1071                     }
1072                 }
1073             }
1074             else
1075             {
1076                 callback(state);
1077             }
1078         }
1079
1080         class NoInstanceWMIProvider : IWmiProvider
1081         {
1082             static NoInstanceWMIProvider singleton;
1083             internal static NoInstanceWMIProvider Default
1084             {
1085                 get
1086                 {
1087                     if (null == singleton)
1088                     {
1089                         singleton = new NoInstanceWMIProvider();
1090                     }
1091                     return singleton;
1092                 }
1093             }
1094
1095             void IWmiProvider.EnumInstances(IWmiInstances instances) { }
1096             bool IWmiProvider.GetInstance(IWmiInstance instance) { return false; }
1097             bool IWmiProvider.PutInstance(IWmiInstance instance) { return false; }
1098             bool IWmiProvider.DeleteInstance(IWmiInstance instance) { return false; }
1099             bool IWmiProvider.InvokeMethod(IWmiMethodContext method) { return false; }
1100         }
1101     }
1102
1103     internal interface IWmiProvider
1104     {
1105         //methods with return value should return false if instance is not found
1106         void EnumInstances(IWmiInstances instances);
1107         bool GetInstance(IWmiInstance instance);
1108         bool PutInstance(IWmiInstance instance);
1109         bool DeleteInstance(IWmiInstance instance);
1110         bool InvokeMethod(IWmiMethodContext method);
1111     }
1112
1113     internal interface IWmiInstances
1114     {
1115         IWmiInstance NewInstance(string className);
1116         void AddInstance(IWmiInstance inst);
1117     }
1118
1119     internal interface IWmiInstance
1120     {
1121         IWmiInstance NewInstance(string className);
1122         object GetProperty(string name);
1123         void SetProperty(string name, object value);
1124     }
1125
1126     internal interface IWmiMethodContext
1127     {
1128         string MethodName { get; }
1129         IWmiInstance Instance { get; }
1130         object ReturnParameter { set; }
1131         object GetParameter(string name);
1132         void SetParameter(string name, object value);
1133     }
1134
1135     internal interface IWmiInstanceProvider
1136     {
1137         string GetInstanceType();
1138         void FillInstance(IWmiInstance wmiInstance);
1139     }
1140 }