File: managementpath.cs
Project: ndp\fx\src\wmi\managed\System\Management\System.Management.csproj (System.Management)
using System;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using WbemUtilities_v1;
using WbemClient_v1;
using System.Globalization;
using System.Reflection;
using System.ComponentModel.Design.Serialization;
 
namespace System.Management
{
    /// <summary>
    ///    <para>Provides a wrapper for parsing and building paths to WMI objects.</para>
    /// </summary>
    /// <example>
    ///    <code lang='C#'>using System; 
    /// using System.Management;
    ///  
    /// // This sample displays all properties in a ManagementPath object. 
    /// 
    /// class Sample_ManagementPath 
    /// { 
    ///     public static int Main(string[] args) { 
    ///         ManagementPath path = new ManagementPath( "\\\\MyServer\\MyNamespace:Win32_logicaldisk='c:'");
    ///       
    ///         // Results of full path parsing 
    ///         Console.WriteLine("Path: " + path.Path);
    ///         Console.WriteLine("RelativePath: " + path.RelativePath);
    ///         Console.WriteLine("Server: " + path.Server); 
    ///         Console.WriteLine("NamespacePath: " + path.NamespacePath); 
    ///         Console.WriteLine("ClassName: " + path.ClassName);
    ///         Console.WriteLine("IsClass: " + path.IsClass); 
    ///         Console.WriteLine("IsInstance: " + path.IsInstance); 
    ///         Console.WriteLine("IsSingleton: " + path.IsSingleton); 
    ///            
    ///         // Change a portion of the full path 
    ///         path.Server = "AnotherServer";
    ///         Console.WriteLine("New Path: " + path.Path); 
    ///         return 0; 
    ///    } 
    /// }
    ///    </code>
    ///    <code lang='VB'>Imports System
    /// Imports System.Management 
    /// 
    /// 'This sample displays all properties in a ManagementPath object. 
    /// Class Sample_ManagementPath Overloads
    ///     Public Shared Function Main(args() As String) As Integer
    ///         Dim path As _ New
    ///         ManagementPath("\\MyServer\MyNamespace:Win32_LogicalDisk='c:'") 
    /// 
    ///         ' Results of full path parsing
    ///         Console.WriteLine("Path: " &amp; path.Path) 
    ///         Console.WriteLine("RelativePath: " &amp; path.RelativePath)
    ///         Console.WriteLine("Server: " &amp; path.Server)
    ///         Console.WriteLine("NamespacePath: " &amp; path.NamespacePath) 
    ///         Console.WriteLine("ClassName: " &amp; path.ClassName) 
    ///         Console.WriteLine("IsClass: " &amp; path.IsClass)
    ///         Console.WriteLine("IsInstance: " &amp; path.IsInstance) 
    ///         Console.WriteLine("IsSingleton: " &amp; path.IsSingleton) 
    /// 
    ///         ' Change a portion of the full path 
    ///         path.Server= "AnotherServer"
    ///         Console.WriteLine("New Path: " &amp; path.Path)
    ///         Return 0
    ///     End Function
    /// End Class
    ///    </code>
    /// </example>
    [TypeConverter(typeof(ManagementPathConverter ))]
    public class ManagementPath : ICloneable
    {
        private static ManagementPath defaultPath = new ManagementPath("//./root/cimv2");
 
        //Used to minimize the cases in which new wbemPath (WMI object path parser) objects need to be constructed
        //This is done for performance reasons.
        private bool   isWbemPathShared = false; 
        
        internal event IdentifierChangedEventHandler IdentifierChanged;
 
        //Fires IdentifierChanged event
        private void FireIdentifierChanged()
        {
            if (IdentifierChanged != null)
                IdentifierChanged(this, null);
        }
 
