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.Diagnostics;
6 using System.ComponentModel;
7 using System.Runtime.InteropServices;
8 using System.Globalization;
9 using System.Reflection;
10 using System.ComponentModel.Design.Serialization;
11 
12 namespace System.Management
13 {
14     /// <summary>
15     ///    <para>Provides a wrapper for parsing and building paths to WMI objects.</para>
16     /// </summary>
17     /// <example>
18     ///    <code lang='C#'>using System;
19     /// using System.Management;
20     ///
21     /// // This sample displays all properties in a ManagementPath object.
22     ///
23     /// class Sample_ManagementPath
24     /// {
25     ///     public static int Main(string[] args) {
26     ///         ManagementPath path = new ManagementPath( "\\\\MyServer\\MyNamespace:Win32_logicaldisk='c:'");
27     ///
28     ///         // Results of full path parsing
29     ///         Console.WriteLine("Path: " + path.Path);
30     ///         Console.WriteLine("RelativePath: " + path.RelativePath);
31     ///         Console.WriteLine("Server: " + path.Server);
32     ///         Console.WriteLine("NamespacePath: " + path.NamespacePath);
33     ///         Console.WriteLine("ClassName: " + path.ClassName);
34     ///         Console.WriteLine("IsClass: " + path.IsClass);
35     ///         Console.WriteLine("IsInstance: " + path.IsInstance);
36     ///         Console.WriteLine("IsSingleton: " + path.IsSingleton);
37     ///
38     ///         // Change a portion of the full path
39     ///         path.Server = "AnotherServer";
40     ///         Console.WriteLine("New Path: " + path.Path);
41     ///         return 0;
42     ///    }
43     /// }
44     ///    </code>
45     ///    <code lang='VB'>Imports System
46     /// Imports System.Management
47     ///
48     /// 'This sample displays all properties in a ManagementPath object.
49     /// Class Sample_ManagementPath Overloads
50     ///     Public Shared Function Main(args() As String) As Integer
51     ///         Dim path As _ New
52     ///         ManagementPath("\\MyServer\MyNamespace:Win32_LogicalDisk='c:'")
53     ///
54     ///         ' Results of full path parsing
55     ///         Console.WriteLine("Path: " &amp; path.Path)
56     ///         Console.WriteLine("RelativePath: " &amp; path.RelativePath)
57     ///         Console.WriteLine("Server: " &amp; path.Server)
58     ///         Console.WriteLine("NamespacePath: " &amp; path.NamespacePath)
59     ///         Console.WriteLine("ClassName: " &amp; path.ClassName)
60     ///         Console.WriteLine("IsClass: " &amp; path.IsClass)
61     ///         Console.WriteLine("IsInstance: " &amp; path.IsInstance)
62     ///         Console.WriteLine("IsSingleton: " &amp; path.IsSingleton)
63     ///
64     ///         ' Change a portion of the full path
65     ///         path.Server= "AnotherServer"
66     ///         Console.WriteLine("New Path: " &amp; path.Path)
67     ///         Return 0
68     ///     End Function
69     /// End Class
70     ///    </code>
71     /// </example>
72     [TypeConverter(typeof(ManagementPathConverter ))]
73     public class ManagementPath : ICloneable
74     {
75         private static ManagementPath defaultPath = new ManagementPath("//./root/cimv2");
76 
77         //Used to minimize the cases in which new wbemPath (WMI object path parser) objects need to be constructed
78         //This is done for performance reasons.
79         private bool   isWbemPathShared = false;
80 
81         internal event IdentifierChangedEventHandler IdentifierChanged;
82 
83         //Fires IdentifierChanged event
FireIdentifierChanged()84         private void FireIdentifierChanged()
85         {
86             if (IdentifierChanged != null)
87                 IdentifierChanged(this, null);
88         }
89 
90         //internal factory
91         /// <summary>
92         /// Internal static "factory" method for making a new ManagementPath
93         /// from the system property of a WMI object
94         /// </summary>
95         /// <param name="wbemObject">The WMI object whose __PATH property will
96         /// be used to supply the returned object</param>
GetManagementPath( IWbemClassObjectFreeThreaded wbemObject)97         internal static string GetManagementPath (
98             IWbemClassObjectFreeThreaded wbemObject)
99         {
100             string path = null;
101             int status  = (int)ManagementStatus.Failed;
102 
103             if (null != wbemObject)
104             {
105                 int dummy1 = 0, dummy2 = 0;
106                 object val = null;
107                 status = wbemObject.Get_ ("__PATH", 0, ref val, ref dummy1, ref dummy2);
108                 if ((status < 0) || (val == System.DBNull.Value))
109                 {
110                     //try to get the relpath instead
111                     status = wbemObject.Get_ ("__RELPATH", 0, ref val, ref dummy1, ref dummy2);
112                     if (status < 0)
113                     {
114                         if ((status & 0xfffff000) == 0x80041000)
115                             ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
116                         else
117                             Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
118                     }
119                 }
120 
121                 if (System.DBNull.Value == val)
122                     path = null;
123                 else
124                     path = (string)val;
125             }
126 
127             return path;
128         }
129 
130         //Used internally to check whether a string passed in as a namespace is indeed syntactically correct
131         //for a namespace (e.g. either has "\" or "/" in it or is the special case of "root")
132         //This doesn't check for the existance of that namespace, nor does it guarrantee correctness.
IsValidNamespaceSyntax(string nsPath)133         internal static bool IsValidNamespaceSyntax(string nsPath)
134         {
135             if (nsPath.Length != 0)
136             {
137                 // Any path separators present?
138                 char[] pathSeparators = { '\\', '/' };
139                 if (nsPath.IndexOfAny(pathSeparators) == -1)
140                 {
141                     // No separators.  The only valid path is "root".
142                     if (String.Compare("root", nsPath, StringComparison.OrdinalIgnoreCase) != 0)
143                         return false;
144                 }
145             }
146 
147             return true;
148         }
149 
150 
_Clone(ManagementPath path)151         internal static ManagementPath _Clone(ManagementPath path)
152         {
153             return ManagementPath._Clone(path, null);
154         }
155 
_Clone(ManagementPath path, IdentifierChangedEventHandler handler)156         internal static ManagementPath _Clone(ManagementPath path, IdentifierChangedEventHandler handler)
157         {
158             ManagementPath pathTmp = new ManagementPath();
159 
160             // Wire up change handler chain. Use supplied handler, if specified;
161             // otherwise, default to that of the path argument.
162             if (handler != null)
163                 pathTmp.IdentifierChanged = handler;
164 
165             // Assign ManagementPath IWbemPath to this.wmiPath.
166             // Optimization for performance : As long as the path is only read, we share this interface.
167             // On the first write, a private copy will be needed;
168             // isWbemPathShared signals ManagementPath to create such a copy at write-time.
169             if (path != null && path.wmiPath != null)
170             {
171                 pathTmp.wmiPath = path.wmiPath;
172                 pathTmp.isWbemPathShared = path.isWbemPathShared = true;
173             }
174 
175             return pathTmp;
176         }
177 
178         /// <overload>
179         ///    Initializes a new instance
180         ///    of the <see cref='System.Management.ManagementPath'/> class.
181         /// </overload>
182         /// <summary>
183         /// <para> Initializes a new instance of the <see cref='System.Management.ManagementPath'/> class that is empty. This is the default constructor.</para>
184         /// </summary>
ManagementPath()185         public ManagementPath () : this ((string) null) {}
186 
187         /// <summary>
188         /// <para>Initializes a new instance of the <see cref='System.Management.ManagementPath'/> class for the given path.</para>
189         /// </summary>
190         /// <param name='path'> The object path. </param>
ManagementPath(string path)191         public ManagementPath(string path)
192         {
193             if ((null != path) && (0 < path.Length))
194                 wmiPath = CreateWbemPath(path);
195         }
196 
197         /// <summary>
198         ///    <para>Returns the full object path as the string representation.</para>
199         /// </summary>
200         /// <returns>
201         ///    A string containing the full object
202         ///    path represented by this object. This value is equivalent to the value of the
203         /// <see cref='System.Management.ManagementPath.Path'/> property.
204         /// </returns>
ToString()205         public override string ToString ()
206         {
207             return this.Path;
208         }
209 
210         /// <summary>
211         /// <para>Returns a copy of the <see cref='System.Management.ManagementPath'/>.</para>
212         /// </summary>
213         /// <returns>
214         ///    The cloned object.
215         /// </returns>
Clone()216         public ManagementPath Clone ()
217         {
218             return new ManagementPath (Path);
219         }
220 
221         /// <summary>
222         /// Standard Clone returns a copy of this ManagementPath as a generic "Object" type
223         /// </summary>
224         /// <returns>
225         ///    The cloned object.
226         /// </returns>
ICloneable.Clone()227         object ICloneable.Clone ()
228         {
229             return Clone ();
230         }
231 
232         /// <summary>
233         ///    <para>Gets or sets the default scope path used when no scope is specified.
234         ///       The default scope is /-/ \\.\root\cimv2, and can be changed by setting this property.</para>
235         /// </summary>
236         /// <value>
237         ///    <para>By default the scope value is /-/ \\.\root\cimv2, or a different scope path if
238         ///       the default was changed.</para>
239         /// </value>
240         public static ManagementPath DefaultPath
241         {
242             get { return ManagementPath.defaultPath; }
243             set { ManagementPath.defaultPath = value; }
244         }
245 
246         //private members
247         private IWbemPath       wmiPath;
248 
CreateWbemPath(string path)249         private IWbemPath CreateWbemPath(string path)
250         {
251             IWbemPath wbemPath = (IWbemPath)MTAHelper.CreateInMTA(typeof(WbemDefPath));//new WbemDefPath();
252             SetWbemPath(wbemPath, path);
253             return wbemPath;
254         }
255 
SetWbemPath(string path)256         private void SetWbemPath(string path)
257         {
258             // Test/utilize isWbemPathShared *only* on public + internal members!
259             if (wmiPath == null)
260                 wmiPath = CreateWbemPath(path);
261             else
262                 SetWbemPath(wmiPath, path);
263         }
264 
SetWbemPath(IWbemPath wbemPath, string path)265         private static void SetWbemPath(IWbemPath wbemPath, string path)
266         {
267             if (null != wbemPath)
268             {
269                 uint flags = (uint) tag_WBEM_PATH_CREATE_FLAG.WBEMPATH_CREATE_ACCEPT_ALL;
270 
271                 //For now we have to special-case the "root" namespace -
272                 //  this is because in the case of "root", the path parser cannot tell whether
273                 //  this is a namespace name or a class name
274                 if (String.Compare(path, "root", StringComparison.OrdinalIgnoreCase) == 0)
275                     flags = flags | (uint) tag_WBEM_PATH_CREATE_FLAG.WBEMPATH_TREAT_SINGLE_IDENT_AS_NS;
276 
277                 int status = wbemPath.SetText_(flags, path);
278 
279                 if (status < 0)
280                 {
281                     if ((status & 0xfffff000) == 0x80041000)
282                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
283                     else
284                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
285                 }
286             }
287         }
288 
GetWbemPath()289         private string GetWbemPath()
290         {
291             return GetWbemPath(this.wmiPath);
292         }
293 
GetWbemPath(IWbemPath wbemPath)294         private static string GetWbemPath(IWbemPath wbemPath)
295         {
296             String pathStr = String.Empty;
297 
298             if (null != wbemPath)
299             {
300                 // Requesting the path from a parser which has
301                 // been only given a relative path results in an incorrect
302                 // value being returned (e.g. \\.\win32_logicaldisk). To work
303                 // around this we check if there are any namespaces,
304                 // and if not ask for the relative path instead.
305                 int flags = (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_SERVER_TOO;
306                 uint nCount = 0;
307 
308                 int status = (int)ManagementStatus.NoError;
309 
310                 status = wbemPath.GetNamespaceCount_(out nCount);
311 
312                 if (status >= 0)
313                 {
314                     if (0 == nCount)
315                         flags = (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_RELATIVE_ONLY;
316 
317                     // Get the space we need to reserve
318                     uint bufLen = 0;
319 
320                     status = wbemPath.GetText_(flags, ref bufLen, null);
321 
322                     if (status >= 0 && 0 < bufLen)
323                     {
324                         pathStr = new String ('0', (int) bufLen-1);
325                         status = wbemPath.GetText_(flags, ref bufLen, pathStr);
326                     }
327                 }
328 
329                 if (status < 0)
330                 {
331                     if (status == (int)tag_WBEMSTATUS.WBEM_E_INVALID_PARAMETER)
332                     {
333                         // Interpret as unspecified - return ""
334                     }
335 
336                     else if ((status & 0xfffff000) == 0x80041000)
337                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
338                     else
339                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
340                 }
341             }
342 
343             return pathStr;
344         }
345 
ClearKeys(bool setAsSingleton)346         private void ClearKeys (bool setAsSingleton)
347         {
348             // Test/utilize isWbemPathShared *only* on public + internal members!
349             int status = (int)ManagementStatus.NoError;
350 
351             try
352             {
353                 if (null != wmiPath)
354                 {
355                     IWbemPathKeyList keyList = null;
356                     status = wmiPath.GetKeyList_(out keyList);
357 
358                     if (null != keyList)
359                     {
360                         status = keyList.RemoveAllKeys_(0);
361                         if ((status & 0x80000000) == 0)
362                         {
363                             sbyte bSingleton = (setAsSingleton) ? (sbyte)(-1) : (sbyte)0;
364                             status = keyList.MakeSingleton_(bSingleton);
365                             FireIdentifierChanged ();
366                         }
367                     }
368                 }
369             }
370             catch (COMException e)
371             {
372                 ManagementException.ThrowWithExtendedInfo(e);
373             }
374 
375             if ((status & 0xfffff000) == 0x80041000)
376             {
377                 ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
378             }
379             else if ((status & 0x80000000) != 0)
380             {
381                 Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
382             }
383         }
384 
385         internal bool IsEmpty
386         {
387             get
388             {
389                 return (Path.Length == 0 ) ;
390             }
391         }
392 
393 
394         //
395         // Methods
396         //
397 
398         /// <summary>
399         ///    <para> Sets the path as a new class path. This means that the path must have
400         ///       a class name but not key values.</para>
401         /// </summary>
SetAsClass()402         public void SetAsClass ()
403         {
404             if (IsClass || IsInstance)
405             {
406                 // Check if this IWbemPath is shared among multiple managed objects.
407                 // With this write, it will have to maintain its own copy.
408                 if (isWbemPathShared)
409                 {
410                     wmiPath = CreateWbemPath(this.GetWbemPath());
411                     isWbemPathShared = false;
412                 }
413 
414                 ClearKeys (false);
415             }
416             else
417                 throw new ManagementException (ManagementStatus.InvalidOperation, null, null);
418         }
419 
420         /// <summary>
421         ///    <para> Sets the path as a new singleton object path. This means that it is a path to an instance but
422         ///       there are no key values.</para>
423         /// </summary>
SetAsSingleton()424         public void SetAsSingleton ()
425         {
426             if (IsClass || IsInstance)
427             {
428                 // Check if this IWbemPath is shared among multiple managed objects.
429                 // With this write, it will have to maintain its own copy.
430                 if (isWbemPathShared)
431                 {
432                     wmiPath = CreateWbemPath(this.GetWbemPath());
433                     isWbemPathShared = false;
434                 }
435 
436                 ClearKeys (true);
437             }
438             else
439                 throw new ManagementException (ManagementStatus.InvalidOperation, null, null);
440         }
441 
442         //
443         // Properties
444         //
445 
446         /// <summary>
447         ///    <para> Gets or sets the string representation of the full path in the object.</para>
448         /// </summary>
449         /// <value>
450         ///    <para>A string containing the full path
451         ///       represented in this object.</para>
452         /// </value>
453         [RefreshProperties(RefreshProperties.All)]
454         public string Path
455         {
456             get
457             {
458                 return this.GetWbemPath();
459             }
460             set
461             {
462                 try
463                 {
464                     // Before overwriting, check it's OK
465                     // Note, we've never done such validation, should we?
466                     //
467                     // Check if this IWbemPath is shared among multiple managed objects.
468                     // With this write, it will have to maintain its own copy.
469                     if (isWbemPathShared)
470                     {
471                         wmiPath = CreateWbemPath(this.GetWbemPath());
472                         isWbemPathShared = false;
473                     }
474 
475                     this.SetWbemPath(value);
476                 }
477                 catch
478                 {
479                     throw new ArgumentOutOfRangeException ("value");
480                 }
481                 FireIdentifierChanged();
482             }
483         }
484 
485         /// <summary>
486         ///    <para> Gets or sets the relative path: class name and keys only.</para>
487         /// </summary>
488         /// <value>
489         ///    A string containing the relative
490         ///    path (not including the server and namespace portions) represented in this
491         ///    object.
492         /// </value>
493         [RefreshProperties(RefreshProperties.All)]
494         public string RelativePath
495         {
496             get
497             {
498                 String pathStr = String.Empty;
499 
500                 if (null != wmiPath)
501                 {
502                     // Get the space we need to reserve
503                     uint bufLen = 0;
504                     int status = wmiPath.GetText_(
505                         (int) tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_RELATIVE_ONLY,
506                         ref bufLen,
507                         null);
508 
509                     if (status >= 0 && 0 < bufLen)
510                     {
511                         pathStr = new String ('0', (int) bufLen-1);
512                         status = wmiPath.GetText_(
513                             (int) tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_RELATIVE_ONLY,
514                             ref bufLen,
515                             pathStr);
516                     }
517 
518                     if (status < 0)
519                     {
520                         if (status == (int)tag_WBEMSTATUS.WBEM_E_INVALID_PARAMETER)
521                         {
522                             // Interpret as unspecified - return ""
523                         }
524                         else if ((status & 0xfffff000) == 0x80041000)
525                             ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
526                         else
527                             Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
528                     }
529                 }
530 
531                 return pathStr;
532             }
533 
534             set
535             {
536                 try
537                 {
538                     // No need for isWbemPathShared here since internal SetRelativePath
539                     // always creates a new copy.
540                     SetRelativePath (value);
541                 }
542                 catch (COMException)
543                 {
544                     throw new ArgumentOutOfRangeException ("value");
545                 }
546                 FireIdentifierChanged();
547             }
548         }
549 
SetRelativePath(string relPath)550         internal void SetRelativePath (string relPath)
551         {
552             // No need for isWbemPathShared here since internal SetRelativePath
553             // always creates a new copy.
554             ManagementPath newPath = new ManagementPath (relPath);
555             newPath.NamespacePath = this.GetNamespacePath((int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY);
556             newPath.Server = this.Server;
557             wmiPath = newPath.wmiPath;
558         }
559 
560         //Used to update the relative path when the user changes any key properties
UpdateRelativePath(string relPath)561         internal void UpdateRelativePath(string relPath)
562         {
563             if (relPath == null)
564                 return;
565 
566             //Get the server & namespace part from the existing path, and concatenate the given relPath.
567             //NOTE : we need to do this because IWbemPath doesn't have a function to set the relative path alone...
568             string newPath = String.Empty;
569             string nsPath = this.GetNamespacePath((int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY);
570 
571             if (nsPath.Length>0 )
572                 newPath = String.Concat(nsPath, ":", relPath);
573             else
574                 newPath = relPath;
575 
576             // Check if this IWbemPath is shared among multiple managed objects.
577             // With this write, it will have to maintain its own copy.
578             if (isWbemPathShared)
579             {
580                 wmiPath = CreateWbemPath(this.GetWbemPath());
581                 isWbemPathShared = false;
582             }
583 
584             this.SetWbemPath(newPath);
585         }
586 
587 
588         /// <summary>
589         ///    <para>Gets or sets the server part of the path.</para>
590         /// </summary>
591         /// <value>
592         ///    A string containing the server name
593         ///    from the path represented in this object.
594         /// </value>
595         [RefreshProperties(RefreshProperties.All)]
596         public string Server
597         {
598             get
599             {
600                 String pathStr = String.Empty;
601 
602                 if (null != wmiPath)
603                 {
604 
605                     uint uLen = 0;
606                     int status = wmiPath.GetServer_(ref uLen, null);
607 
608                     if (status >= 0 && 0 < uLen)
609                     {
610                         pathStr = new String ('0', (int) uLen-1);
611                         status = wmiPath.GetServer_(ref uLen, pathStr);
612                     }
613 
614                     if (status < 0)
615                     {
616                         if (status == (int)tag_WBEMSTATUS.WBEM_E_NOT_AVAILABLE)
617                         {
618                             // Interpret as unspecified - return ""
619                         }
620                         else if ((status & 0xfffff000) == 0x80041000)
621                             ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
622                         else
623                             Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
624                     }
625                 }
626 
627                 return pathStr;
628             }
629             set
630             {
631                 String oldValue = Server;
632 
633                 // Only set if changed
634                 if (0 != String.Compare(oldValue,value,StringComparison.OrdinalIgnoreCase))
635                 {
636                     if (null == wmiPath)
637                         wmiPath = (IWbemPath)MTAHelper.CreateInMTA(typeof(WbemDefPath));//new WbemDefPath ();
638                     else if (isWbemPathShared)
639                     {
640                         // Check if this IWbemPath is shared among multiple managed objects.
641                         // With this write, it will have to maintain its own copy.
642                         wmiPath = CreateWbemPath(this.GetWbemPath());
643                         isWbemPathShared = false;
644                     }
645 
646                     int status = wmiPath.SetServer_(value);
647 
648                     if (status < 0)
649                     {
650                         if ((status & 0xfffff000) == 0x80041000)
651                             ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
652                         else
653                             Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
654                     }
655 
656                     FireIdentifierChanged();
657                 }
658             }
659         }
660 
SetNamespacePath(string nsPath, out bool bChange)661         internal string SetNamespacePath(string nsPath, out bool bChange)
662         {
663             int         status = (int)ManagementStatus.NoError;
664             string      nsOrg = null;
665             string      nsNew = null;
666             IWbemPath   wmiPathTmp = null;
667             bChange = false;
668 
669             Debug.Assert(nsPath != null);
670 
671             //Do some validation on the path to make sure it is a valid namespace path (at least syntactically)
672             if (!IsValidNamespaceSyntax(nsPath))
673                 ManagementException.ThrowWithExtendedInfo((ManagementStatus)tag_WBEMSTATUS.WBEM_E_INVALID_NAMESPACE);
674 
675             wmiPathTmp = CreateWbemPath(nsPath);
676             if (wmiPath == null)
677                 wmiPath = this.CreateWbemPath("");
678             else if (isWbemPathShared)
679             {
680                 // Check if this IWbemPath is shared among multiple managed objects.
681                 // With this write, it will have to maintain its own copy.
682                 wmiPath = CreateWbemPath(this.GetWbemPath());
683                 isWbemPathShared = false;
684             }
685 
686             nsOrg = GetNamespacePath(wmiPath,
687                 (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_NAMESPACE_ONLY);
688             nsNew = GetNamespacePath(wmiPathTmp,
689                 (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_NAMESPACE_ONLY);
690 
691             if (String.Compare(nsOrg, nsNew, StringComparison.OrdinalIgnoreCase) != 0)
692             {
693                 wmiPath.RemoveAllNamespaces_();                                 // Out with the old... Ignore status code.
694 
695                 // Add the new ones in
696                 bChange = true;                                                 // Now dirty from above.
697                 uint nCount = 0;
698                 status = wmiPathTmp.GetNamespaceCount_(out nCount);
699 
700                 if (status >= 0)
701                 {
702                     for (uint i = 0; i < nCount; i++)
703                     {
704                         uint uLen = 0;
705                         status = wmiPathTmp.GetNamespaceAt_(i, ref uLen, null);
706 
707                         if (status >= 0)
708                         {
709                             string nSpace = new String('0', (int) uLen-1);
710                             status = wmiPathTmp.GetNamespaceAt_(i, ref uLen, nSpace);
711                             if (status >= 0)
712                             {
713                                 status = wmiPath.SetNamespaceAt_(i, nSpace);
714 
715                                 if (status < 0)
716                                     break;
717                             }
718                             else
719                                 break;
720                         }
721                         else
722                             break;
723                     }
724                 }
725             }
726             else {;}    // Continue on. Could have different server name, same ns specified.
727 
728             //
729             // Update Server property if specified in the namespace.
730             // eg: "\\MyServer\root\cimv2".
731             //
732             if (status >= 0 && nsPath.Length > 1 &&
733                 (nsPath[0] == '\\' && nsPath[1] == '\\' ||
734                 nsPath[0] == '/'  && nsPath[1] == '/'))
735             {
736                 uint uLen = 0;
737                 status = wmiPathTmp.GetServer_(ref uLen, null);
738 
739                 if (status >= 0 && uLen > 0)
740                 {
741                     string serverNew = new String ('0', (int) uLen-1);
742                     status = wmiPathTmp.GetServer_(ref uLen, serverNew);
743 
744                     if (status >= 0)
745                     {
746                         // Compare server name on this object, if specified, to the caller's.
747                         //     Update this object if different or unspecified.
748                         uLen = 0;
749                         status = wmiPath.GetServer_(ref uLen, null);            // NB: Cannot use property get since it may throw.
750 
751                         if (status >= 0)
752                         {
753                             string serverOrg = new String('0', (int)uLen-1);
754                             status = wmiPath.GetServer_(ref uLen, serverOrg);
755 
756                             if (status >= 0 && String.Compare(serverOrg, serverNew, StringComparison.OrdinalIgnoreCase) != 0)
757                                 status = wmiPath.SetServer_(serverNew);
758                         }
759                         else if (status == (int)tag_WBEMSTATUS.WBEM_E_NOT_AVAILABLE)
760                         {
761                             status = wmiPath.SetServer_(serverNew);
762                             if (status >= 0)
763                                 bChange = true;
764                         }
765                     }
766                 }
767                 else if (status == (int)tag_WBEMSTATUS.WBEM_E_NOT_AVAILABLE)    // No caller-supplied server name;
768                     status = (int)ManagementStatus.NoError;                     // Ignore error.
769             }
770 
771             if (status < 0)
772             {
773                 if ((status & 0xfffff000) == 0x80041000)
774                     ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
775                 else
776                     Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
777             }
778 
779             return nsNew;
780         }
781 
GetNamespacePath(int flags)782         internal string GetNamespacePath(int flags)
783         {
784             return GetNamespacePath(wmiPath, flags);
785         }
786 
GetNamespacePath(IWbemPath wbemPath, int flags)787         internal static string GetNamespacePath(IWbemPath wbemPath, int flags)
788         {
789             string pathStr = String.Empty;
790 
791             if (null != wbemPath)
792             {
793                 // Requesting the namespace path from a parser which has
794                 // been only given a relative path results in an incorrect
795                 // value being returned (e.g. \\.\). To work
796                 // around this, check if there are any namespaces,
797                 // and if not just return "".
798                 uint nCount = 0;
799                 int status = (int)ManagementStatus.NoError;
800 
801                 status = wbemPath.GetNamespaceCount_(out nCount);
802 
803                 if (status >= 0 && nCount > 0)
804                 {
805                     // Get the space we need to reserve
806                     uint bufLen = 0;
807                     status = wbemPath.GetText_(flags, ref bufLen, null);
808 
809                     if (status >= 0 && bufLen > 0)
810                     {
811                         pathStr = new String ('0', (int) bufLen-1);
812                         status = wbemPath.GetText_(flags, ref bufLen, pathStr);
813                     }
814                 }
815 
816                 if (status < 0)
817                 {
818                     if (status == (int)tag_WBEMSTATUS.WBEM_E_INVALID_PARAMETER)
819                     {
820                         // Interpret as unspecified - return ""
821                     }
822                     else if ((status & 0xfffff000) == 0x80041000)
823                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
824                     else
825                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
826                 }
827             }
828 
829             return pathStr;
830         }
831 
832         /// <summary>
833         ///    <para>Gets or sets the namespace part of the path. Note that this does not include
834         ///       the server name, which can be retrieved separately.</para>
835         /// </summary>
836         /// <value>
837         ///    A string containing the namespace
838         ///    portion of the path represented in this object.
839         /// </value>
840         [RefreshProperties(RefreshProperties.All)]
841         public string NamespacePath
842         {
843             get
844             {
845                 return GetNamespacePath((int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_NAMESPACE_ONLY);
846             }
847             set
848             {
849                 bool bChange = false;
850 
851                 try
852                 {
853                     // isWbemPathShared handled in internal SetNamespacePath.
854                     SetNamespacePath(value, out bChange);
855                 }
856                 catch (COMException)
857                 {
858                     throw new ArgumentOutOfRangeException ("value");
859                 }
860 
861                 if (bChange)
862                     FireIdentifierChanged();
863             }
864         }
865 
866         /// <summary>
867         ///    Gets or sets the class portion of the path.
868         /// </summary>
869         /// <value>
870         ///    A string containing the name of the
871         ///    class.
872         /// </value>
873         [RefreshProperties(RefreshProperties.All)]
874         public string ClassName
875         {
876             get
877             {
878                 return internalClassName;
879             }
880             set
881             {
882                 String oldValue = ClassName;
883 
884                 // Only set if changed
885                 if (0 != String.Compare(oldValue,value,StringComparison.OrdinalIgnoreCase))
886                 {
887                     // isWbemPathShared handled in internal className property accessor.
888                     internalClassName = value;
889                     FireIdentifierChanged();
890                 }
891             }
892         }
893 
894         internal string internalClassName
895         {
896             get
897             {
898                 String pathStr = String.Empty;
899                 int status = (int)ManagementStatus.NoError;
900 
901                 if (null != wmiPath)
902                 {
903                     uint bufLen = 0;
904                     status = wmiPath.GetClassName_(ref bufLen, null);
905 
906                     if (status >= 0 && 0 < bufLen)
907                     {
908                         pathStr = new String ('0', (int) bufLen-1);
909                         status = wmiPath.GetClassName_(ref bufLen, pathStr);
910 
911                         if (status < 0)
912                             pathStr = String.Empty;
913                     }
914                 }
915 
916                 return pathStr;
917             }
918             set
919             {
920                 int status = (int)ManagementStatus.NoError;
921 
922                 if (wmiPath == null)
923                     wmiPath = (IWbemPath)MTAHelper.CreateInMTA(typeof(WbemDefPath));//new WbemDefPath();
924                 else if (isWbemPathShared)
925                 {
926                     // Check if this IWbemPath is shared among multiple managed objects.
927                     // With this write, it will have to maintain its own copy.
928                     wmiPath = CreateWbemPath(this.GetWbemPath());
929                     isWbemPathShared = false;
930                 }
931 
932                 try
933                 {
934                     status = wmiPath.SetClassName_(value);
935                 }
936                 catch (COMException)
937                 {
938                     throw new ArgumentOutOfRangeException ("value");
939                 }
940 
941                 if (status < 0)
942                 {
943                     if ((status & 0xfffff000) == 0x80041000)
944                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
945                     else
946                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
947                 }
948             }
949         }
950 
951         /// <summary>
952         ///    <para>Gets or sets a value indicating whether this is a class path.</para>
953         /// </summary>
954         /// <value>
955         /// <para><see langword='true'/> if this is a class path; otherwise,
956         /// <see langword='false'/>.</para>
957         /// </value>
958         public bool IsClass
959         {
960             get
961             {
962                 if (null == wmiPath)
963                     return false;
964 
965                 ulong uInfo = 0;
966                 int status = wmiPath.GetInfo_(0, out uInfo);
967 
968                 if (status < 0)
969                 {
970                     if ((status & 0xfffff000) == 0x80041000)
971                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
972                     else
973                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
974                 }
975 
976                 return (0 != (uInfo & (ulong)tag_WBEM_PATH_STATUS_FLAG.WBEMPATH_INFO_IS_CLASS_REF));
977             }
978         }
979 
980         /// <summary>
981         ///    <para>Gets or sets a value indicating whether this is an instance path.</para>
982         /// </summary>
983         /// <value>
984         /// <para><see langword='true'/> if this is an instance path; otherwise,
985         /// <see langword='false'/>.</para>
986         /// </value>
987         public bool IsInstance
988         {
989             get
990             {
991                 if (null == wmiPath)
992                     return false;
993 
994                 ulong uInfo = 0;
995                 int status = wmiPath.GetInfo_(0, out uInfo);
996 
997                 if (status < 0)
998                 {
999                     if ((status & 0xfffff000) == 0x80041000)
1000                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
1001                     else
1002                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
1003                 }
1004 
1005                 return (0 != (uInfo & (ulong)tag_WBEM_PATH_STATUS_FLAG.WBEMPATH_INFO_IS_INST_REF));
1006             }
1007         }
1008 
1009         /// <summary>
1010         ///    <para>Gets or sets a value indicating whether this is a singleton instance path.</para>
1011         /// </summary>
1012         /// <value>
1013         /// <para><see langword='true'/> if this is a singleton instance path; otherwise,
1014         /// <see langword='false'/>.</para>
1015         /// </value>
1016         public bool IsSingleton
1017         {
1018             get
1019             {
1020                 if (null == wmiPath)
1021                     return false;
1022 
1023                 ulong uInfo = 0;
1024                 int status = wmiPath.GetInfo_(0, out uInfo);
1025 
1026                 if (status < 0)
1027                 {
1028                     if ((status & 0xfffff000) == 0x80041000)
1029                         ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
1030                     else
1031                         Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
1032                 }
1033 
1034                 return (0 != (uInfo & (ulong)tag_WBEM_PATH_STATUS_FLAG.WBEMPATH_INFO_IS_SINGLETON));
1035             }
1036         }
1037     }
1038 
1039     /// <summary>
1040     /// Converts a String to a ManagementPath
1041     /// </summary>
1042     class ManagementPathConverter : ExpandableObjectConverter
1043     {
1044 
1045         /// <summary>
1046         /// Determines if this converter can convert an object in the given source type to the native type of the converter.
1047         /// </summary>
1048         /// <param name='context'>An ITypeDescriptorContext that provides a format context.</param>
1049         /// <param name='sourceType'>A Type that represents the type you wish to convert from.</param>
1050         /// <returns>
1051         ///    <para>true if this converter can perform the conversion; otherwise, false.</para>
1052         /// </returns>
CanConvertFrom(ITypeDescriptorContext context, Type sourceType)1053         public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
1054         {
1055             if ((sourceType == typeof(ManagementPath)))
1056             {
1057                 return true;
1058             }
1059             return base.CanConvertFrom(context,sourceType);
1060         }
1061 
1062         /// <summary>
1063         /// Gets a value indicating whether this converter can convert an object to the given destination type using the context.
1064         /// </summary>
1065         /// <param name='context'>An ITypeDescriptorContext that provides a format context.</param>
1066         /// <param name='destinationType'>A Type that represents the type you wish to convert to.</param>
1067         /// <returns>
1068         ///    <para>true if this converter can perform the conversion; otherwise, false.</para>
1069         /// </returns>
CanConvertTo(ITypeDescriptorContext context, Type destinationType)1070         public override Boolean CanConvertTo(ITypeDescriptorContext context, Type destinationType)
1071         {
1072             if ((destinationType == typeof(InstanceDescriptor)))
1073             {
1074                 return true;
1075             }
1076             return base.CanConvertTo(context,destinationType);
1077         }
1078 
1079         /// <summary>
1080         ///      Converts the given object to another type.  The most common types to convert
1081         ///      are to and from a string object.  The default implementation will make a call
1082         ///      to ToString on the object if the object is valid and if the destination
1083         ///      type is string.  If this cannot convert to the desitnation type, this will
1084         ///      throw a NotSupportedException.
1085         /// </summary>
1086         /// <param name='context'>An ITypeDescriptorContext that provides a format context.</param>
1087         /// <param name='culture'>A CultureInfo object. If a null reference (Nothing in Visual Basic) is passed, the current culture is assumed.</param>
1088         /// <param name='value'>The Object to convert.</param>
1089         /// <param name='destinationType'>The Type to convert the value parameter to.</param>
1090         /// <returns>An Object that represents the converted value.</returns>
ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)1091         public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
1092         {
1093 
1094             if (destinationType == null)
1095             {
1096                 throw new ArgumentNullException("destinationType");
1097             }
1098 
1099             if (value is ManagementPath && destinationType == typeof(InstanceDescriptor))
1100             {
1101                 ManagementPath obj = ((ManagementPath)(value));
1102                 ConstructorInfo ctor = typeof(ManagementPath).GetConstructor(new Type[] {typeof(System.String)});
1103                 if (ctor != null)
1104                 {
1105                     return new InstanceDescriptor(ctor, new object[] {obj.Path});
1106                 }
1107             }
1108             return base.ConvertTo(context,culture,value,destinationType);
1109         }
1110     }
1111 }
1112