        //internal factory
        /// <summary>
        /// Internal static "factory" method for making a new ManagementPath
        /// from the system property of a WMI object
        /// </summary>
        /// <param name="wbemObject">The WMI object whose __PATH property will
        /// be used to supply the returned object</param>
        internal static string GetManagementPath (
            IWbemClassObjectFreeThreaded wbemObject)
        {
            string path = null;
            int status  = (int)ManagementStatus.Failed;
 
            if (null != wbemObject)
            {
                int dummy1 = 0, dummy2 = 0;
                object val = null;
                status = wbemObject.Get_ ("__PATH", 0, ref val, ref dummy1, ref dummy2);
                if ((status < 0) || (val == System.DBNull.Value))
                {
                    //try to get the relpath instead
                    status = wbemObject.Get_ ("__RELPATH", 0, ref val, ref dummy1, ref dummy2);
                    if (status < 0) 
                    {
                        if ((status & 0xfffff000) == 0x80041000)
                            ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                        else
                            Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                    }
                }
                
                if (System.DBNull.Value == val)
                    path = null;
                else
                    path = (string)val;
            }
 
            return path;
        }
 
        //Used internally to check whether a string passed in as a namespace is indeed syntactically correct
        //for a namespace (e.g. either has "\" or "/" in it or is the special case of "root")
        //This doesn't check for the existance of that namespace, nor does it guarrantee correctness.
        internal static bool IsValidNamespaceSyntax(string nsPath)
        {
            if (nsPath.Length != 0)
            {
                // Any path separators present?
                char[] pathSeparators = { '\\', '/' };
                if (nsPath.IndexOfAny(pathSeparators) == -1)
                {
                    // No separators.  The only valid path is "root".
                    if (String.Compare("root", nsPath, StringComparison.OrdinalIgnoreCase) != 0)
                        return false;
                }
            }
            
            return true;
        }
 
 
        internal static ManagementPath _Clone(ManagementPath path)
        {
            return ManagementPath._Clone(path, null);
        }
 
        internal static ManagementPath _Clone(ManagementPath path, IdentifierChangedEventHandler handler)
        {
            ManagementPath pathTmp = new ManagementPath();
 
            // Wire up change handler chain. Use supplied handler, if specified;
            // otherwise, default to that of the path argument.
            if (handler != null)
                pathTmp.IdentifierChanged = handler;
 
            // Assign ManagementPath IWbemPath to this.wmiPath.  
            // Optimization for performance : As long as the path is only read, we share this interface.
            // On the first write, a private copy will be needed; 
            // isWbemPathShared signals ManagementPath to create such a copy at write-time.
            if (path != null && path.wmiPath != null)
            {
                pathTmp.wmiPath = path.wmiPath;
                pathTmp.isWbemPathShared = path.isWbemPathShared = true;
            }
 
            return pathTmp;
        }
 
        /// <overload>
        ///    Initializes a new instance
        ///    of the <see cref='System.Management.ManagementPath'/> class.
        /// </overload>
        /// <summary>
        /// <para> Initializes a new instance of the <see cref='System.Management.ManagementPath'/> class that is empty. This is the default constructor.</para>
        /// </summary>
        public ManagementPath () : this ((string) null) {}
 
        /// <summary>
        /// <para>Initializes a new instance of the <see cref='System.Management.ManagementPath'/> class for the given path.</para>
        /// </summary>
        /// <param name='path'> The object path. </param>
        public ManagementPath(string path) 
        {
            if ((null != path) && (0 < path.Length))
                wmiPath = CreateWbemPath(path);
        }
        
        /// <summary>
        ///    <para>Returns the full object path as the string representation.</para>
        /// </summary>
        /// <returns>
        ///    A string containing the full object
        ///    path represented by this object. This value is equivalent to the value of the
        /// <see cref='System.Management.ManagementPath.Path'/> property.
        /// </returns>
        public override string ToString () 
        {
            return this.Path;
        }
 
        /// <summary>
        /// <para>Returns a copy of the <see cref='System.Management.ManagementPath'/>.</para>
        /// </summary>
        /// <returns>
        ///    The cloned object.
        /// </returns>
        public ManagementPath Clone ()
        {
            return new ManagementPath (Path);
        }
 
        /// <summary>
        /// Standard Clone returns a copy of this ManagementPath as a generic "Object" type
        /// </summary>
        /// <returns>
        ///    The cloned object.
        /// </returns>
        object ICloneable.Clone ()
        {
            return Clone ();    
        }
 
        /// <summary>
        ///    <para>Gets or sets the default scope path used when no scope is specified.
        ///       The default scope is /-/ \\.\root\cimv2, and can be changed by setting this property.</para>
        /// </summary>
        /// <value>
        ///    <para>By default the scope value is /-/ \\.\root\cimv2, or a different scope path if
        ///       the default was changed.</para>
        /// </value>
        public static ManagementPath DefaultPath 
        {
            get { return ManagementPath.defaultPath; }
            set { ManagementPath.defaultPath = value; }
        }
        
        //private members
        private IWbemPath       wmiPath;
 
        private IWbemPath CreateWbemPath(string path)
        {
            IWbemPath wbemPath = (IWbemPath)MTAHelper.CreateInMTA(typeof(WbemDefPath));//new WbemDefPath();
            SetWbemPath(wbemPath, path);
            return wbemPath;
        }
 
        private void SetWbemPath(string path)
        {
            // Test/utilize isWbemPathShared *only* on public + internal members!
            if (wmiPath == null)
                wmiPath = CreateWbemPath(path);
            else
                SetWbemPath(wmiPath, path);
        }
 
        private static void SetWbemPath(IWbemPath wbemPath, string path)
        {
            if (null != wbemPath)
            {
                uint flags = (uint) tag_WBEM_PATH_CREATE_FLAG.WBEMPATH_CREATE_ACCEPT_ALL;
 
                //For now we have to special-case the "root" namespace - 
                //  this is because in the case of "root", the path parser cannot tell whether 
                //  this is a namespace name or a class name
                //
                if (String.Compare(path, "root", StringComparison.OrdinalIgnoreCase) == 0)
                    flags = flags | (uint) tag_WBEM_PATH_CREATE_FLAG.WBEMPATH_TREAT_SINGLE_IDENT_AS_NS;
 
                int status = wbemPath.SetText_(flags, path);
 
                if (status < 0)
                {
                    if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
            }
        }
 
        private string GetWbemPath()
        {
            return GetWbemPath(this.wmiPath);
        }
 
        private static string GetWbemPath(IWbemPath wbemPath)
        {
            String pathStr = String.Empty;
 
            if (null != wbemPath)
            {
                // 
 
 
 
 
 
                int flags = (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_SERVER_TOO;
                uint nCount = 0;
 
                int status = (int)ManagementStatus.NoError;
 
                status = wbemPath.GetNamespaceCount_(out nCount);
 
                if (status >= 0)
                {
                    if (0 == nCount)
                        flags = (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_RELATIVE_ONLY;
 
                    // Get the space we need to reserve
                    uint bufLen = 0;
                
                    status = wbemPath.GetText_(flags, ref bufLen, null);
 
                    if (status >= 0 && 0 < bufLen)
                    {
                        pathStr = new String ('0', (int) bufLen-1);
                        status = wbemPath.GetText_(flags, ref bufLen, pathStr);
                    }
                }
 
                if (status < 0)
                {
                    if (status == (int)tag_WBEMSTATUS.WBEM_E_INVALID_PARAMETER) 
                    {
                        // Interpret as unspecified - return ""
                    }
                    
                    else if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
            }
 
            return pathStr;
        }
 
        private void ClearKeys (bool setAsSingleton)
        {
            // Test/utilize isWbemPathShared *only* on public + internal members!
            int status = (int)ManagementStatus.NoError;
 
            try 
            {
                if (null != wmiPath)
                {
                    IWbemPathKeyList keyList = null;
                    status = wmiPath.GetKeyList_(out keyList);
 
                    if (null != keyList)
                    {
                        status = keyList.RemoveAllKeys_(0);
                        if ((status & 0x80000000) == 0)
                        {
                            sbyte bSingleton = (setAsSingleton) ? (sbyte)(-1) : (sbyte)0;
                            status = keyList.MakeSingleton_(bSingleton);
                            FireIdentifierChanged ();       // 
                        }
                    }
                }
            }
            catch (COMException e) 
            {
                ManagementException.ThrowWithExtendedInfo(e);
            }
        
            if ((status & 0xfffff000) == 0x80041000)
            {
                ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
            }
            else if ((status & 0x80000000) != 0)
            {
                Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
            }
        }
        
        internal bool IsEmpty 
        {
            get 
            {
                return (Path.Length == 0 ) ;
            }
        }
 
 
        //
        // Methods
        //
 
        /// <summary>
        ///    <para> Sets the path as a new class path. This means that the path must have
        ///       a class name but not key values.</para>
        /// </summary>
        public void SetAsClass ()
        {
            if (IsClass || IsInstance)
            {
                // Check if this IWbemPath is shared among multiple managed objects.
                // With this write, it will have to maintain its own copy.
                if (isWbemPathShared)
                {
                    wmiPath = CreateWbemPath(this.GetWbemPath());
                    isWbemPathShared = false;
                }
 
                ClearKeys (false);
            }
            else
                throw new ManagementException (ManagementStatus.InvalidOperation, null, null);
        }
 
        /// <summary>
        ///    <para> Sets the path as a new singleton object path. This means that it is a path to an instance but
        ///       there are no key values.</para>
        /// </summary>
        public void SetAsSingleton ()
        {
            if (IsClass || IsInstance)
            {
                // Check if this IWbemPath is shared among multiple managed objects.
                // With this write, it will have to maintain its own copy.
                if (isWbemPathShared)
                {
                    wmiPath = CreateWbemPath(this.GetWbemPath());
                    isWbemPathShared = false;
                }
 
                ClearKeys (true);
            }
            else
                throw new ManagementException (ManagementStatus.InvalidOperation, null, null);
        }
 
        //
        // Properties
        //
 
        /// <summary>
        ///    <para> Gets or sets the string representation of the full path in the object.</para>
        /// </summary>
        /// <value>
        ///    <para>A string containing the full path
        ///       represented in this object.</para>
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        public string Path
        {
            get
            {
                return this.GetWbemPath();
            }
            set
            {
                try
                {
                    // Before overwriting, check it's OK
                    // Note, we've never done such validation, should we?
                    //
                    // Check if this IWbemPath is shared among multiple managed objects.
                    // With this write, it will have to maintain its own copy.
                    if (isWbemPathShared)
                    {
                        wmiPath = CreateWbemPath(this.GetWbemPath());
                        isWbemPathShared = false;
                    }
 
                    this.SetWbemPath(value);
                }
                catch
                {
                    throw new ArgumentOutOfRangeException ("value");
                }
                FireIdentifierChanged();
            }
        }
 
        /// <summary>
        ///    <para> Gets or sets the relative path: class name and keys only.</para>
        /// </summary>
        /// <value>
        ///    A string containing the relative
        ///    path (not including the server and namespace portions) represented in this
        ///    object.
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        public string RelativePath
        {
            get 
            { 
                String pathStr = String.Empty;
 
                if (null != wmiPath)
                {
                    // Get the space we need to reserve
                    uint bufLen = 0;
                    int status = wmiPath.GetText_(
                        (int) tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_RELATIVE_ONLY,
                        ref bufLen, 
                        null);
 
                    if (status >= 0 && 0 < bufLen)
                    {
                        pathStr = new String ('0', (int) bufLen-1);
                        status = wmiPath.GetText_(
                            (int) tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_RELATIVE_ONLY,
                            ref bufLen, 
                            pathStr);
                    }
 
                    if (status < 0)
                    {
                        if (status == (int)tag_WBEMSTATUS.WBEM_E_INVALID_PARAMETER) 
                        {
                            // Interpret as unspecified - return ""
                        }
                        else if ((status & 0xfffff000) == 0x80041000)
                            ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                        else
                            Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                    }
                }
 
                return pathStr;
            }
 
            set 
            {
                try 
                {
                    // No need for isWbemPathShared here since internal SetRelativePath
                    // always creates a new copy.
                    SetRelativePath (value);
                } 
                catch (COMException) 
                {
                    throw new ArgumentOutOfRangeException ("value");
                }
                FireIdentifierChanged();
            }
        }
 
        internal void SetRelativePath (string relPath)
        {
            // No need for isWbemPathShared here since internal SetRelativePath
            // always creates a new copy.
            ManagementPath newPath = new ManagementPath (relPath);
            newPath.NamespacePath = this.GetNamespacePath((int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY);
            newPath.Server = this.Server;
            wmiPath = newPath.wmiPath;
        }
 
        //Used to update the relative path when the user changes any key properties
        internal void UpdateRelativePath(string relPath)
        {
            if (relPath == null)
                return;
 
            //Get the server & namespace part from the existing path, and concatenate the given relPath.
            //NOTE : we need to do this because IWbemPath doesn't have a function to set the relative path alone...
            string newPath = String.Empty;
            string nsPath = this.GetNamespacePath((int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY);
 
            if (nsPath.Length>0 )
                newPath = String.Concat(nsPath, ":", relPath);
            else
                newPath = relPath;
 
            // Check if this IWbemPath is shared among multiple managed objects.
            // With this write, it will have to maintain its own copy.
            if (isWbemPathShared)
            {
                wmiPath = CreateWbemPath(this.GetWbemPath());
                isWbemPathShared = false;
            }
 
            this.SetWbemPath(newPath);
        }
 
        
        /// <summary>
        ///    <para>Gets or sets the server part of the path.</para>
        /// </summary>
        /// <value>
        ///    A string containing the server name
        ///    from the path represented in this object.
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        public string Server
        {
            get 
            { 
                String pathStr = String.Empty;
 
                if (null != wmiPath) 
                {
 
                    uint uLen = 0;
                    int status = wmiPath.GetServer_(ref uLen, null);
 
                    if (status >= 0 && 0 < uLen)
                    {
                        pathStr = new String ('0', (int) uLen-1);
                        status = wmiPath.GetServer_(ref uLen, pathStr);
                    }
 
                    if (status < 0)
                    {
                        if (status == (int)tag_WBEMSTATUS.WBEM_E_NOT_AVAILABLE) 
                        {
                            // Interpret as unspecified - return ""
                        }
                        else if ((status & 0xfffff000) == 0x80041000)
                            ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                        else
                            Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                    }
                }
 
                return pathStr;
            }
            set 
            {
                String oldValue = Server;
 
                // Only set if changed
                if (0 != String.Compare(oldValue,value,StringComparison.OrdinalIgnoreCase))
                {
                    if (null == wmiPath)
                        wmiPath = (IWbemPath)MTAHelper.CreateInMTA(typeof(WbemDefPath));//new WbemDefPath ();
                    else if (isWbemPathShared)
                    {
                        // Check if this IWbemPath is shared among multiple managed objects.
                        // With this write, it will have to maintain its own copy.
                        wmiPath = CreateWbemPath(this.GetWbemPath());
                        isWbemPathShared = false;
                    }
 
                    int status = wmiPath.SetServer_(value);
 
                    if (status < 0)
                    {
                        if ((status & 0xfffff000) == 0x80041000)
                            ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                        else
                            Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                    }
 
                    FireIdentifierChanged();
                }
            }
        }
 
        internal string SetNamespacePath(string nsPath, out bool bChange) 
        {
            int         status = (int)ManagementStatus.NoError;
            string      nsOrg = null;
            string      nsNew = null;
            IWbemPath   wmiPathTmp = null; 
            bChange = false;
 
            Debug.Assert(nsPath != null);
 
            //Do some validation on the path to make sure it is a valid namespace path (at least syntactically)
            if (!IsValidNamespaceSyntax(nsPath))
                ManagementException.ThrowWithExtendedInfo((ManagementStatus)tag_WBEMSTATUS.WBEM_E_INVALID_NAMESPACE);
 
            wmiPathTmp = CreateWbemPath(nsPath);
            if (wmiPath == null)
                wmiPath = this.CreateWbemPath("");
            else if (isWbemPathShared)
            {
                // Check if this IWbemPath is shared among multiple managed objects.
                // With this write, it will have to maintain its own copy.
                wmiPath = CreateWbemPath(this.GetWbemPath());
                isWbemPathShared = false;
            }
 
            nsOrg = GetNamespacePath(wmiPath,
                (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_NAMESPACE_ONLY);
            nsNew = GetNamespacePath(wmiPathTmp,
                (int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_NAMESPACE_ONLY);
 
            if (String.Compare(nsOrg, nsNew, StringComparison.OrdinalIgnoreCase) != 0)
            {
                wmiPath.RemoveAllNamespaces_();                                 // Out with the old... Ignore status code.
 
                // Add the new ones in
                bChange = true;                                                 // Now dirty from above.
                uint nCount = 0;
                status = wmiPathTmp.GetNamespaceCount_(out nCount);
 
                if (status >= 0)
                {
                    for (uint i = 0; i < nCount; i++) 
                    {
                        uint uLen = 0;
                        status = wmiPathTmp.GetNamespaceAt_(i, ref uLen, null);
                            
                        if (status >= 0)
                        {
                            string nSpace = new String('0', (int) uLen-1);
                            status = wmiPathTmp.GetNamespaceAt_(i, ref uLen, nSpace);
                            if (status >= 0)
                            {
                                status = wmiPath.SetNamespaceAt_(i, nSpace);
                                    
                                if (status < 0)
                                    break;
                            }
                            else
                                break;
                        }
                        else
                            break;
                    }
                }
            }
            else {;}    // Continue on. Could have different server name, same ns specified.
 
            //
            // Update Server property if specified in the namespace.
            // eg: "\\MyServer\root\cimv2".
            //
            if (status >= 0 && nsPath.Length > 1 &&
                (nsPath[0] == '\\' && nsPath[1] == '\\' ||
                nsPath[0] == '/'  && nsPath[1] == '/'))
            {
                uint uLen = 0;
                status = wmiPathTmp.GetServer_(ref uLen, null);
 
                if (status >= 0 && uLen > 0)
                {
                    string serverNew = new String ('0', (int) uLen-1);
                    status = wmiPathTmp.GetServer_(ref uLen, serverNew);
 
                    if (status >= 0)
                    {
                        // Compare server name on this object, if specified, to the caller's.
                        //     Update this object if different or unspecified.
                        uLen = 0;
                        status = wmiPath.GetServer_(ref uLen, null);            // NB: Cannot use property get since it may throw.
 
                        if (status >= 0)
                        {
                            string serverOrg = new String('0', (int)uLen-1);
                            status = wmiPath.GetServer_(ref uLen, serverOrg);
 
                            if (status >= 0 && String.Compare(serverOrg, serverNew, StringComparison.OrdinalIgnoreCase) != 0)
                                status = wmiPath.SetServer_(serverNew);
                        }
                        else if (status == (int)tag_WBEMSTATUS.WBEM_E_NOT_AVAILABLE)
                        {
                            status = wmiPath.SetServer_(serverNew);
                            if (status >= 0)
                                bChange = true;
                        }
                    }
                }
                else if (status == (int)tag_WBEMSTATUS.WBEM_E_NOT_AVAILABLE)    // No caller-supplied server name;
                    status = (int)ManagementStatus.NoError;                     // Ignore error.
            }
 
            if (status < 0)
            {
                if ((status & 0xfffff000) == 0x80041000)
                    ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                else
                    Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
            }
 
            return nsNew;
        }
 
        internal string GetNamespacePath(int flags)
        {
            return GetNamespacePath(wmiPath, flags);
        }
 
        internal static string GetNamespacePath(IWbemPath wbemPath, int flags)
        {
            string pathStr = String.Empty;
 
            if (null != wbemPath)
            {
                // 
 
 
 
 
 
                uint nCount = 0;
                int status = (int)ManagementStatus.NoError;
 
                status = wbemPath.GetNamespaceCount_(out nCount);
 
                if (status >= 0 && nCount > 0)
                {
                    // Get the space we need to reserve
                    uint bufLen = 0;
                    status = wbemPath.GetText_(flags, ref bufLen, null);
 
                    if (status >= 0 && bufLen > 0)
                    {
                        pathStr = new String ('0', (int) bufLen-1);
                        status = wbemPath.GetText_(flags, ref bufLen, pathStr);
                    }
                }
 
                if (status < 0)
                {
                    if (status == (int)tag_WBEMSTATUS.WBEM_E_INVALID_PARAMETER) 
                    {
                        // Interpret as unspecified - return ""
                    }
                    else if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
            }
 
            return pathStr;
        }
 
        /// <summary>
        ///    <para>Gets or sets the namespace part of the path. Note that this does not include
        ///       the server name, which can be retrieved separately.</para>
        /// </summary>
        /// <value>
        ///    A string containing the namespace
        ///    portion of the path represented in this object.
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        public string NamespacePath 
        {
            get 
            {
                return GetNamespacePath((int)tag_WBEM_GET_TEXT_FLAGS.WBEMPATH_GET_NAMESPACE_ONLY);
            }
            set 
            {
                bool bChange = false;
 
                try
                {
                    // isWbemPathShared handled in internal SetNamespacePath.
                    SetNamespacePath(value, out bChange);
                }
                catch (COMException)
                {
                    throw new ArgumentOutOfRangeException ("value");
                }
 
                if (bChange)
                    FireIdentifierChanged();
            }
        }
 
        /// <summary>
        ///    Gets or sets the class portion of the path.
        /// </summary>
        /// <value>
        ///    A string containing the name of the
        ///    class.
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        public string ClassName
        {
            get
            {
                return internalClassName;
            }
            set 
            {
                String oldValue = ClassName;
 
                // Only set if changed
                if (0 != String.Compare(oldValue,value,StringComparison.OrdinalIgnoreCase))
                {
                    // isWbemPathShared handled in internal className property accessor.
                    internalClassName = value;
                    FireIdentifierChanged();
                }
            }
        }
 
        internal string internalClassName
        {
            get
            {
                String pathStr = String.Empty;
                int status = (int)ManagementStatus.NoError;
 
                if (null != wmiPath)
                {
                    uint bufLen = 0;
                    status = wmiPath.GetClassName_(ref bufLen, null);
 
                    if (status >= 0 && 0 < bufLen)
                    {
                        pathStr = new String ('0', (int) bufLen-1);
                        status = wmiPath.GetClassName_(ref bufLen, pathStr);
 
                        if (status < 0)
                            pathStr = String.Empty;
                    }
                }
 
                return pathStr;
            }
            set
            {
                int status = (int)ManagementStatus.NoError;
 
                if (wmiPath == null)
                    wmiPath = (IWbemPath)MTAHelper.CreateInMTA(typeof(WbemDefPath));//new WbemDefPath();
                else if (isWbemPathShared)
                {
                    // Check if this IWbemPath is shared among multiple managed objects.
                    // With this write, it will have to maintain its own copy.
                    wmiPath = CreateWbemPath(this.GetWbemPath());
                    isWbemPathShared = false;
                }
 
                try
                {
                    status = wmiPath.SetClassName_(value);
                }
                catch (COMException)
                {       // 
                    throw new ArgumentOutOfRangeException ("value");
                }
 
                if (status < 0)
                {
                    if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
            }
        }
            
        /// <summary>
        ///    <para>Gets or sets a value indicating whether this is a class path.</para>
        /// </summary>
        /// <value>
        /// <para><see langword='true'/> if this is a class path; otherwise, 
        /// <see langword='false'/>.</para>
        /// </value>
        public bool IsClass 
        {
            get
            {
                if (null == wmiPath)
                    return false;
 
                ulong uInfo = 0;
                int status = wmiPath.GetInfo_(0, out uInfo);
 
                if (status < 0)
                {
                    if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
 
                return (0 != (uInfo & (ulong)tag_WBEM_PATH_STATUS_FLAG.WBEMPATH_INFO_IS_CLASS_REF));
            }
        }
 
        /// <summary>
        ///    <para>Gets or sets a value indicating whether this is an instance path.</para>
        /// </summary>
        /// <value>
        /// <para><see langword='true'/> if this is an instance path; otherwise, 
        /// <see langword='false'/>.</para>
        /// </value>
        public bool IsInstance 
        {
            get
            {
                if (null == wmiPath)
                    return false;
 
                ulong uInfo = 0;
                int status = wmiPath.GetInfo_(0, out uInfo);
 
                if (status < 0)
                {
                    if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
 
                return (0 != (uInfo & (ulong)tag_WBEM_PATH_STATUS_FLAG.WBEMPATH_INFO_IS_INST_REF));
            }
        }
 
        /// <summary>
        ///    <para>Gets or sets a value indicating whether this is a singleton instance path.</para>
        /// </summary>
        /// <value>
        /// <para><see langword='true'/> if this is a singleton instance path; otherwise, 
        /// <see langword='false'/>.</para>
        /// </value>
        public bool IsSingleton 
        {
            get
            {
                if (null == wmiPath)
                    return false;
 
                ulong uInfo = 0;
                int status = wmiPath.GetInfo_(0, out uInfo);
 
                if (status < 0)
                {
                    if ((status & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)status);
                    else
                        Marshal.ThrowExceptionForHR(status, WmiNetUtilsHelper.GetErrorInfo_f());
                }
 
                return (0 != (uInfo & (ulong)tag_WBEM_PATH_STATUS_FLAG.WBEMPATH_INFO_IS_SINGLETON));
            }
        }
    }
 
    /// <summary>
    /// Converts a String to a ManagementPath
    /// </summary>
    class ManagementPathConverter : ExpandableObjectConverter 
    {
        
        /// <summary>
        /// Determines if this converter can convert an object in the given source type to the native type of the converter. 
        /// </summary>
        /// <param name='context'>An ITypeDescriptorContext that provides a format context.</param>
        /// <param name='sourceType'>A Type that represents the type you wish to convert from.</param>
        /// <returns>
        ///    <para>true if this converter can perform the conversion; otherwise, false.</para>
        /// </returns>
        public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
        {
            if ((sourceType == typeof(ManagementPath))) 
            {
                return true;
            }
            return base.CanConvertFrom(context,sourceType);
        }
        
        /// <summary>
        /// Gets a value indicating whether this converter can convert an object to the given destination type using the context.
        /// </summary>
        /// <param name='context'>An ITypeDescriptorContext that provides a format context.</param>
        /// <param name='destinationType'>A Type that represents the type you wish to convert to.</param>
        /// <returns>
        ///    <para>true if this converter can perform the conversion; otherwise, false.</para>
        /// </returns>
        public override Boolean CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
        {
            if ((destinationType == typeof(InstanceDescriptor))) 
            {
                return true;
            }
            return base.CanConvertTo(context,destinationType);
        }
        
        /// <summary>
        ///      Converts the given object to another type.  The most common types to convert
        ///      are to and from a string object.  The default implementation will make a call
        ///      to ToString on the object if the object is valid and if the destination
        ///      type is string.  If this cannot convert to the desitnation type, this will
        ///      throw a NotSupportedException.
        /// </summary>
        /// <param name='context'>An ITypeDescriptorContext that provides a format context.</param>
        /// <param name='culture'>A CultureInfo object. If a null reference (Nothing in Visual Basic) is passed, the current culture is assumed.</param>
        /// <param name='value'>The Object to convert.</param>
        /// <param name='destinationType'>The Type to convert the value parameter to.</param>
        /// <returns>An Object that represents the converted value.</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
        {
 
            if (destinationType == null) 
            {
                throw new ArgumentNullException("destinationType");
            }
 
            if (value is ManagementPath && destinationType == typeof(InstanceDescriptor)) 
            {
                ManagementPath obj = ((ManagementPath)(value));
                ConstructorInfo ctor = typeof(ManagementPath).GetConstructor(new Type[] {typeof(System.String)});
                if (ctor != null) 
                {
                    return new InstanceDescriptor(ctor, new object[] {obj.Path});
                }
            }
            return base.ConvertTo(context,culture,value,destinationType);
        }
    }
}