ManagementQuery.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Wmi / managed / System / Management / ManagementQuery.cs / 1305376 / ManagementQuery.cs

                            using System; 
using System.Collections.Specialized;
using WbemUtilities_v1;
using WbemClient_v1;
using System.Globalization; 
using System.Reflection;
using System.ComponentModel.Design.Serialization; 
using System.ComponentModel; 
using System.ComponentModel.Design;
 


namespace System.Management
{ 
 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	
	///  
	///     Provides an abstract base class for all management query objects. 
	/// 
 	///  
	///     This class is abstract; only
 	///       derivatives of it are actually used in the API.
 	/// 
	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC// 
 	[TypeConverter(typeof(ManagementQueryConverter ))]
	public abstract class ManagementQuery : ICloneable 
	{ 
		internal const string DEFAULTQUERYLANGUAGE = "WQL";
 		internal static readonly string tokenSelect = "select ";	// Keep trailing space char. 

		//Used when any public property on this object is changed, to signal
 		//to the containing object that it needs to be refreshed.
 		internal event IdentifierChangedEventHandler IdentifierChanged; 

		//Fires IdentifierChanged event 
 		internal void FireIdentifierChanged() 
		{
			if (IdentifierChanged != null) 
				IdentifierChanged(this, null);
 		}

		private string queryLanguage; 
 		private string queryString;
 
 		internal void SetQueryString (string qString) 
		{
 			queryString = qString; 
		}

		//default constructor
		internal ManagementQuery() : this(DEFAULTQUERYLANGUAGE, null) {} 

 		//parameterized constructors 
		internal ManagementQuery(string query) : this(DEFAULTQUERYLANGUAGE, query) {} 
 		internal ManagementQuery(string language, string query)
 		{ 
			QueryLanguage = language;
 			QueryString = query;
		}
 
		/// 
		///  Parses the query string and sets the property values accordingly. 
 		///  
		/// The query string to be parsed.
 		protected internal virtual void ParseQuery (string query) {} 

 		//
		//properties
 		// 
		/// 
		///    Gets or sets the query in text format. 
		///  
 		/// 
		///     If the query object is 
 		///       constructed with no parameters, the property is null until specifically set. If the
 		///       object was constructed with a specified query, the property returns the specified
		///       query string.
 		///  
		public virtual string QueryString
		{ 
			get {return (null != queryString) ? queryString : String.Empty;} 
 			set {
				if (queryString != value) { 
 					ParseQuery (value);	// this may throw
 					queryString = value;
					FireIdentifierChanged ();
 				} 
			}
		} 
 
		/// 
 		///     Gets or sets the query language used in the query 
		///       string, defining the format of the query string.
 		/// 
 		/// 
		///    Can be set to any supported query 
 		///       language. "WQL" is the only value supported intrinsically by WMI.
		///  
		public virtual String QueryLanguage 
		{
 			get {return (null != queryLanguage) ? queryLanguage : String.Empty;} 
			set {
 				if (queryLanguage != value) {
 					queryLanguage = value;
					FireIdentifierChanged (); 
 				}
			} 
		} 

		//ICloneable 
 		/// 
		///    Returns a copy of the object.
 		/// 
 		///  
		///    The cloned object.
 		///  
		public abstract object Clone(); 

		internal static void ParseToken (ref string q, string token, string op, ref bool bTokenFound, ref string tokenValue) 
		{
 			if (bTokenFound)
				throw new ArgumentException (RC.GetString("INVALID_QUERY_DUP_TOKEN"));	// Invalid query - duplicate token
 
 			bTokenFound = true;
 			q = q.Remove (0, token.Length).TrimStart (null); 
 
			// Next character should be the operator if any
 			if (op != null) 
			{
				if (0 != q.IndexOf(op, StringComparison.Ordinal))
					throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query
 
 				// Strip off the op and any leading WS
				q = q.Remove(0, op.Length).TrimStart(null); 
 			} 

 			if (0 == q.Length) 
				throw new ArgumentException (RC.GetString("INVALID_QUERY_NULL_TOKEN"));		// Invalid query - token has no value
 			
			// Next token should be the token value - look for terminating WS
			// or end of string 
			int i;
 			if (-1 == (i = q.IndexOf (' '))) 
				i = q.Length;			// No WS => consume entire string 
 				
 			tokenValue = q.Substring (0, i); 
			q = q.Remove (0, tokenValue.Length).TrimStart(null);
 		}

		internal static void ParseToken (ref string q, string token, ref bool bTokenFound) 
		{
			if (bTokenFound) 
 				throw new ArgumentException (RC.GetString("INVALID_QUERY_DUP_TOKEN"));	// Invalid query - duplicate token 

			bTokenFound = true; 
 			q = q.Remove (0, token.Length).TrimStart (null);
 		}
	
 	}//ManagementQuery 

 
	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	 
	/// 
	///     Represents a management query that returns instances or classes. 
 	/// 
	/// 
 	///    This class or its derivatives are used to specify a
 	///       query in the . Use 
	///       a more specific query class whenever possible.
 	///  
	///  
	///    using System;
	/// using System.Management; 
 	///
	/// // This sample demonstrates creating a query.
 	///
 	/// class Sample_ObjectQuery 
	/// {
 	///     public static int Main(string[] args) 
	///     { 
	///         ObjectQuery objectQuery = new ObjectQuery("select * from Win32_Share");
	///         ManagementObjectSearcher searcher = 
 	///             new ManagementObjectSearcher(objectQuery);
	///         foreach (ManagementObject share in searcher.Get())
 	///         {
 	///             Console.WriteLine("Share = " + share["Name"]); 
	///         }
 	///         return 0; 
	///     } 
	/// }
	///     
 	///    Imports System
	/// Imports System.Management
 	///
 	/// ' This sample demonstrates creating a query. 
	///
 	/// Class Sample_ObjectQuery 
	///     Overloads Public Shared Function Main(args() As String) As Integer 
	///         Dim objectQuery As New ObjectQuery("select * from Win32_Share")
	///         Dim searcher As New ManagementObjectSearcher(objectQuery) 
 	///         Dim share As ManagementObject
	///         For Each share In searcher.Get()
 	///             Console.WriteLine("Share = " & share("Name"))
 	///         Next share 
	///         Return 0
 	///     End Function 
	/// End Class 
	///    
	///  
 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//
	public class ObjectQuery : ManagementQuery
 	{
 		///  
		/// Initializes a new instance of the 
 		/// class. 
		///  
		/// 
		///  Initializes a new instance of the  
 		/// class with no initialized values. This
		/// is the default constructor.
 		/// 
 		public ObjectQuery() : base() {} 
		/// 
 		///  Initializes a new instance of the  
		/// class 
		/// for a specific query string.
		///  
 		/// The string representation of the query.
		public ObjectQuery(string query) : base(query) {}
 		/// 
 		///  Initializes a new instance of the  
		/// class for a specific
 		/// query string and language. 
		///  
		/// The query language in which this query is specified.
		/// The string representation of the query. 
 		public ObjectQuery(string language, string query) : base(language, query) {}

		//ICloneable
 		///  
 		///    Returns a copy of the object.
		///  
 		///  
		///    The cloned object.
		///  
		public override object Clone ()
 		{
			return new ObjectQuery(QueryLanguage, QueryString);
 		} 
 		
	}//ObjectQuery 
 

 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	 
	/// 
	///     Represents a WMI event query.
	/// 
 	///  
	///     Objects of this class or its derivatives are used in
 	///     to subscribe to 
 	///       WMI events. Use more specific derivatives of this class whenever possible. 
	/// 
 	///  
	///    using System;
	/// using System.Management;
	///
 	/// // This sample demonstrates how to subscribe to an event 
	/// // using the EventQuery object.
 	/// 
 	/// class Sample_EventQuery 
	/// {
 	///     public static int Main(string[] args) 
	///     {
	///         //For this example, we make sure we have an arbitrary class on root\default
	///         ManagementClass newClass = new ManagementClass(
 	///             "root\\default", 
	///             String.Empty,
 	///             null); 
 	///         newClass["__Class"] = "TestWql"; 
	///         newClass.Put();
 	/// 
	///         //Create a query object for watching for class deletion events
	///         EventQuery eventQuery = new EventQuery("select * from __classdeletionevent");
	///
 	///         //Initialize an event watcher object with this query 
	///         ManagementEventWatcher watcher = new ManagementEventWatcher(
 	///             new ManagementScope("root/default"), 
 	///             eventQuery); 
	///
 	///         //Set up a handler for incoming events 
	///         MyHandler handler = new MyHandler();
	///         watcher.EventArrived += new EventArrivedEventHandler(handler.Arrived);
	///
 	///         //Start watching for events 
	///         watcher.Start();
 	/// 
 	///         //For this example, we delete the class to trigger an event 
	///         newClass.Delete();
 	/// 
	///         //Nothing better to do - we loop to wait for an event to arrive.
	///         while (!handler.IsArrived) {
	///              System.Threading.Thread.Sleep(1000);
 	///         } 
	///
 	///         //In this example we only want to wait for one event, so we can stop watching 
 	///         watcher.Stop(); 
	///
 	///         //Get some values from the event. 
	///         //Note: this can also be done in the event handler.
	///         ManagementBaseObject eventArg =
	///             (ManagementBaseObject)(handler.ReturnedArgs.NewEvent["TargetClass"]);
 	///         Console.WriteLine("Class Deleted = " + eventArg["__CLASS"]); 
	///
 	///         return 0; 
 	///     } 
	///
 	///     public class MyHandler 
	///     {
	///         private bool isArrived = false;
	///         private EventArrivedEventArgs args;
 	/// 
	///         //Handles the event when it arrives
 	///         public void Arrived(object sender, EventArrivedEventArgs e) { 
 	///             args = e; 
	///             isArrived = true;
 	///         } 
	///
	///         //Public property to get at the event information stored in the handler
	///         public EventArrivedEventArgs ReturnedArgs {
 	///             get { 
	///                 return args;
 	///             } 
 	///         } 
	///
 	///         //Used to determine whether the event has arrived or not. 
	///         public bool IsArrived {
	///             get {
	///                 return isArrived;
 	///             } 
	///         }
 	///     } 
 	/// } 
	///    
 	///    Imports System 
	/// Imports System.Management
	///
	/// ' This sample demonstrates how to subscribe an event
 	/// ' using the EventQuery object. 
	///
 	/// Class Sample_EventQuery 
 	///     Public Shared Sub Main() 
	///
 	///         'For this example, we make sure we have an arbitrary class on root\default 
	///         Dim newClass As New ManagementClass( _
	///             "root\default", _
	///             String.Empty, Nothing)
 	///             newClass("__Class") = "TestWql" 
	///             newClass.Put()
 	/// 
 	///         'Create a query object for watching for class deletion events 
	///         Dim eventQuery As New EventQuery("select * from __classdeletionevent")
 	/// 
	///         'Initialize an event watcher object with this query
	///         Dim watcher As New ManagementEventWatcher( _
	///             New ManagementScope("root/default"), _
 	///             eventQuery) 
	///
 	///         'Set up a handler for incoming events 
 	///         Dim handler As New MyHandler() 
	///         AddHandler watcher.EventArrived, AddressOf handler.Arrived
 	/// 
	///         'Start watching for events
	///         watcher.Start()
	///
 	///         'For this example, we delete the class to trigger an event 
	///         newClass.Delete()
 	/// 
 	///         'Nothing better to do - we loop to wait for an event to arrive. 
	///         While Not handler.IsArrived
 	///             Console.Write("0") 
	///             System.Threading.Thread.Sleep(1000)
	///         End While
	///
 	///         'In this example we only want to wait for one event, so we can stop watching 
	///         watcher.Stop()
 	/// 
 	///         'Get some values from the event 
	///         'Note: this can also be done in the event handler.
 	///         Dim eventArg As ManagementBaseObject = CType( _ 
	///             handler.ReturnedArgs.NewEvent("TargetClass"), _
	///             ManagementBaseObject)
	///         Console.WriteLine(("Class Deleted = " + eventArg("__CLASS")))
 	/// 
	///     End Sub
 	/// 
 	///     Public Class MyHandler 
	///         Private _isArrived As Boolean = False
 	///         Private args As EventArrivedEventArgs 
	///
	///         'Handles the event when it arrives
	///         Public Sub Arrived(sender As Object, e As EventArrivedEventArgs)
 	///             args = e 
	///             _isArrived = True
 	///         End Sub 
 	/// 
	///         'Public property to get at the event information stored in the handler
 	///         Public ReadOnly Property ReturnedArgs() As EventArrivedEventArgs 
	///             Get
	///                 Return args
	///             End Get
 	///         End Property 
	///
 	///         'Used to determine whether the event has arrived or not. 
 	///         Public ReadOnly Property IsArrived() As Boolean 
	///             Get
 	///                 Return _isArrived 
	///             End Get
	///         End Property
	///     End Class
 	/// End Class 
	///    
 	///  
 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC// 
	public class EventQuery : ManagementQuery
 	{ 
		/// 
		/// Initializes a new instance of the 
		/// class.
 		///  
		/// 
 		/// Initializes a new instance of the  
 		/// class. This is the 
		/// default constructor.
 		///  
		public EventQuery() : base() {}
		/// 
		///  Initializes a new instance of the 
 		/// class for the specified query. 
		/// 
 		/// A textual representation of the event query. 
 		public EventQuery(string query) : base(query) {} 
		/// 
 		///  Initializes a new instance of the  
		/// class for the specified
		/// language and query.
		/// 
 		/// The language in which the query string is specified.  
		/// The string representation of the query.
 		public EventQuery(string language, string query) : base(language, query) {} 
 
 		//ICloneable
		///  
 		///    Returns a copy of the object.
		/// 
		/// 
		///    The cloned object. 
 		/// 
		public override object Clone() 
 		{ 
 			return new EventQuery(QueryLanguage, QueryString);
		} 
 	}//EventQuery


	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	 
	/// 
	///     Represents a WMI data query in WQL format. 
 	///  
	/// 
 	///    using System; 
 	/// using System.Management;
	///
 	/// // This sample demonstrates how to use a WqlObjectQuery class to
	/// // perform an object query. 
	///
	/// class Sample_WqlObjectQuery 
 	/// { 
	///     public static int Main(string[] args) {
 	///         WqlObjectQuery objectQuery = new WqlObjectQuery("select * from Win32_Share"); 
 	///         ManagementObjectSearcher searcher =
	///             new ManagementObjectSearcher(objectQuery);
 	///
	///         foreach (ManagementObject share in searcher.Get()) { 
	///             Console.WriteLine("Share = " + share["Name"]);
	///         } 
 	/// 
	///         return 0;
 	///     } 
 	/// }
	///    
 	///    Imports System
	/// Imports System.Management 
	///
	/// ' This sample demonstrate how to use a WqlObjectQuery class to 
 	/// ' perform an object query. 
	///
 	/// Class Sample_WqlObjectQuery 
 	///     Overloads Public Shared Function Main(args() As String) As Integer
	///         Dim objectQuery As New WqlObjectQuery("select * from Win32_Share")
 	///         Dim searcher As New ManagementObjectSearcher(objectQuery)
	/// 
	///         Dim share As ManagementObject
	///         For Each share In searcher.Get() 
 	///             Console.WriteLine("Share = " & share("Name")) 
	///         Next share
 	/// 
 	///         Return 0
	///     End Function
 	/// End Class
	///     
	/// 
	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC// 
 	public class WqlObjectQuery : ObjectQuery 
	{
 		//constructors 
 		//Here we don't take a language argument but hard-code it to WQL in the base class
		/// 
 		/// Initializes a new instance of the  class.
		///  
		/// 
		/// Initializes a new instance of the  class. This is the 
 		///    default constructor. 
		/// 
 		public WqlObjectQuery() : base(null) {} 
 	
		/// 
 		///  Initializes a new instance of the  class initialized to the
		///    specified query. 
		/// 
		///  The representation of the data query. 
 		public WqlObjectQuery(string query) : base(query) {} 

		//QueryLanguage property is read-only in this class (does this work ??) 
 		/// 
 		///    Gets or sets the language of the query.
		/// 
 		///  
		///     The value of this
		///       property is always "WQL". 
		///  
 		public override string QueryLanguage
		{ 
 			get
 			{return base.QueryLanguage;}
		}
 
 		//ICloneable
		///  
		///    Creates a copy of the object. 
		/// 
 		///  
		///    The copied object.
 		/// 
 		public override object Clone()
		{ 
 			return new WqlObjectQuery(QueryString);
		} 
 

	}//WqlObjectQuery 



	 
 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	
	///  
 	///     Represents a WQL SELECT data query. 
 	/// 
	///  
 	///    using System;
	/// using System.Management;
	///
	/// // This sample demonstrates how to perform a WQL select query. 
 	///
	/// class Sample_SelectQuery 
 	/// { 
 	///     public static int Main(string[] args) {
	///         SelectQuery selectQuery = new SelectQuery("win32_logicaldisk"); 
 	///         ManagementObjectSearcher searcher =
	///             new ManagementObjectSearcher(selectQuery);
	///
	///         foreach (ManagementObject disk in searcher.Get()) { 
 	///             Console.WriteLine(disk.ToString());
	///         } 
 	///         return 0; 
 	///     }
	/// } 
 	///    
	///    Imports System
	/// Imports System.Management
	/// 
 	/// ' This sample demonstrates how to perform a WQL select query.
	/// 
 	/// Class Sample_SelectQuery 
 	///     Overloads Public Shared Function Main(args() As String) As Integer
	///         Dim selectQuery As New SelectQuery("win32_logicaldisk") 
 	///         Dim searcher As New ManagementObjectSearcher(selectQuery)
	///
	///         Dim disk As ManagementObject
	///         For Each disk In  searcher.Get() 
 	///             Console.WriteLine(disk.ToString())
	///         Next disk 
 	/// 
 	///         Return 0
	///     End Function 
 	/// End Class
	///    
	/// 
	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC// 
 	public class SelectQuery : WqlObjectQuery
	{ 
 		private bool isSchemaQuery = false; 
 		private string className;
		private string condition; 
 		private StringCollection selectedProperties;

		//default constructor
		///  
		/// Initializes a new instance of the 
 		/// class. 
		///  
 		/// 
 		/// Initializes a new instance of the  
		/// class. This is the
 		/// default constructor.
		/// 
		public SelectQuery() :this(null) {} 
		
 		//parameterized constructors 
		//ISSUE : We have 2 possible constructors that take a single string : 
 		//  one that takes the full query string and the other that takes the class name.
 		//  We resolve this by trying to parse the string, if it succeeds we assume it's the query, if 
		//  not we assume it's the class name.
 		/// 
		/// Initializes a new instance of the  class for the specified
		///    query or the specified class name. 
		/// 
 		/// The entire query or the class name to use in the query. The parser in this class attempts to parse the string as a valid WQL SELECT query. If the parser is unsuccessful, it assumes the string is a class name. 
		///  
 		///    SelectQuery s = new SelectQuery("SELECT * FROM Win32_Service WHERE State='Stopped');
 		/// 
		/// or
 		///
		/// //This is equivalent to "SELECT * FROM Win32_Service"
		/// SelectQuery s = new SelectQuery("Win32_Service"); 
		///    
 		///    Dim s As New SelectQuery("SELECT * FROM Win32_Service WHERE State='Stopped') 
		/// 
 		/// or
 		/// 
		/// //This is equivalent to "SELECT * FROM Win32_Service"
 		/// Dim s As New SelectQuery("Win32_Service")
		///    
		///  
		public SelectQuery(string queryOrClassName)
 		{ 
			selectedProperties = new StringCollection (); 

 			if (null != queryOrClassName) 
 			{
				// Minimally determine if the string is a query or class name.
 				//
				if (queryOrClassName.TrimStart().StartsWith(tokenSelect, StringComparison.OrdinalIgnoreCase)) 
				{
					// Looks to be a query - do further checking. 
 					// 
					QueryString = queryOrClassName;		// Parse/validate; may throw.
 				} 
 				else
				{
 					// Do some basic sanity checking on whether it's a class name
					// 

					ManagementPath p = new ManagementPath (queryOrClassName); 
 
					if (p.IsClass && (p.NamespacePath.Length==0))
 						ClassName = queryOrClassName; 
					else
 						throw new ArgumentException (RC.GetString("INVALID_QUERY"),"queryOrClassName");

 				} 
			}
 		} 
 
		/// 
		///  Initializes a new instance of the  
		/// class with the specified
 		/// class name and condition.
		/// 
 		/// The name of the class to select in the query. 
 		/// The condition to be applied in the query.
		///  
 		///    SelectQuery s = new SelectQuery("Win32_Process", "HandleID=1234"); 
		///    
		///    Dim s As New SelectQuery("Win32_Process", "HandleID=1234") 
		///    
 		/// 
		public SelectQuery(string className, string condition) : this(className, condition, null) {}
 
 		/// 
 		///  Initializes a new instance of the  
		/// class with the specified 
 		/// class name and condition, selecting only the specified properties.
		///  
		/// The name of the class from which to select.
		/// The condition to be applied to instances of the selected class.
 		/// An array of property names to be returned in the query results.
		///  
 		///    String[] properties = {"VariableName", "VariableValue"};
 		/// 
		/// SelectQuery s = new SelectQuery("Win32_Environment", 
 		///                                 "User='<system>'",
		///                                 properties); 
		///    
		///    Dim properties As String[] = {"VariableName", "VariableValue"}
 		///
		/// Dim s As New SelectQuery("Win32_Environment", _ 
 		///                          "User=""<system>""", _
 		///                          properties) 
		///     
 		/// 
		public SelectQuery(string className, string condition, string[] selectedProperties) : base () 
		{
			this.isSchemaQuery = false;
 			this.className = className;
			this.condition = condition; 
 			this.selectedProperties = new StringCollection ();
 
 			if (null != selectedProperties) 
				this.selectedProperties.AddRange (selectedProperties);
 
 			BuildQuery();
		}

		///  
		/// Initializes a new instance of the 
 		/// class for a schema query, optionally specifying a condition. For schema queries, 
		/// only the  parameter is valid:  
 		/// and 
 		/// are not supported and are ignored. 
		/// 
 		/// to indicate that this is a schema query; otherwise, . A  value is invalid in this constructor.
		/// The condition to be applied to form the result set of classes.
		///  
		///    SelectQuery s = new SelectQuery(true, "__CLASS = 'Win32_Service'");
 		///     
		///    Dim s As New SelectQuery(true, "__CLASS = ""Win32_Service""") 
 		///    
 		///  
		public SelectQuery(bool isSchemaQuery, string condition) : base ()
 		{
			if (isSchemaQuery == false)
				throw new ArgumentException(RC.GetString("INVALID_QUERY"), "isSchemaQuery"); 
			
 			this.isSchemaQuery = true; 
			this.className = null; 
 			this.condition = condition;
 			this.selectedProperties = null; 

			BuildQuery();
 		}
		 
		
		///  
 		/// Gets or sets the query in the , in string form. 
		/// 
 		///  
 		///    A string representing the query.
		/// 
 		/// 
		///     Setting this 
		///       property value overrides any previous value stored in the object. In addition, setting this
		///       property causes the other members of the object to be updated when the string 
 		///       is reparsed. 
		/// 
 		///  
 		///    SelectQuery s = new SelectQuery();
		/// s.QueryString = "SELECT * FROM Win32_LogicalDisk";
 		///    
		///    Dim s As New SelectQuery() 
		/// s.QueryString = "SELECT * FROM Win32_LogicalDisk"
		///     
 		///  
		public override string QueryString
 		{ 
 			get {
				// We need to force a rebuild as we may not have detected
 				// a change to selected properties
				BuildQuery (); 
				return base.QueryString;}
			set { 
 				base.QueryString = value; 
			}
 		} 

 		/// 
		///    Gets or sets a value indicating whether this query is a schema query or an instances query.
 		///  
		/// 
		///  if this query 
		///    should be evaluated over the schema;  if the query should 
 		///    be evaluated over instances.
		///  
 		/// 
 		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is
 		///       rebuilt to reflect the new query type. 
		/// 
		public bool IsSchemaQuery 
		{ 
 			get
			{ return isSchemaQuery; } 
 			set
 			{ isSchemaQuery = value; BuildQuery(); FireIdentifierChanged(); }
		}
 

 		///  
		///    Gets or sets the class name to be selected from in the query. 
		/// 
		///  
 		///    A string representing the name of the
		///       class.
 		/// 
 		///  
		///     Setting this property value
 		///       overrides any previous value stored in the object. The query string is 
		///       rebuilt to reflect the new class name. 
		/// 
		///  
 		///    SelectQuery s = new SelectQuery("SELECT * FROM Win32_LogicalDisk");
		/// Console.WriteLine(s.QueryString); //output is : SELECT * FROM Win32_LogicalDisk
 		///
 		/// s.ClassName = "Win32_Process"; 
		/// Console.WriteLine(s.QueryString); //output is : SELECT * FROM Win32_Process
 		///     
		///    Dim s As New SelectQuery("SELECT * FROM Win32_LogicalDisk") 
		/// Console.WriteLine(s.QueryString)  'output is : SELECT * FROM Win32_LogicalDisk
		/// 
 		/// s.ClassName = "Win32_Process"
		/// Console.WriteLine(s.QueryString)  'output is : SELECT * FROM Win32_Process
 		///    
 		///  
		public string ClassName
 		{ 
			get { return (null != className) ? className : String.Empty; } 
			set { className = value; BuildQuery(); FireIdentifierChanged(); }
		} 

 		/// 
		///    Gets or sets the condition to be applied in the SELECT
 		///       query. 
 		/// 
		///  
 		///    A string containing the condition to 
		///    be applied in the SELECT query.
		///  
		/// 
 		///     Setting this property value overrides any previous value
		///       stored in the object. The query string is rebuilt to reflect the new
 		///       condition. 
 		/// 
		public string Condition 
 		{ 
			get { return (null != condition) ? condition : String.Empty; }
			set { condition = value; BuildQuery(); FireIdentifierChanged(); } 
		}

 		/// 
		///     Gets or sets an array of property names to be 
 		///       selected in the query.
 		///  
		///  
 		/// A  containing the names of the
		///    properties to be selected in the query. 
		/// 
		/// 
 		///     Setting this property value overrides any previous value stored
		///       in the object. The query string is rebuilt to reflect the new 
 		///       properties.
 		///  
		public StringCollection SelectedProperties 
 		{
			get { return selectedProperties; } 
			set {
				if (null != value)
 				{
					// A tad painful since StringCollection doesn't support ICloneable 
 					StringCollection src = (StringCollection)value;
 					StringCollection dst = new StringCollection (); 
 
					foreach (String s in src)
 						dst.Add (s); 
						
					selectedProperties = dst;
				}
 				else 
					selectedProperties = new StringCollection ();
 
 				BuildQuery(); 
 				FireIdentifierChanged();
			} 
 		}

		/// 
		///  Builds the query string according to the current property values. 
		/// 
 		protected internal void BuildQuery() 
		{ 
 			string s;
 
 			if (isSchemaQuery == false) //this is an instances query
			{
 				//If the class name is not set we can't build a query
				//Shouldn't throw here because the user may be in the process of filling in the properties... 
				if (className == null)
					SetQueryString (String.Empty); 
 
 				if ((className == null) || (className.Length==0))
					return; 

 				//Select clause
 				s = tokenSelect;
 
				//If properties are specified list them
 				if ((null != selectedProperties) && (0 < selectedProperties.Count)) 
				{ 
					int count = selectedProperties.Count;
 
					for (int i = 0; i < count; i++)
 						s = s + selectedProperties[i] + ((i == (count - 1)) ? " " : ",");
				}
 				else 
 					s = s + "* ";
 
				//From clause 
 				s = s + "from " + className;
 
			}
			else //this is a schema query, ignore className or selectedProperties.
			{
 				//Select clause 
				s = "select * from meta_class";
 			} 
 
 			//Where clause
			if ((Condition != null) && (Condition.Length != 0)) 
 				s = s + " where " + condition;

			//Set the queryString member to the built query (NB: note we set
			//by accessing the internal helper function rather than the property, 
			//since we do not want to force a parse of a query we just built).
 			SetQueryString (s); 
		} 

 
 		/// 
 		///  Parses the query string and sets the property values accordingly.
		/// 
 		/// The query string to be parsed. 
		protected internal override void ParseQuery(string query)
		{ 
			//Clear out previous property values 
 			className = null;
			condition = null; 
 			if (selectedProperties != null)
 				selectedProperties.Clear();

			//Trim whitespaces 
 			string q = query.Trim();
			bool bFound = false; string tempProp; int i; 
 
			if (isSchemaQuery == false) //instances query
			{ 
 				//Find "select" clause and get the property list if exists
				string keyword = tokenSelect;
 				if ((q.Length >= keyword.Length) && (String.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase) == 0)) //select clause found
 				{ 
					ParseToken (ref q, keyword, ref bFound);
 					if (q[0] != '*') //we have properties 
					{ 
						if (null != selectedProperties)
							selectedProperties.Clear (); 
 						else
							selectedProperties = new StringCollection ();

 						//get the property list 
 						while (true)
						{ 
 							if ((i = q.IndexOf(',')) > 0) 
							{
								tempProp = q.Substring(0, i); 
								q = q.Remove(0, i+1).TrimStart(null);
 								tempProp = tempProp.Trim();
								if (tempProp.Length>0)
 									selectedProperties.Add(tempProp); 
 							}
							else 
 							{ //last property in the list 
								if ((i = q.IndexOf(' ')) > 0)
								{ 
									tempProp = q.Substring(0, i);
 									q = q.Remove(0, i).TrimStart(null);
									selectedProperties.Add(tempProp);
 									break; 
 								}
								else //bad query 
 									throw new ArgumentException(RC.GetString("INVALID_QUERY")); 
							}
						} //while 
					}
 					else
						q = q.Remove(0, 1).TrimStart(null);
 				} 
 				else //select clause has to be there, otherwise the parsing fails
					throw new ArgumentException(RC.GetString("INVALID_QUERY")); 
 
 				//Find "from" clause, get the class name and remove the clause
				keyword = "from "; bFound = false; 
				if ((q.Length >= keyword.Length) && (String.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase) == 0)) //from clause found
					ParseToken(ref q, keyword, null, ref bFound, ref className);
 				else //from clause has to be there, otherwise the parsing fails
					throw new ArgumentException(RC.GetString("INVALID_QUERY")); 

 				//Find "where" clause, get the condition out and remove the clause 
 				keyword = "where "; 
				if ((q.Length >= keyword.Length) && (String.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase) == 0)) //where clause exists
 				{ 
					condition = q.Substring(keyword.Length).Trim();
				}
			} //if isSchemaQuery == false
 			else //this is a schema query 
			{
 				//Find "select" clause and make sure it's the right syntax 
 				string keyword = "select"; 

				// Should start with "select" 
 				if ((q.Length < keyword.Length) ||
					(0 != String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase)))
					throw new ArgumentException (RC.GetString("INVALID_QUERY"),"select");
 
				q = q.Remove (0, keyword.Length).TrimStart (null);
 
 				// Next should be a '*' 
				if (0 != q.IndexOf ('*', 0))
 					throw new ArgumentException (RC.GetString("INVALID_QUERY"),"*"); 

 				q = q.Remove (0, 1).TrimStart (null);

				// Next should be "from" 
 				keyword = "from";
 
				if ((q.Length < keyword.Length) || 
					(0 != String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase)))
					throw new ArgumentException (RC.GetString("INVALID_QUERY"),"from"); 

 				q = q.Remove (0, keyword.Length).TrimStart (null);

				// Next should be "meta_class" 
 				keyword = "meta_class";
 
 				if ((q.Length < keyword.Length) || 
					(0 != String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase)))
 					throw new ArgumentException (RC.GetString("INVALID_QUERY"),"meta_class"); 

				q = q.Remove (0, keyword.Length).TrimStart (null);

				// There may be a where clause 
				if (0 < q.Length)
 				{ 
					//Find "where" clause, and get the condition out 
 					keyword = "where";
 				 
					if ((q.Length < keyword.Length) ||
 						(0 != String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase)))
						throw new ArgumentException (RC.GetString("INVALID_QUERY"),"where");
 
					q = q.Remove (0, keyword.Length);
 
					// Must be some white space next 
 					if ((0 == q.Length) || !Char.IsWhiteSpace (q[0]))
						throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 
 				
 					q = q.TrimStart(null);	// Remove the leading whitespace

					condition = q; 
 				}
				else 
					condition = String.Empty; 

				//Empty not-applicable properties 
 				className = null;
				selectedProperties = null;
 			}//schema query
 		} 

		///  
 		///     Creates a copy of the object. 
		/// 
		///  
		///    The copied object.
 		/// 
		public override Object Clone ()
 		{ 
 			string[] strArray = null;
 
			if (null != selectedProperties) 
 			{
				int count = selectedProperties.Count; 

				if (0 < count)
				{
 					strArray = new String [count]; 
					selectedProperties.CopyTo (strArray, 0);
 				} 
 			} 

			if (isSchemaQuery == false) 
 				return new SelectQuery(className, condition, strArray);
			else
				return new SelectQuery(true, condition);
		} 

 	}//SelectQuery 
 
	
 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	 
 	/// 
	///     Represents a WQL ASSOCIATORS OF data query.
 	///       It can be used for both instances and schema queries.
	///  
	/// 
	///    using System; 
 	/// using System.Management; 
	///
 	/// // This sample demonstrates how to query all instances associated 
 	/// // with Win32_LogicalDisk='C:'.
	///
 	/// class Sample_RelatedObjectQuery
	/// { 
	///     public static int Main(string[] args) {
	/// 
 	///         //This query requests all objects related to the 'C:' drive. 
	///         RelatedObjectQuery relatedQuery =
 	///             new RelatedObjectQuery("win32_logicaldisk='c:'"); 
 	///         ManagementObjectSearcher searcher =
	///             new ManagementObjectSearcher(relatedQuery);
 	///
	///         foreach (ManagementObject relatedObject in searcher.Get()) { 
	///             Console.WriteLine(relatedObject.ToString());
	///         } 
 	/// 
	///         return 0;
 	///     } 
 	/// }
	///    
 	///    Imports System
	/// Imports System.Management 
	///
	/// ' This sample demonstrates how to query all instances associated 
 	/// ' with Win32_LogicalDisk='C:'. 
	///
 	/// Class Sample_RelatedObjectQuery 
 	///     Overloads Public Shared Function Main(args() As String) As Integer
	///
 	///         'This query requests all objects related to the 'C:' drive.
	///         Dim relatedQuery As New RelatedObjectQuery("win32_logicaldisk='c:'") 
	///         Dim searcher As New ManagementObjectSearcher(relatedQuery)
	/// 
 	///         Dim relatedObject As ManagementObject 
	///         For Each relatedObject In  searcher.Get()
 	///             Console.WriteLine(relatedObject.ToString()) 
 	///         Next relatedObject
	///
 	///         Return 0
	///     End Function 
	/// End Class
	///     
 	///  
	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//
 	public class RelatedObjectQuery : WqlObjectQuery 
 	{
		private static readonly string tokenAssociators = "associators";
 		private static readonly string tokenOf = "of";
		private static readonly string tokenWhere = "where"; 
		private static readonly string tokenResultClass = "resultclass";
		private static readonly string tokenAssocClass = "assocclass"; 
 		private static readonly string tokenResultRole = "resultrole"; 
		private static readonly string tokenRole = "role";
 		private static readonly string tokenRequiredQualifier = "requiredqualifier"; 
 		private static readonly string tokenRequiredAssocQualifier = "requiredassocqualifier";
		private static readonly string tokenClassDefsOnly = "classdefsonly";
 		private static readonly string tokenSchemaOnly = "schemaonly";
 
		private bool isSchemaQuery;
		private string sourceObject; 
		private string relatedClass; 
 		private string relationshipClass;
		private string relatedQualifier; 
 		private string relationshipQualifier;
 		private string relatedRole;
		private string thisRole;
 		private bool classDefinitionsOnly; 

		 
		//default constructor 
		/// 
 		///    Initializes a new instance 
		///    of the  class.
 		/// 
 		/// 
		/// Initializes a new instance of the  class. This is the 
 		///    default constructor.
		///  
		public RelatedObjectQuery() :this(null) {} 
		
 		//parameterized constructor 
		//ISSUE : We have 2 possible constructors that take a single string :
 		//  one that takes the full query string and the other that takes the source object path.
 		//  We resolve this by trying to parse the string, if it succeeds we assume it's the query, if
		//  not we assume it's the source object. 
 		/// 
		/// Initializes a new instance of the class. If the specified string can be succesfully parsed as 
		///    a WQL query, it is considered to be the query string; otherwise, it is assumed to be the path of the source 
		///    object for the query. In this case, the query is assumed to be an instance query. 
 		///  
		/// The query string or the path of the source object.
 		/// 
 		///    //This query retrieves all objects related to the 'mymachine' computer system
		/// //It specifies the full query string in the constructor 
 		/// RelatedObjectQuery q =
		///     new RelatedObjectQuery("associators of {Win32_ComputerSystem.Name='mymachine'}"); 
		/// 
		/// //or
 		/// 
		/// //This query retrieves all objects related to the 'Alerter' service
 		/// //It specifies only the object of interest in the constructor
 		/// RelatedObjectQuery q =
		///     new RelatedObjectQuery("Win32_Service.Name='Alerter'"); 
 		///    
		///    'This query retrieves all objects related to the 'mymachine' computer system 
		/// 'It specifies the full query string in the constructor 
		/// Dim q As New RelatedObjectQuery("associators of {Win32_ComputerSystem.Name='mymachine'}")
 		/// 
		/// 'or
 		///
 		/// 'This query retrieves all objects related to the 'Alerter' service
		/// 'It specifies only the object of interest in the constructor 
 		/// Dim q As New RelatedObjectQuery("Win32_Service.Name='Alerter'")
		///     
		///  
		public RelatedObjectQuery(string queryOrSourceObject)
 		{ 
			if (null != queryOrSourceObject)
 			{
 				// Minimally determine if the string is a query or instance name.
				// 
                if (queryOrSourceObject.TrimStart().StartsWith(tokenAssociators, StringComparison.OrdinalIgnoreCase))
                { 
                    // Looks to be a query - do further checking. 
                    //
                    QueryString = queryOrSourceObject;	// Parse/validate; may throw. 
                }
                else
                {
                    // We'd like to treat it as the source object. Is it a valid 
                    // class or instance?
                    // 
                    // Do some basic sanity checking on whether it's a class/instance name 
                    //
 
                    ManagementPath p = new ManagementPath (queryOrSourceObject);

                    if ((p.IsClass || p.IsInstance) && (p.NamespacePath.Length==0))
                    { 
                        SourceObject = queryOrSourceObject;
                        isSchemaQuery = false; 
                    } 
                    else
                        throw new ArgumentException (RC.GetString("INVALID_QUERY"),"queryOrSourceObject"); 
                }
 			}
		}
 
		/// 
		/// Initializes a new instance of the  class for the given source object and related class. 
 		///    The query is assumed to be an instance query (as opposed to a schema query). 
		/// 
 		/// The path of the source object for this query. 
 		/// The related objects class.
		public RelatedObjectQuery(string sourceObject, string relatedClass) : this(sourceObject, relatedClass,
 																					null, null, null, null, null, false) {}
		 
		//Do we need additional variants of constructors here ??
		///  
 		/// Initializes a new instance of the  class for the given set of parameters. 
		///    The query is assumed to be an instance query (as opposed to a schema query).
 		///  
 		/// The path of the source object.
		/// The related objects required class.
 		/// The relationship type.
		/// The qualifier required to be present on the related objects. 
		/// The qualifier required to be present on the relationships.
		/// The role that the related objects are required to play in the relationship. 
 		/// The role that the source object is required to play in the relationship. 
		/// to return only the class definitions of the related objects; otherwise,  .
 		public RelatedObjectQuery(string sourceObject, 
 								   string relatedClass,
							       string relationshipClass,
 								   string relatedQualifier,
								   string relationshipQualifier, 
								   string relatedRole,
								   string thisRole, 
 								   bool classDefinitionsOnly) 
		{
 			this.isSchemaQuery = false; 
 			this.sourceObject = sourceObject;
			this.relatedClass = relatedClass;
 			this.relationshipClass = relationshipClass;
			this.relatedQualifier = relatedQualifier; 
			this.relationshipQualifier = relationshipQualifier;
			this.relatedRole = relatedRole; 
 			this.thisRole = thisRole; 
			this.classDefinitionsOnly = classDefinitionsOnly;
 			BuildQuery(); 

 		}

		///  
 		/// Initializes a new instance of the  class for a schema query using the given set
		///    of parameters. This constructor is used for schema queries only: the first 
		///    parameter must be set to  
		///    .
 		///  
		/// to indicate that this is a schema query; otherwise,  .
 		/// The path of the source class.
 		/// The related objects' required base class.
		/// The relationship type. 
 		/// The qualifier required to be present on the related objects.
		/// The qualifier required to be present on the relationships. 
		/// The role that the related objects are required to play in the relationship. 
		/// The role that the source class is required to play in the relationship.
 		public RelatedObjectQuery(bool isSchemaQuery, 
			string sourceObject,
 			string relatedClass,
 			string relationshipClass,
			string relatedQualifier, 
 			string relationshipQualifier,
			string relatedRole, 
			string thisRole) 
		{
 			if (isSchemaQuery == false) 
				throw new ArgumentException(RC.GetString("INVALID_QUERY"), "isSchemaQuery");

 			this.isSchemaQuery = true;
 			this.sourceObject = sourceObject; 
			this.relatedClass = relatedClass;
 			this.relationshipClass = relationshipClass; 
			this.relatedQualifier = relatedQualifier; 
			this.relationshipQualifier = relationshipQualifier;
			this.relatedRole = relatedRole; 
 			this.thisRole = thisRole;
			this.classDefinitionsOnly = false; //this parameter is not relevant for schema queries.
 			BuildQuery();
 
 		}
 
		///  
 		///    Gets or sets a value indicating whether this is a schema query or an instance query.
		///  
		/// 
		///  if this query
 		///    should be evaluated over the schema;  if the query should
		///    be evaluated over instances. 
 		/// 
 		///  
		///    Setting this property value overrides any 
 		///       previous value stored in the object. The query string is
		///       rebuilt to reflect the new query type. 
		/// 
		public bool IsSchemaQuery
 		{
			get 
 			{ return isSchemaQuery; }
 			set 
			{ isSchemaQuery = value; BuildQuery(); FireIdentifierChanged(); } 
 		}
 
		/// 
		///     Gets or sets the source object to be used for the query. For instance
		///       queries, this is typically an instance path. For schema queries, this is typically a class name.
 		///  
		/// 
 		///    A string representing the path of the 
 		///    object to be used for the query. 
		/// 
 		///  
		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is
		///       rebuilt to reflect the new source object.
 		///  
		public string SourceObject
 		{ 
 			get { return (null != sourceObject) ? sourceObject : String.Empty; } 
			set { sourceObject = value; BuildQuery(); FireIdentifierChanged(); }
 		} 

		/// 
		///    Gets or sets the class of the endpoint objects.
		///  
 		/// 
		///    A string containing the related class 
 		///       name. 
 		/// 
		///  
 		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is
		///       rebuilt to reflect the new related class.
		///  
 		/// 
		///    To find all the Win32 services available on a computer, this property is set 
 		///       to "Win32_Service" :  
 		///    RelatedObjectQuery q = new RelatedObjectQuery("Win32_ComputerSystem='MySystem'");
		/// q.RelatedClass = "Win32_Service"; 
 		///    
		///    Dim q As New RelatedObjectQuery("Win32_ComputerSystem=""MySystem""")
		/// q.RelatedClass = "Win32_Service"
		///     
 		/// 
		public string RelatedClass 
 		{ 
 			get { return (null != relatedClass) ? relatedClass : String.Empty; }
			set { relatedClass = value; BuildQuery(); FireIdentifierChanged(); } 
 		}

		/// 
		///    Gets or sets the type of relationship (association). 
		/// 
 		///  
		///    A string containing the relationship 
 		///       class name.
 		///  
		/// 
 		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is
		///       rebuilt to reflect the new relationship class. 
		/// 
 		///  
		///    For example, for finding all the Win32 services dependent on 
 		///       a service, this property should be set to the "Win32_DependentService" association class: 
 		///    RelatedObjectQuery q = new RelatedObjectQuery("Win32_Service='TCP/IP'"); 
		/// q.RelationshipClass = "Win32_DependentService";
 		///    
		///    Dim q As New RelatedObjectQuery("Win32_Service=""TCP/IP""")
		/// q.RelationshipClass = "Win32_DependentService" 
		///    
 		///  
		public string RelationshipClass 
 		{
 			get { return (null != relationshipClass) ? relationshipClass : String.Empty; } 
			set { relationshipClass = value; BuildQuery(); FireIdentifierChanged(); }
 		}

		///  
		///    Gets or sets a qualifier required to be defined on the related objects.
		///  
 		///  
		///    A string containing the name of the
 		///    qualifier required on the related objects. 
 		/// 
		/// 
 		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is 
		///       rebuilt to reflect the new qualifier.
		///  
 		public string RelatedQualifier 
		{
 			get { return (null != relatedQualifier) ? relatedQualifier : String.Empty; } 
 			set { relatedQualifier = value; BuildQuery(); FireIdentifierChanged(); }
		}

 		///  
		///    Gets or sets a qualifier required to be defined on the relationship objects.
		///  
		///  
 		///    A string containing the name of the qualifier required
		///       on the relationship objects. 
 		/// 
 		/// 
		///    Setting this property value overrides any
 		///       previous value stored in the object. The query string is 
		///       rebuilt to reflect the new qualifier.
		///  
		public string RelationshipQualifier 
 		{
			get { return (null != relationshipQualifier) ? relationshipQualifier : String.Empty; } 
 			set { relationshipQualifier = value; BuildQuery(); FireIdentifierChanged(); }
 		}

		///  
 		///    Gets or sets the role that the related objects returned should be playing in the relationship.
		///  
		///  
		///    A string containing the role of the
 		///       related objects. 
		/// 
 		/// 
 		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is 
 		///       rebuilt to reflect the new role.
		///  
		public string RelatedRole 
		{
 			get { return (null != relatedRole) ? relatedRole : String.Empty; } 
			set { relatedRole = value; BuildQuery(); FireIdentifierChanged(); }
 		}

 		///  
		///    Gets or sets the role that the source object should be playing in the relationship.
 		///  
		///  
		///    A string containing the role of this object.
		///  
 		/// 
		///    Setting this property value overrides any
 		///       previous value stored in the object. The query string is
 		///       rebuilt to reflect the new role. 
		/// 
 		public string ThisRole 
		{ 
			get { return (null != thisRole) ? thisRole : String.Empty; }
			set { thisRole = value; BuildQuery(); FireIdentifierChanged(); } 
 		}

		/// 
 		///    Gets or sets a value indicating that for all instances that adhere to the query, only their class definitions be returned. 
 		///       This parameter is only valid for instance queries.
		///  
 		///  
		///  if the query
		///    requests only class definitions of the result set; otherwise, 
		/// .
 		/// 
		/// 
 		///    Setting this property value overrides any 
 		///       previous value stored in the object. The query string is
		///       rebuilt to reflect the new flag. 
 		///  
		public bool ClassDefinitionsOnly
		{ 
			get { return classDefinitionsOnly; }
 			set { classDefinitionsOnly = value; BuildQuery(); FireIdentifierChanged(); }
		}
 

 		///  
 		///  Builds the query string according to the current property values. 
		/// 
 		protected internal void BuildQuery() 
		{
			//If the source object is not set we can't build a query
			//Shouldn't throw here because the user may be in the process of filling in the properties...
 			if (sourceObject == null) 
				SetQueryString (String.Empty);
 
 			if ((sourceObject == null) || (sourceObject.Length==0)) 
 				return;
 
			//"associators" clause
 			string s = tokenAssociators + " " + tokenOf + " {" + sourceObject + "}";

			//If any of the other parameters are set we need a "where" clause 
			if (!(RelatedClass.Length==0) ||
				!(RelationshipClass.Length==0) || 
 				!(RelatedQualifier.Length==0) || 
				!(RelationshipQualifier.Length==0) ||
 				!(RelatedRole.Length==0) || 
 				!(ThisRole.Length==0) ||
				classDefinitionsOnly ||
 				isSchemaQuery)
			{ 
				s = s + " " + tokenWhere;
 
				//"ResultClass" 
 				if (!(RelatedClass.Length==0))
					s = s + " " + tokenResultClass + " = " + relatedClass; 

 				//"AssocClass"
 				if (!(RelationshipClass.Length==0))
					s = s + " " + tokenAssocClass + " = " + relationshipClass; 

 				//"ResultRole" 
				if (!(RelatedRole.Length==0)) 
					s = s + " " + tokenResultRole + " = " + relatedRole;
 
				//"Role"
 				if (!(ThisRole.Length==0))
					s = s + " " + tokenRole + " = " + thisRole;
 
 				//"RequiredQualifier"
 				if (!(RelatedQualifier.Length==0)) 
					s = s + " " + tokenRequiredQualifier + " = " + relatedQualifier; 

 				//"RequiredAssocQualifier" 
				if (!(RelationshipQualifier.Length==0))
					s = s + " " + tokenRequiredAssocQualifier + " = " + relationshipQualifier;

				//"SchemaOnly" and "ClassDefsOnly" 
 				if (!isSchemaQuery) //this is an instance query - classDefs allowed
				{ 
 					if (classDefinitionsOnly) 
 						s = s + " " + tokenClassDefsOnly;
				} 
 				else //this is a schema query, schemaonly required
					s = s + " " + tokenSchemaOnly;
			}
	 
 			//Set the queryString member to the built query (NB: note we set
			//by accessing the internal helper function rather than the property, 
 			//since we do not want to force a parse of a query we just built). 
 			SetQueryString (s);
 
		}//BuildQuery()


 		///  
		///  Parses the query string and sets the property values accordingly.
		///  
		/// The query string to be parsed. 
 		protected internal override void ParseQuery(string query)
		{ 
 			// Temporary variables to hold token values until we are sure query is valid
 			string tempSourceObject = null;
			string tempRelatedClass = null;
 			string tempRelationshipClass = null; 
			string tempRelatedRole = null;
			string tempThisRole = null; 
			string tempRelatedQualifier = null; 
 			string tempRelationshipQualifier = null;
			bool   tempClassDefsOnly = false; 
 			bool   tempIsSchemaQuery = false;

 			//Trim whitespaces
			string q = query.Trim(); 
 			int i;
 
			//Find "associators" clause 
			if (0 != String.Compare(q, 0, tokenAssociators, 0, tokenAssociators.Length, StringComparison.OrdinalIgnoreCase))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"),"associators");	// Invalid query 
 			
			// Strip off the clause
 			q = q.Remove(0, tokenAssociators.Length);
 
 			// Must be some white space next
			if ((0 == q.Length) || !Char.IsWhiteSpace (q[0])) 
 				throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 
			
			q = q.TrimStart(null);	// Remove the leading whitespace 

			// Next token should be "of"
 			if (0 != String.Compare(q, 0, tokenOf, 0, tokenOf.Length, StringComparison.OrdinalIgnoreCase))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"),"of");	// Invalid query 
 			
 			// Strip off the clause and leading WS 
			q = q.Remove(0, tokenOf.Length).TrimStart (null); 

 			// Next character should be "{" 
			if (0 != q.IndexOf('{'))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query

			// Strip off the "{" and any leading WS 
 			q = q.Remove(0, 1).TrimStart(null);
 
			// Next item should be the source object 
 			if (-1 == (i = q.IndexOf('}')))
 				throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 

			tempSourceObject = q.Substring(0, i).TrimEnd(null);
 			q = q.Remove(0, i+1).TrimStart(null);
				 
			// At this point we may or may not have a "where" clause
			if (0 < q.Length) 
 			{ 
				// Next should be the "where" clause
 				if (0 != String.Compare (q, 0, tokenWhere, 0, tokenWhere.Length, StringComparison.OrdinalIgnoreCase)) 
 					throw new ArgumentException(RC.GetString("INVALID_QUERY"),"where");	// Invalid query
				
 				q = q.Remove (0, tokenWhere.Length);
 
				// Must be some white space next
				if ((0 == q.Length) || !Char.IsWhiteSpace (q[0])) 
					throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 
 				
				q = q.TrimStart(null);	// Remove the leading whitespace 

 				// Remaining tokens can appear in any order
 				bool bResultClassFound = false;
				bool bAssocClassFound = false; 
 				bool bResultRoleFound = false;
				bool bRoleFound = false; 
				bool bRequiredQualifierFound = false; 
				bool bRequiredAssocQualifierFound = false;
 				bool bClassDefsOnlyFound = false; 
				bool bSchemaOnlyFound = false;

 				// Keep looking for tokens until we are done
 				while (true) 
				{
 					if ((q.Length >= tokenResultClass.Length) && (0 == String.Compare (q, 0, tokenResultClass, 0, tokenResultClass.Length, StringComparison.OrdinalIgnoreCase))) 
						ParseToken (ref q, tokenResultClass, "=", ref bResultClassFound, ref tempRelatedClass); 
					else if ((q.Length >= tokenAssocClass.Length) && (0 == String.Compare (q, 0, tokenAssocClass, 0, tokenAssocClass.Length, StringComparison.OrdinalIgnoreCase)))
						ParseToken (ref q, tokenAssocClass, "=", ref bAssocClassFound, ref tempRelationshipClass); 
 					else if ((q.Length >= tokenResultRole.Length) && (0 == String.Compare (q, 0, tokenResultRole, 0, tokenResultRole.Length, StringComparison.OrdinalIgnoreCase)))
						ParseToken (ref q, tokenResultRole, "=", ref bResultRoleFound, ref tempRelatedRole);
 					else if ((q.Length >= tokenRole.Length) && (0 == String.Compare (q, 0, tokenRole, 0, tokenRole.Length, StringComparison.OrdinalIgnoreCase)))
 						ParseToken (ref q, tokenRole, "=", ref bRoleFound, ref tempThisRole); 
					else if ((q.Length >= tokenRequiredQualifier.Length) && (0 == String.Compare (q, 0, tokenRequiredQualifier, 0, tokenRequiredQualifier.Length, StringComparison.OrdinalIgnoreCase)))
 						ParseToken (ref q, tokenRequiredQualifier, "=", ref bRequiredQualifierFound, ref tempRelatedQualifier); 
					else if ((q.Length >= tokenRequiredAssocQualifier.Length) && (0 == String.Compare (q, 0, tokenRequiredAssocQualifier, 0, tokenRequiredAssocQualifier.Length, StringComparison.OrdinalIgnoreCase))) 
						ParseToken (ref q, tokenRequiredAssocQualifier, "=", ref bRequiredAssocQualifierFound, ref tempRelationshipQualifier);
					else if ((q.Length >= tokenSchemaOnly.Length) && (0 == String.Compare (q, 0, tokenSchemaOnly, 0, tokenSchemaOnly.Length, StringComparison.OrdinalIgnoreCase))) 
 					{
						ParseToken (ref q, tokenSchemaOnly, ref bSchemaOnlyFound);
 						tempIsSchemaQuery = true;
 					} 
					else if ((q.Length >= tokenClassDefsOnly.Length) && (0 == String.Compare (q, 0, tokenClassDefsOnly, 0, tokenClassDefsOnly.Length, StringComparison.OrdinalIgnoreCase)))
 					{ 
						ParseToken (ref q, tokenClassDefsOnly, ref bClassDefsOnlyFound); 
						tempClassDefsOnly = true;
					} 
 					else if (0 == q.Length)
						break;		// done
 					else
 						throw new ArgumentException(RC.GetString("INVALID_QUERY"));		// Unrecognized token 
				}
 
 				//Can't have both classDefsOnly and schemaOnly 
				if (bSchemaOnlyFound && bClassDefsOnlyFound)
					throw new ArgumentException(RC.GetString("INVALID_QUERY")); 
			}

 			// Getting here means we parsed successfully. Assign the values.
			sourceObject = tempSourceObject; 
 			relatedClass = tempRelatedClass;
 			relationshipClass = tempRelationshipClass; 
			relatedRole = tempRelatedRole; 
 			thisRole = tempThisRole;
			relatedQualifier = tempRelatedQualifier; 
			relationshipQualifier = tempRelationshipQualifier;
			classDefinitionsOnly = tempClassDefsOnly;
 			isSchemaQuery = tempIsSchemaQuery;
 
		}//ParseQuery()
 
 
 		//ICloneable
 		///  
		///    Creates a copy of the object.
 		/// 
		/// 
		///    The copied object. 
		/// 
 		public override object Clone() 
		{ 
 			if (isSchemaQuery == false)
 				return new RelatedObjectQuery(sourceObject, relatedClass, relationshipClass, 
											relatedQualifier, relationshipQualifier, relatedRole,
 											thisRole, classDefinitionsOnly);
			else
				return new RelatedObjectQuery(true, sourceObject, relatedClass, relationshipClass, 
											relatedQualifier, relationshipQualifier, relatedRole,
 											thisRole); 
				 
 		}
 
 	}//RelatedObjectQuery


	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	 
 	/// 
	///     Represents a WQL REFERENCES OF data query. 
	///  
	/// 
 	///    The following example searches for all objects related to the 
	///       'C:' drive object:
 	///    using System;
 	/// using System.Management;
	/// 
 	/// class Sample_RelationshipQuery
	/// { 
	///     public static int Main(string[] args) { 
	///         RelationshipQuery query =
 	///             new RelationshipQuery("references of {Win32_LogicalDisk.DeviceID='C:'}"); 
	///         ManagementObjectSearcher searcher =
 	///             new ManagementObjectSearcher(query);
 	///
	///         foreach (ManagementObject assoc in searcher.Get()) { 
 	///             Console.WriteLine("Association class = " + assoc["__CLASS"]);
	///         } 
	/// 
	///         return 0;
 	///     } 
	/// }
 	///    
 	///    Imports System
	/// Imports System.Management 
 	///
	/// Class Sample_RelatedObjectQuery 
	///     Overloads Public Shared Function Main(args() As String) As Integer 
	///         Dim query As New RelationshipQuery("references of {Win32_LogicalDisk.DeviceID='C:'}")
 	///         Dim searcher As New ManagementObjectSearcher(query) 
	///         Dim assoc As ManagementObject
 	///
 	///         For Each assoc In searcher.Get()
	///             Console.WriteLine("Association class = " & assoc("__CLASS")) 
 	///         Next assoc
	/// 
	///         Return 0 
	///     End Function
 	/// End Class 
	///    
 	/// 

 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC// 
	public class RelationshipQuery : WqlObjectQuery
 	{ 
		private static readonly string tokenReferences = "references"; 
		private static readonly string tokenOf = "of";
		private static readonly string tokenWhere = "where"; 
 		private static readonly string tokenResultClass = "resultclass";
		private static readonly string tokenRole = "role";
 		private static readonly string tokenRequiredQualifier = "requiredqualifier";
 		private static readonly string tokenClassDefsOnly = "classdefsonly"; 
		private static readonly string tokenSchemaOnly = "schemaonly";
 
 		private string sourceObject; 
		private string relationshipClass;
		private string relationshipQualifier; 
		private string thisRole;
 		private bool classDefinitionsOnly;
		private bool isSchemaQuery;
 		 
 		//default constructor
		///  
 		///    Initializes a new instance 
		///    of the  class.
		///  
		/// 
 		/// Initializes a new instance of the  class. This is the default constructor.
		/// 
 		public RelationshipQuery() :this(null) {} 
 		
		//parameterized constructor 
 		//ISSUE : We have 2 possible constructors that take a single string : 
		//  one that takes the full query string and the other that takes the source object path.
		//  We resolve this by trying to parse the string, if it succeeds we assume it's the query, if 
		//  not we assume it's the source object.
 		/// 
		/// Initializes a new instance of the class. If the specified string can be succesfully parsed as
 		///    a WQL query, it is considered to be the query string; otherwise, it is assumed to be the path of the source 
 		///    object for the query. In this case, the query is assumed to be an instances query. 
		///  
 		/// The query string or the class name for this query. 
		/// 
		///    This example shows the two different ways to use this constructor: 
		///    //Full query string is specified to the constructor
 		/// RelationshipQuery q = new RelationshipQuery("references of {Win32_ComputerSystem.Name='mymachine'}");
		///
 		/// //Only the object of interest is specified to the constructor 
 		/// RelationshipQuery q = new RelationshipQuery("Win32_Service.Name='Alerter'");
		///     
 		///    'Full query string is specified to the constructor 
		/// Dim q As New RelationshipQuery("references of {Win32_ComputerSystem.Name='mymachine'}")
		/// 
		/// 'Only the object of interest is specified to the constructor
 		/// Dim q As New RelationshipQuery("Win32_Service.Name='Alerter'")
		///    
 		///  
 		public RelationshipQuery(string queryOrSourceObject)
		{ 
 			if (null != queryOrSourceObject) 
			{
				// Minimally determine if the string is a query or instance name. 
				//
 				if (queryOrSourceObject.TrimStart().StartsWith(tokenReferences, StringComparison.OrdinalIgnoreCase))
				{
 					// Looks to be a query - do further checking. 
 					//
					QueryString = queryOrSourceObject;	// Parse/validate; may throw. 
 				} 
				else
				{ 
					// We'd like to treat it as the source object. Is it a valid
 					// class or instance?

					// Do some basic sanity checking on whether it's a class/instance name 
 					//
 					ManagementPath p = new ManagementPath (queryOrSourceObject); 
 
					if ((p.IsClass || p.IsInstance) && (p.NamespacePath.Length==0))
 					{ 
						SourceObject = queryOrSourceObject;
						isSchemaQuery = false;
					}
 					else 
						throw new ArgumentException (RC.GetString("INVALID_QUERY"),"queryOrSourceObject");
 
 				} 
 			}
		} 

 		/// 
		/// Initializes a new instance of the  class for the given source object and relationship class.
		///    The query is assumed to be an instance query (as opposed to a schema query). 
		/// 
 		///  The path of the source object for this query. 
		///  The type of relationship for which to query. 
 		public RelationshipQuery(string sourceObject, string relationshipClass) : this(sourceObject, relationshipClass,
 																					    null, null, false) {} 
		//Do we need additional variants of constructors here ??
 		/// 
		/// Initializes a new instance of the  class for the given set of parameters.
		///    The query is assumed to be an instance query (as opposed to a schema query). 
		/// 
 		///  The path of the source object for this query. 
		///  The type of relationship for which to query. 
 		///  A qualifier required to be present on the relationship object.
 		///  The role that the source object is required to play in the relationship. 
		/// When this method returns, it contains a boolean that indicates that only class definitions for the resulting objects are returned.
 		public RelationshipQuery(string sourceObject,
							      string relationshipClass,
								  string relationshipQualifier, 
								  string thisRole,
 								  bool classDefinitionsOnly) 
		{ 
 			this.isSchemaQuery = false;
 			this.sourceObject = sourceObject; 
			this.relationshipClass = relationshipClass;
 			this.relationshipQualifier = relationshipQualifier;
			this.thisRole = thisRole;
			this.classDefinitionsOnly = classDefinitionsOnly; 
			BuildQuery();
 		} 
 
		/// 
 		/// Initializes a new instance of the  class for a schema query using the given set 
 		///    of parameters. This constructor is used for schema queries only, so the first
		///    parameter must be 
 		///    .
		///  
		/// to indicate that this is a schema query; otherwise,  .
		///  The path of the source class for this query. 
 		///  The type of relationship for which to query. 
		///  A qualifier required to be present on the relationship class.
 		///  The role that the source class is required to play in the relationship. 
 		public RelationshipQuery(bool isSchemaQuery,
			string sourceObject,
 			string relationshipClass,
			string relationshipQualifier, 
			string thisRole)
		{ 
 			if (isSchemaQuery == false) 
				throw new ArgumentException(RC.GetString("INVALID_QUERY"), "isSchemaQuery");
 
 			this.isSchemaQuery = true;
 			this.sourceObject = sourceObject;
			this.relationshipClass = relationshipClass;
 			this.relationshipQualifier = relationshipQualifier; 
			this.thisRole = thisRole;
			this.classDefinitionsOnly = false; //this parameter is not relevant for schema queries. 
			BuildQuery(); 

 		} 
		
 		
 		/// 
		///    Gets or sets a value indicating whether this query is a schema query or an instance query. 
 		/// 
		///  
		///  if this query 
		///    should be evaluated over the schema;  if the query should
 		///    be evaluated over instances. 
		/// 
 		/// 
 		///    Setting this property value overrides any
		///       previous value stored in the object. The query string is 
 		///       rebuilt to reflect the new query type.
		///  
		public bool IsSchemaQuery 
		{
 			get 
			{ return isSchemaQuery; }
 			set
 			{ isSchemaQuery = value; BuildQuery(); FireIdentifierChanged(); }
		} 

 		 
		///  
		///    Gets or sets the source object for this query.
		///  
 		/// 
		///    A string representing the path of
 		///    the object to be used for the query.
 		///  
		/// 
 		///    Setting this property value overrides any 
		///       previous value stored in the object. The query string is 
		///       rebuilt to reflect the new source object.
		///  
 		public string SourceObject
		{
 			get { return (null != sourceObject) ? sourceObject : String.Empty; }
 			set { sourceObject = value; BuildQuery(); FireIdentifierChanged(); } 
		}
 
 		///  
		///    Gets or sets the class of the relationship objects wanted in the query.
		///  
		/// 
 		///    A string containing the relationship
		///    class name.
 		///  
 		/// 
		///    Setting this property value overrides any 
 		///       previous value stored in the object. The query string is 
		///       rebuilt to reflect the new class.
		///  
		public string RelationshipClass
 		{
			get { return (null != relationshipClass) ? relationshipClass : String.Empty; }
 			set { relationshipClass = value; BuildQuery(); FireIdentifierChanged(); } 
 		}
 
		///  
 		///    Gets or sets a qualifier required on the relationship objects.
		///  
		/// 
		///    A string containing the name of the
 		///    qualifier required on the relationship objects.
		///  
 		/// 
 		///    Setting this property value overrides any 
		///       previous value stored in the object. The query string is 
 		///       rebuilt to reflect the new qualifier.
		///  
		public string RelationshipQualifier
		{
 			get { return (null != relationshipQualifier) ? relationshipQualifier : String.Empty; }
			set { relationshipQualifier = value; BuildQuery(); FireIdentifierChanged(); } 
 		}
 
 		///  
		///    Gets or sets the role of the source object in the relationship.
 		///  
		/// 
		///    A string containing the role of this
		///    object.
 		///  
		/// 
 		///    Setting this property value overrides any 
 		///       previous value stored in the object. The query string is 
		///       rebuilt to reflect the new role.
 		///  
		public string ThisRole
		{
			get { return (null != thisRole) ? thisRole : String.Empty; }
 			set { thisRole = value; BuildQuery(); FireIdentifierChanged(); } 
		}
 
 		///  
 		///    Gets or sets a value indicating that only the class definitions of the relevant relationship objects be returned.
		///  
 		/// 
		///  if the query requests only class definitions of the
		///    result set; otherwise, .
		///  
 		/// 
		///    Setting this property value overrides any previous 
 		///       value stored in the object. As a side-effect, the query string is 
 		///       rebuilt to reflect the new flag.
		///  
 		public bool ClassDefinitionsOnly
		{
			get { return classDefinitionsOnly; }
			set { classDefinitionsOnly = value; BuildQuery(); FireIdentifierChanged(); } 
 		}
 
 
		/// 
 		///  Builds the query string according to the current property values. 
 		/// 
		protected internal void BuildQuery()
 		{
			//If the source object is not set we can't build a query 
			//Shouldn't throw here because the user may be in the process of filling in the properties...
			if (sourceObject == null) 
 				SetQueryString(String.Empty); 

			if ((sourceObject == null) || (sourceObject.Length==0)) 
 				return;

 			//"references" clause
			string s = tokenReferences + " " + tokenOf + " {" + sourceObject + "}"; 

 			//If any of the other parameters are set we need a "where" clause 
			if (!(RelationshipClass.Length==0) || 
				!(RelationshipQualifier.Length==0) ||
				!(ThisRole.Length==0) || 
 				classDefinitionsOnly ||
				isSchemaQuery)
 			{
 				s = s + " " + tokenWhere; 

				//"ResultClass" 
 				if (!(RelationshipClass.Length==0)) 
					s = s + " " + tokenResultClass + " = " + relationshipClass;
 
				//"Role"
				if (!(ThisRole.Length==0))
 					s = s + " " + tokenRole + " = " + thisRole;
 
				//"RequiredQualifier"
 				if (!(RelationshipQualifier.Length==0)) 
 					s = s + " " + tokenRequiredQualifier + " = " + relationshipQualifier; 

				//"SchemaOnly" and "ClassDefsOnly" 
 				if (!isSchemaQuery) //this is an instance query - classDefs allowed
				{
					if (classDefinitionsOnly)
						s = s + " " + tokenClassDefsOnly; 
 				}
				else //this is a schema query, schemaonly required 
 					s = s + " " + tokenSchemaOnly; 
 				
			} 

 			//Set the queryString member to the built query (NB: note we set
			//by accessing the internal helper function rather than the property,
			//since we do not want to force a parse of a query we just built). 
			SetQueryString (s);
 		} //BuildQuery() 
 
		
 		///  
 		///  Parses the query string and sets the property values accordingly.
		/// 
 		/// The query string to be parsed.
		protected internal override void ParseQuery(string query) 
		{
			// Temporary variables to hold token values until we are sure query is valid 
 			string tempSourceObject = null; 
			string tempRelationshipClass = null;
 			string tempThisRole = null; 
 			string tempRelationshipQualifier = null;
			bool   tempClassDefsOnly = false;
 			bool   tempSchemaOnly = false;
 
			//Trim whitespaces
			string q = query.Trim(); 
			int i; 

 			//Find "references" clause 
			if (0 != String.Compare(q, 0, tokenReferences, 0, tokenReferences.Length, StringComparison.OrdinalIgnoreCase))
 				throw new ArgumentException(RC.GetString("INVALID_QUERY"),"references");	// Invalid query
 			
			// Strip off the clause 
 			q = q.Remove(0, tokenReferences.Length);
 
			// Must be some white space next 
			if ((0 == q.Length) || !Char.IsWhiteSpace (q[0]))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 
 			
			q = q.TrimStart(null);	// Remove the leading whitespace

 			// Next token should be "of" 
 			if (0 != String.Compare(q, 0, tokenOf, 0, tokenOf.Length, StringComparison.OrdinalIgnoreCase))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"),"of");	// Invalid query 
 			 
			// Strip off the clause and leading WS
			q = q.Remove(0, tokenOf.Length).TrimStart (null); 

			// Next character should be "{"
 			if (0 != q.IndexOf('{'))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 

 			// Strip off the "{" and any leading WS 
 			q = q.Remove(0, 1).TrimStart(null); 

			// Next item should be the source object 
 			if (-1 == (i = q.IndexOf('}')))
				throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query

			tempSourceObject = q.Substring(0, i).TrimEnd(null); 
			q = q.Remove(0, i+1).TrimStart(null);
 				 
			// At this point we may or may not have a "where" clause 
 			if (0 < q.Length)
 			{ 
				// Next should be the "where" clause
 				if (0 != String.Compare (q, 0, tokenWhere, 0, tokenWhere.Length, StringComparison.OrdinalIgnoreCase))
					throw new ArgumentException(RC.GetString("INVALID_QUERY"),"where");	// Invalid query
				 
				q = q.Remove (0, tokenWhere.Length);
 
 				// Must be some white space next 
				if ((0 == q.Length) || !Char.IsWhiteSpace (q[0]))
 					throw new ArgumentException(RC.GetString("INVALID_QUERY"));	// Invalid query 
 				
				q = q.TrimStart(null);	// Remove the leading whitespace

 				// Remaining tokens can appear in any order 
				bool bResultClassFound = false;
				bool bRoleFound = false; 
				bool bRequiredQualifierFound = false; 
 				bool bClassDefsOnlyFound = false;
				bool bSchemaOnlyFound = false; 

 				// Keep looking for tokens until we are done
 				while (true)
				{ 
 					if ((q.Length >= tokenResultClass.Length) && (0 == String.Compare (q, 0, tokenResultClass, 0, tokenResultClass.Length, StringComparison.OrdinalIgnoreCase)))
						ParseToken (ref q, tokenResultClass, "=", ref bResultClassFound, ref tempRelationshipClass); 
					else if ((q.Length >= tokenRole.Length) && (0 == String.Compare (q, 0, tokenRole, 0, tokenRole.Length, StringComparison.OrdinalIgnoreCase))) 
						ParseToken (ref q, tokenRole, "=", ref bRoleFound, ref tempThisRole);
 					else if ((q.Length >= tokenRequiredQualifier.Length) && (0 == String.Compare (q, 0, tokenRequiredQualifier, 0, tokenRequiredQualifier.Length, StringComparison.OrdinalIgnoreCase))) 
						ParseToken (ref q, tokenRequiredQualifier, "=", ref bRequiredQualifierFound, ref tempRelationshipQualifier);
 					else if ((q.Length >= tokenClassDefsOnly.Length) && (0 == String.Compare (q, 0, tokenClassDefsOnly, 0, tokenClassDefsOnly.Length, StringComparison.OrdinalIgnoreCase)))
 					{
						ParseToken (ref q, tokenClassDefsOnly, ref bClassDefsOnlyFound); 
 						tempClassDefsOnly = true;
					} 
					else if ((q.Length >= tokenSchemaOnly.Length) && (0 == String.Compare (q, 0, tokenSchemaOnly, 0, tokenSchemaOnly.Length, StringComparison.OrdinalIgnoreCase))) 
					{
 						ParseToken (ref q, tokenSchemaOnly, ref bSchemaOnlyFound); 
						tempSchemaOnly = true;
 					}
 					else if (0 == q.Length)
						break;		// done 
 					else
						throw new ArgumentException(RC.GetString("INVALID_QUERY"));		// Unrecognized token 
				} 

				//Can't have both classDefsOnly and schemaOnly 
 				if (tempClassDefsOnly && tempSchemaOnly)
					throw new ArgumentException(RC.GetString("INVALID_QUERY"));

 			} 

 			// Getting here means we parsed successfully. Assign the values. 
			sourceObject = tempSourceObject; 
 			relationshipClass = tempRelationshipClass;
			thisRole = tempThisRole; 
			relationshipQualifier = tempRelationshipQualifier;
			classDefinitionsOnly = tempClassDefsOnly;
 			isSchemaQuery = tempSchemaOnly;
 
		}//ParseQuery()
 
 
 		//ICloneable
 		///  
		///    Creates a copy of the object.
 		/// 
		/// 
		///    The copied object. 
		/// 
 		public override object Clone() 
		{ 
 			if (isSchemaQuery == false)
 				return new RelationshipQuery(sourceObject, relationshipClass, 
											relationshipQualifier, thisRole, classDefinitionsOnly);
 			else
				return new RelationshipQuery(true, sourceObject, relationshipClass, relationshipQualifier,
											thisRole); 
		}
 
 	}//RelationshipQuery 

 
	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//	
 	/// 
 	///     Represents a WMI event query in WQL format.
	///  
 	/// 
	///    using System; 
	/// using System.Management; 
	///
 	/// // This sample demonstrates how to subscribe to an event 
	/// // using a WQL event query.
 	///
 	/// class Sample_EventQuery
	/// { 
 	///     public static int Main(string[] args)
	///     { 
	///         //For this example, we make sure we have an arbitrary class on root\default 
	///         ManagementClass newClass = new ManagementClass(
 	///             "root\\default", 
	///             String.Empty,
 	///             null);
 	///         newClass["__Class"] = "TestWql";
	///         newClass.Put(); 
 	///
	///         //Create a query object for watching for class deletion events 
	///         WqlEventQuery eventQuery = new WqlEventQuery("select * from __classdeletionevent"); 
	///
 	///         //Initialize an event watcher object with this query 
	///         ManagementEventWatcher watcher = new ManagementEventWatcher(
 	///             new ManagementScope("root/default"),
 	///             eventQuery);
	/// 
 	///         //Set up a handler for incoming events
	///         MyHandler handler = new MyHandler(); 
	///         watcher.EventArrived += new EventArrivedEventHandler(handler.Arrived); 
	///
 	///         //Start watching for events 
	///         watcher.Start();
 	///
 	///         //For this example, we delete the class to trigger an event
	///         newClass.Delete(); 
 	///
	///         //Nothing better to do - we loop to wait for an event to arrive. 
	///         while (!handler.IsArrived) { 
	///              System.Threading.Thread.Sleep(1000);
 	///         } 
	///
 	///         //In this example we only want to wait for one event, so we can stop watching
 	///         watcher.Stop();
	/// 
 	///         return 0;
	///     } 
	/// 
	///     public class MyHandler
 	///     { 
	///         private bool isArrived = false;
 	///
 	///         //Handles the event when it arrives
	///         public void Arrived(object sender, EventArrivedEventArgs e) { 
 	///             ManagementBaseObject eventArg = (ManagementBaseObject)(e.NewEvent["TargetClass"]);
	///             Console.WriteLine("Class Deleted = " + eventArg["__CLASS"]); 
	///             isArrived = true; 
	///         }
 	/// 
	///          //Used to determine whether the event has arrived or not.
 	///         public bool IsArrived {
 	///             get {
	///                 return isArrived; 
 	///             }
	///         } 
	///     } 
	/// }
 	///     
	///    Imports System
 	/// Imports System.Management
 	///
	/// ' This sample demonstrates how to subscribe an event 
 	/// ' using a WQL event query.
	/// 
	/// Class Sample_EventQuery 
	///     Public Shared Sub Main()
 	/// 
	///         'For this example, we make sure we have an arbitrary class on root\default
 	///         Dim newClass As New ManagementClass( _
 	///             "root\default", _
	///             String.Empty, Nothing) 
 	///             newClass("__Class") = "TestWql"
	///             newClass.Put() 
	/// 
	///         'Create a query object for watching for class deletion events
 	///         Dim eventQuery As New WqlEventQuery("select * from __classdeletionevent") 
	///
 	///         'Initialize an event watcher object with this query
 	///         Dim watcher As New ManagementEventWatcher( _
	///             New ManagementScope("root/default"), _ 
 	///             eventQuery)
	/// 
	///         'Set up a handler for incoming events 
	///         Dim handler As New MyHandler()
 	///         AddHandler watcher.EventArrived, AddressOf handler.Arrived 
	///
 	///         'Start watching for events
 	///         watcher.Start()
	/// 
 	///         'For this example, we delete the class to trigger an event
	///         newClass.Delete() 
	/// 
	///         'Nothing better to do - we loop to wait for an event to arrive.
 	///         While Not handler.IsArrived 
	///             Console.Write("0")
 	///             System.Threading.Thread.Sleep(1000)
 	///         End While
	/// 
 	///         'In this example we only want to wait for one event, so we can stop watching
	///         watcher.Stop() 
	/// 
	///     End Sub
 	/// 
	///     Public Class MyHandler
 	///         Private _isArrived As Boolean = False
 	///
	///         'Handles the event when it arrives 
 	///         Public Sub Arrived(sender As Object, e As EventArrivedEventArgs)
	///             Dim eventArg As ManagementBaseObject = CType( _ 
	///                 e.NewEvent("TargetClass"), _ 
	///                 ManagementBaseObject)
 	///             Console.WriteLine(("Class Deleted = " + eventArg("__CLASS"))) 
	///             _isArrived = True
 	///         End Sub
 	///
	///         'Used to determine whether the event has arrived or not. 
 	///         Public ReadOnly Property IsArrived() As Boolean
	///             Get 
	///                 Return _isArrived 
	///             End Get
 	///         End Property 
	///     End Class
 	/// End Class
 	///    
	///  
 	//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC//
	public class WqlEventQuery : EventQuery 
	{ 
		private static readonly string tokenSelectAll = "select * ";
 
 		private string eventClassName;
		private TimeSpan withinInterval;
 		private string condition;
 		private TimeSpan groupWithinInterval; 
		private StringCollection groupByPropertyList;
 		private string havingCondition; 
 
		//default constructor
		///  
		///  Initializes a new instance of the  class.
 		/// 
		/// 
 		/// Initializes a new instance of the  
 		/// class. This is the default
		/// constructor. 
 		///  
		public WqlEventQuery() : this(null, TimeSpan.Zero, null, TimeSpan.Zero, null, null) {}
 
		//parameterized constructors
		//ISSUE : We have 2 possible constructors that take a single string :
 		//  one that takes the full query string and the other that takes the class name.
		//  We resolve this by trying to parse the string, if it succeeds we assume it's the query, if 
 		//  not we assume it's the class name.
 		///  
		///  Initializes a new instance of the  
 		/// class based on the given
		/// query string or event class name. 
		/// 
		/// The string representing either the entire event query or the name of the event class to query. The object will try to parse the string as a valid event query. If unsuccessful, the parser will assume that the parameter represents an event class name.
 		/// 
		///    The two options below are equivalent : 
 		///    //Full query string specified to the constructor
 		/// WqlEventQuery q = new WqlEventQuery("SELECT * FROM MyEvent"); 
		/// 
 		/// //Only relevant event class name specified to the constructor
		/// WqlEventQuery q = new WqlEventQuery("MyEvent"); //results in the same query as above. 
		///    
		///    'Full query string specified to the constructor
 		/// Dim q As New WqlEventQuery("SELECT * FROM MyEvent")
		/// 
 		/// 'Only relevant event class name specified to the constructor
 		/// Dim q As New WqlEventQuery("MyEvent") 'results in the same query as above 
		///     
 		/// 
		public WqlEventQuery(string queryOrEventClassName) 
		{
			groupByPropertyList = new StringCollection();

 			if (null != queryOrEventClassName) 
			{
 				// Minimally determine if the string is a query or event class name. 
 				// 
				if (queryOrEventClassName.TrimStart().StartsWith(tokenSelectAll, StringComparison.OrdinalIgnoreCase))
 				{ 
					QueryString = queryOrEventClassName;	// Parse/validate; may throw.
				}
				else
 				{ 
					// Do some basic sanity checking on whether it's a class name
 					// 
 					ManagementPath p = new ManagementPath (queryOrEventClassName); 

					if (p.IsClass && (p.NamespacePath.Length==0)) 
 					{
						EventClassName = queryOrEventClassName;
					}
					else 
 						throw new ArgumentException (RC.GetString("INVALID_QUERY"),"queryOrEventClassName");
				} 
 			} 
 		}
 
		/// 
 		///  Initializes a new instance of the 
		/// class for the
		/// specified event class name, with the specified condition. 
		/// 
 		/// The name of the event class to query. 
		/// The condition to apply to events of the specified class. 
 		/// 
 		///    This example shows how to create an event query that contains a condition in 
		///       addition to the event class :
 		///    //Requests all "MyEvent" events where the event's properties
		/// //match the specified condition
		/// WqlEventQuery q = new WqlEventQuery("MyEvent", "FirstProp < 20 and SecondProp = 'red'"); 
		///    
 		///    'Requests all "MyEvent" events where the event's properties 
		/// 'match the specified condition 
 		/// Dim q As New WqlEventQuery("MyEvent", "FirstProp < 20 and SecondProp = 'red'")
 		///     
		/// 
 		public WqlEventQuery(string eventClassName, string condition) : this(eventClassName, TimeSpan.Zero, condition, TimeSpan.Zero, null, null) {}

		///  
		///  Initializes a new instance of the 
		/// class for the specified 
 		/// event class, with the specified latency time. 
		/// 
 		/// The name of the event class to query. 
 		/// A timespan value specifying the latency acceptable for receiving this event. This value is used in cases where there is no explicit event provider for the query requested, and WMI is required to poll for the condition. This interval is the maximum amount of time that can pass before notification of an event must be delivered. 
		/// 
 		///    This example shows creating an event query that contains
		///       a 
		///       time interval.
		///    //Requests all instance creation events, with a specified latency of 
 		/// //10 seconds. The query created is "SELECT * FROM __InstanceCreationEvent WITHIN 10" 
		/// WqlEventQuery q = new WqlEventQuery("__InstanceCreationEvent",
 		///                                     new TimeSpan(0,0,10)); 
 		///    
		///    'Requests all instance creation events, with a specified latency of
 		/// '10 seconds. The query created is "SELECT * FROM __InstanceCreationEvent WITHIN 10"
		/// Dim t As New TimeSpan(0,0,10) 
		/// Dim q As New WqlEventQuery("__InstanceCreationEvent", t)
		///     
 		///  
		public WqlEventQuery(string eventClassName, TimeSpan withinInterval):
 										this(eventClassName, withinInterval, null, TimeSpan.Zero, null, null) {} 
 		/// 
		///  Initializes a new instance of the 
 		/// class with the specified
		/// event class name, polling interval, and condition. 
		/// 
		/// The name of the event class to query.  
 		/// A timespan value specifying the latency acceptable for receiving this event. This value is used in cases where there is no explicit event provider for the query requested and WMI is required to poll for the condition. This interval is the maximum amount of time that can pass before notification of an event must be delivered.  
		/// The condition to apply to events of the specified class.
 		///  
 		///     This example creates the event query: "SELECT * FROM
		///    WITHIN 10 WHERE
 		///     ISA ", which means
		///       "send notification of the creation of  
		///       instances,
		///       with a 10-second polling interval." 
 		///    //Requests notification of the creation of Win32_Service instances with a 10 second 
		/// //allowed latency.
 		/// WqlEventQuery q = new WqlEventQuery("__InstanceCreationEvent", 
 		///                                     new TimeSpan(0,0,10),
		///                                     "TargetInstance isa 'Win32_Service'");
 		///    
		///    'Requests notification of the creation of Win32_Service instances with a 10 second 
		/// 'allowed latency.
		/// Dim t As New TimeSpan(0,0,10) 
 		/// Dim q As New WqlEventQuery("__InstanceCreationEvent", _ 
		///                            t, _
 		///                            "TargetInstance isa ""Win32_Service""") 
 		///    
		/// 
 		public WqlEventQuery(string eventClassName, TimeSpan withinInterval, string condition) :
										this(eventClassName, withinInterval, condition, TimeSpan.Zero, null, null) {} 

		///  
		///  Initializes a new instance of the  
 		/// class with the specified
		/// event class name, condition, and grouping interval. 
 		/// 
 		/// The name of the event class to query. 
		/// The condition to apply to events of the specified class.
 		/// The specified interval at which WMI sends one aggregate event, rather than many events. 
		/// 
		///    This example creates the event query: "SELECT * FROM 
		///     WHERE = 5 
 		///       GROUP WITHIN 10", which means "send notification of events of type
		///    , in which the 
 		///     is equal to 5, but send an aggregate event in
 		///       a
		///       10-second interval."
 		///    //Sends an aggregate of the requested events every 10 seconds 
		/// WqlEventQuery q = new WqlEventQuery("FrequentEvent",
		///                                     "InterestingProperty = 5", 
		///                                     new TimeSpan(0,0,10)); 
 		///    
		///    'Sends an aggregate of the requested events every 10 seconds 
 		/// Dim t As New TimeSpan(0,0,10)
 		/// Dim q As New WqlEventQuery("FrequentEvent", _
		///                            "InterestingProperty = 5", _
 		///                            t) 
		///    
		///  
		public WqlEventQuery(string eventClassName, string condition, TimeSpan groupWithinInterval) : 
 										this(eventClassName, TimeSpan.Zero, condition, groupWithinInterval, null, null) {}
 
		/// 
 		///  Initializes a new instance of the 
 		/// class with the specified event class
		/// name, condition, grouping interval, and grouping properties. 
 		/// 
		/// The name of the event class to query.  
		/// The condition to apply to events of the specified class. 
		/// The specified interval at which WMI sends one aggregate event, rather than many events. 
 		/// The properties in the event class by which the events should be grouped. 
		/// 
 		///    This example creates the event query: "SELECT * FROM
 		///     WHERE  = 'MyBoss' GROUP
		///       WITHIN 300 BY ", which means "send notification when 
 		///       new email from a particular sender has arrived within the last 10 minutes,
		///       combined with other events that have the same value in the 
		///     
		///    property."
 		/// //Requests "EmailEvent" events where the Sender property is "MyBoss", and 
		/// //groups them based on importance
 		/// String[] props = {"Importance"};
 		/// WqlEventQuery q = new WqlEventQuery("EmailEvent",
		///                                     "Sender = 'MyBoss'", 
 		///                                     new TimeSpan(0,10,0),
		///                                     props); 
		///  
		/// 'Requests "EmailEvent" events where the Sender property is "MyBoss", and
 		/// 'groups them based on importance 
		/// Dim props() As String = {"Importance"}
 		/// Dim t As New TimeSpan(0,10,0)
 		/// Dim q As New WqlEventQuery("EmailEvent", _
		///                            "Sender = ""MyBoss""", _ 
 		///                            t, _
		///                            props) 
		///  
		/// 
 		public WqlEventQuery(string eventClassName, string condition, TimeSpan groupWithinInterval, string[] groupByPropertyList) : 
			this(eventClassName, TimeSpan.Zero, condition, groupWithinInterval, groupByPropertyList, null) {}

 		/// 
 		///  Initializes a new instance of the  
		/// class with the specified event class
 		/// name, condition, grouping interval, grouping properties, and specified number of events. 
		///  
		/// The name of the event class on which to be queried.
		/// A timespan value specifying the latency acceptable for receiving this event. This value is used in cases where there is no explicit event provider for the query requested, and WMI is required to poll for the condition. This interval is the maximum amount of time that can pass before notification of an event must be delivered. 
 		/// The condition to apply to events of the specified class.
		/// The specified interval at which WMI sends one aggregate event, rather than many events. 
 		/// The properties in the event class by which the events should be grouped.
 		/// The condition to apply to the number of events. 
		/// 
 		///    This example creates the event query: "SELECT * FROM 
		///    WHERE  
		///    ISA GROUP WITHIN 300 BY
		///  HAVING 
 		///  > 15" which means "deliver aggregate events
		///    only if the number of events received from the
 		///    same source exceeds 15."
 		/// //Requests sending aggregated events if the number of events exceeds 15. 
		/// String[] props = {"TargetInstance.SourceName"};
 		/// WqlEventQuery q = new WqlEventQuery("__InstanceCreationEvent", 
		///                                     "TargetInstance isa 'Win32_NTLogEvent'", 
		///                                     new TimeSpan(0,10,0),
		///                                     props, 
 		///                                     "NumberOfEvents >15");
		/// 
 		/// 'Requests sending aggregated events if the number of events exceeds 15.
 		/// Dim props() As String = {"TargetInstance.SourceName"}; 
		/// Dim t As New TimeSpan(0,10,0)
 		/// Dim q As WqlEventQuery("__InstanceCreationEvent", _ 
		///                        "TargetInstance isa ""Win32_NTLogEvent""", _ 
		///                        t, _
		///                        props, _ 
 		///                        "NumberOfEvents >15")
		/// 
 		/// 
 		public WqlEventQuery(string eventClassName, TimeSpan withinInterval, string condition, TimeSpan groupWithinInterval, 
						  string[] groupByPropertyList, string havingCondition)
 		{ 
			this.eventClassName = eventClassName; 
			this.withinInterval = withinInterval;
			this.condition = condition; 
 			this.groupWithinInterval = groupWithinInterval;
			this.groupByPropertyList = new StringCollection ();

 			if (null != groupByPropertyList) 
 				this.groupByPropertyList.AddRange (groupByPropertyList);
			 
 			this.havingCondition = havingCondition; 
			BuildQuery();
		} 

		
 		//QueryLanguage property is read-only in this class (does this work ??)
		///  
 		///    Gets or sets the language of the query.
 		///  
		///  
 		///    The value of this property in this
		///       object is always "WQL". 
		/// 
		public override string QueryLanguage
 		{
			get 
 			{return base.QueryLanguage;}
 		} 
		 
 		/// 
		///    Gets or sets the string representing the query. 
		/// 
		/// 
 		///    A string representing the query.
		///  
 		public override string QueryString
 		{ 
			get 
 			{
				// We need to force a rebuild as we may not have detected 
				// a change to selected properties
				BuildQuery ();
 				return base.QueryString;
			} 
 			set
 			{ 
				base.QueryString = value; 
 			}
		} 
	
		/// 
 		///     Gets or sets the event class to query.
		///  
 		/// 
 		///    A string containing the name of the 
		///    event class to query. 
 		/// 
		///  
		///     Setting this property value overrides any previous value
		///       stored
 		///       in the object. The query string is rebuilt to
		///       reflect the new class name. 
 		/// 
 		///  
		/// This example creates a new  
 		/// that represents the query: "SELECT * FROM  ".
		/// WqlEventQuery q = new WqlEventQuery(); 
		/// q.EventClassName = "MyEvent";
		/// 
 		/// Dim q As New WqlEventQuery()
		/// q.EventClassName = "MyEvent" 
 		/// 
 		///  
		public string EventClassName 
 		{
			get { return (null != eventClassName) ? eventClassName : String.Empty; } 
			set { eventClassName = value; BuildQuery(); }
		}

 		///  
		///    Gets or sets the condition to be applied to events of the
 		///       specified class. 
 		///  
		/// 
 		///    The condition is represented as a 
		///       string, containing one or more clauses of the form: <propName>
		///       <operator> <value> combined with and/or operators. <propName>
		///       must represent a property defined on the event class specified in this query.
 		///  
		/// 
 		///    Setting this property value overrides any previous value 
 		///       stored in the object. The query string is rebuilt to 
		///       reflect the new condition.
 		///  
		/// 
		/// This example creates a new 
		/// that represents the query: "SELECT * FROM  WHERE
 		///  > 8". 
		/// WqlEventQuery q = new WqlEventQuery();
 		/// q.EventClassName = "MyEvent"; 
 		/// q.Condition = "PropVal > 8"; 
		/// 
 		/// Dim q As New WqlEventQuery() 
		/// q.EventClassName = "MyEvent"
		/// q.Condition = "PropVal > 8"
		/// 
 		///  
		public string Condition
 		{ 
 			get { return (null != condition) ? condition : String.Empty; } 
			set { condition = value; BuildQuery(); }
 		} 

		/// 
		///    Gets or sets the polling interval to be used in this query.
		///  
 		/// 
		///    Null, if there is no polling involved; otherwise, a 
 		///       valid  
 		///       value if polling is required.
		///  
 		/// 
		///    This property should only be set in cases
		///       where there is no event provider for the event requested, and WMI is required to
		///       poll for the requested condition. 
 		///    Setting this property value overrides any previous value
		///       stored in 
 		///       the object. The query string is rebuilt to reflect the new interval. 
 		/// 
		///  
 		/// This example creates a new 
		/// that represents the query: "SELECT * FROM WITHIN 10 WHERE  > 8".
		/// WqlEventQuery q = new WqlEventQuery();
		/// q.EventClassName = "__InstanceModificationEvent"; 
 		/// q.Condition = "PropVal > 8";
		/// q.WithinInterval = new TimeSpan(0,0,10); 
 		///  
 		/// Dim q As New WqlEventQuery()
		/// q.EventClassName = "__InstanceModificationEvent" 
 		/// q.Condition = "PropVal > 8"
		/// q.WithinInterval = New TimeSpan(0,0,10)
		/// 
		///  
 		public TimeSpan WithinInterval
		{ 
 			get { return withinInterval; } 
 			set { withinInterval = value; BuildQuery(); }
		} 

 		/// 
		///    Gets or sets the interval to be used for grouping events of
		///       the same type. 
		/// 
 		///  
		///     Null, if there is no 
 		///       grouping involved; otherwise, the interval in which WMI should group events of
 		///       the same type. 
		/// 
 		/// 
		///     Setting this property value overrides any previous value stored in
		///       the object. The query string is rebuilt to reflect the new interval. 
		/// 
 		///  
		/// This example creates a new  
 		/// that represents the query: "SELECT * FROM  WHERE
 		///  > 8 GROUP WITHIN 10", which means "send notification 
		/// of all  events where the 
 		/// property is greater than 8, and aggregate these events within 10-second intervals."
		/// WqlEventQuery q = new WqlEventQuery();
		/// q.EventClassName = "MyEvent"; 
		/// q.Condition = "PropVal > 8";
 		/// q.GroupWithinInterval = new TimeSpan(0,0,10); 
		///  
 		/// Dim q As New WqlEventQuery()
 		/// q.EventClassName = "MyEvent" 
		/// q.Condition = "PropVal > 8"
 		/// q.GroupWithinInterval = New TimeSpan(0,0,10)
		/// 
		///  
		public TimeSpan GroupWithinInterval
 		{ 
			get { return groupWithinInterval; } 
 			set { groupWithinInterval = value; BuildQuery(); }
 		} 

		/// 
 		///    Gets or sets properties in the event to be used for
		///       grouping events of the same type. 
		/// 
		///  
 		///     
		///       Null, if no grouping is required; otherwise, a collection of event
 		///       property names. 
 		/// 
		/// 
 		///     Setting this property value overrides any previous value stored in
		///       the object. The query string is rebuilt to reflect the new grouping. 
		/// 
		///  
 		/// This example creates a new  
		/// that represents the query: "SELECT * FROM  GROUP
 		/// WITHIN 300 BY ", which means "send notification of all 
 		///  events, aggregated by the property, within 10-minute intervals."
		/// WqlEventQuery q = new WqlEventQuery();
 		/// q.EventClassName = "EmailEvent";
		/// q.GroupWithinInterval = new TimeSpan(0,10,0); 
		/// q.GroupByPropertyList = new StringCollection();
		/// q.GroupByPropertyList.Add("Sender"); 
 		///  
		/// Dim q As New WqlEventQuery()
 		/// q.EventClassName = "EmailEvent" 
 		/// q.GroupWithinInterval = New TimeSpan(0,10,0)
		/// q.GroupByPropertyList = New StringCollection()
 		/// q.GroupByPropertyList.Add("Sender")
		///  
		/// 
		public StringCollection GroupByPropertyList 
 		{ 
			get { return groupByPropertyList; }
 			set { 
 				// A tad painful since StringCollection doesn't support ICloneable
				StringCollection src = (StringCollection)value;
 				StringCollection dst = new StringCollection ();
 
				foreach (String s in src)
					dst.Add (s); 
					 
 				groupByPropertyList = dst;
				BuildQuery(); 
 			}
 		}

		///  
 		///    Gets or sets the condition to be applied to the aggregation of
		///       events, based on the number of events received. 
		///  
		/// 
 		///     
		///       Null, if no aggregation or no condition should be applied;
 		///       otherwise, a condition of the form "NumberOfEvents <operator>
 		///       <value>".
		///  
 		/// 
		///     Setting this property value overrides any previous value stored in 
		///       the object. The query string is rebuilt to reflect the new grouping condition. 
		/// 
 		///  
		/// This example creates a new 
 		/// that represents the query: "SELECT * FROM  GROUP
 		/// WITHIN 300 HAVING  > 5", which means "send
		/// notification of all  events, aggregated within 
 		/// 10-minute intervals, if there are more than 5 occurrences."
		/// WqlEventQuery q = new WqlEventQuery(); 
		/// q.EventClassName = "EmailEvent"; 
		/// q.GroupWithinInterval = new TimeSpan(0,10,0);
 		/// q.HavingCondition = "NumberOfEvents > 5"; 
		/// 
 		/// Dim q As New WqlEventQuery()
 		/// q.EventClassName = "EmailEvent"
		/// q.GroupWithinInterval = new TimeSpan(0,10,0) 
 		/// q.HavingCondition = "NumberOfEvents > 5"
		///  
		///  
		public string HavingCondition
 		{ 
			get { return (null != havingCondition) ? havingCondition : String.Empty; }
 			set { havingCondition = value; BuildQuery(); }
 		}
 
		
 		///  
		///  Builds the query string according to the current property values. 
		/// 
		protected internal void BuildQuery() 
 		{
			//If the event class name is not set we can't build a query
 			//This shouldn't throw because the user may be in the process of setting properties...
 			if ((eventClassName == null) || (eventClassName.Length==0)) 
			{
 				SetQueryString (String.Empty); 
				return; 
			}
 
			//Select clause
 			string s = tokenSelectAll;	//no property list allowed here...

			//From clause 
 			s = s + "from " + eventClassName;
 
 			//Within clause 
			if (withinInterval != TimeSpan.Zero)
 				s = s + " within " + withinInterval.TotalSeconds.ToString((IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(System.Double))); 

			//Where clause
			if (!(Condition.Length==0))
				s = s + " where " + condition; 

 			//Group within clause 
			if (groupWithinInterval != TimeSpan.Zero) 
 			{
 				s = s + " group within " + groupWithinInterval.TotalSeconds.ToString((IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(System.Double))); 

				//Group By clause
 				if ((null != groupByPropertyList) && (0 < groupByPropertyList.Count))
				{ 
					int count = groupByPropertyList.Count;
					s = s + " by "; 
 
 					for (int i=0; i= keyword.Length) && (0 == String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase)))
 			{ 
				string intervalString = null; bFound = false;
				ParseToken(ref q, keyword, null, ref bFound, ref intervalString); 
				withinInterval = TimeSpan.FromSeconds(((IConvertible)intervalString).ToDouble(null)); 
 			}
 
			//Find "group within" clause
 			keyword = "group within ";
 			if ((q.Length >= keyword.Length) && ((i = q.ToLower(CultureInfo.InvariantCulture).IndexOf(keyword, StringComparison.Ordinal)) != -1)) //found
			{ 
 				//Separate the part of the string before this - that should be the "where" clause
				w = q.Substring(0, i).Trim(); 
				q = q.Remove(0, i); 

				string intervalString = null; bFound=false; 
 				ParseToken(ref q, keyword, null, ref bFound, ref intervalString);
				groupWithinInterval = TimeSpan.FromSeconds(((IConvertible)intervalString).ToDouble(null));

 				//Find "By" subclause 
 				keyword = "by ";
				if ((q.Length >= keyword.Length) && (0 == String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) 
 				{ 
					q = q.Remove(0, keyword.Length);
					if (null != groupByPropertyList) 
						groupByPropertyList.Clear ();
 					else
						groupByPropertyList = new StringCollection ();
 
 					//get the property list
 					while (true) 
					{ 
 						if ((i = q.IndexOf(',')) > 0)
						{ 
							tempProp = q.Substring(0, i);
							q = q.Remove(0, i+1).TrimStart(null);
 							tempProp = tempProp.Trim();
							if (tempProp.Length>0) 
 								groupByPropertyList.Add(tempProp);
 						} 
						else 
 						{ //last property in the list
							if ((i = q.IndexOf(' ')) > 0) 
							{
								tempProp = q.Substring(0, i);
 								q = q.Remove(0, i).TrimStart(null);
								groupByPropertyList.Add(tempProp); 
 								break;
 							} 
							else //end of the query 
 							{
								groupByPropertyList.Add(q); 
								return;
							}
 						}
					} //while 
 				} //by
 
 				//Find "Having" subclause 
				keyword = "having "; bFound = false;
 				if ((q.Length >= keyword.Length) && (0 == String.Compare (q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) 
				{   //the rest until the end is assumed to be the having condition
					q = q.Remove(0, keyword.Length);
					
 					if (q.Length == 0) //bad query 
						throw new ArgumentException(RC.GetString("INVALID_QUERY"),"having");
 
 					havingCondition = q; 
 				}
			} 
 			else
				//No "group within" then everything should be the "where" clause
				w = q.Trim();
 
			//Find "where" clause
 			keyword = "where "; 
			if ((w.Length >= keyword.Length) && (0 == String.Compare (w, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) //where clause exists 
 			{
 				condition = w.Substring(keyword.Length);				 
			}

 		}//ParseQuery()
 

		//ICloneable 
		///  
		///    Creates a copy of the object.
 		///  
		/// 
 		///    The copied object.
 		/// 
		public override object Clone() 
 		{
			string[] strArray = null; 
 
			if (null != groupByPropertyList)
			{ 
 				int count = groupByPropertyList.Count;

				if (0 < count)
 				{ 
 					strArray = new String [count];
					groupByPropertyList.CopyTo (strArray, 0); 
 				} 
			}
 
			return new WqlEventQuery(eventClassName, withinInterval, condition, groupWithinInterval,
																			strArray, havingCondition);
 		}
 
	}//WqlEventQuery
 
 
 	/// 
 	/// Converts a String to a ManagementQuery 
	/// 
 	class ManagementQueryConverter : ExpandableObjectConverter
	{
 
		/// 
		/// Determines if this converter can convert an object in the given source type to the native type of the converter. 
 		///  
		/// An ITypeDescriptorContext that provides a format context.
 		/// A Type that represents the type you wish to convert from. 
 		/// 
		///    true if this converter can perform the conversion; otherwise, false.
 		/// 
		public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
		{
			if ((sourceType == typeof(ManagementQuery))) 
 			{ 
				return true;
 			} 
 			return base.CanConvertFrom(context,sourceType);
		}

 		///  
		/// Gets a value indicating whether this converter can convert an object to the given destination type using the context.
		///  
		/// An ITypeDescriptorContext that provides a format context. 
 		/// A Type that represents the type you wish to convert to.
		///  
 		///    true if this converter can perform the conversion; otherwise, false.
 		/// 
		public override Boolean CanConvertTo(ITypeDescriptorContext context, Type destinationType)
 		{ 
			if ((destinationType == typeof(InstanceDescriptor)))
			{ 
				return true; 
 			}
			return base.CanConvertTo(context,destinationType); 
 		}

 		/// 
		///      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.
 		///  
		/// An ITypeDescriptorContext that provides a format context.
 		/// A CultureInfo object. If a null reference (Nothing in Visual Basic) is passed, the current culture is assumed.
 		/// The Object to convert.
		/// The Type to convert the value parameter to. 
 		/// An Object that represents the converted value.
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
		{ 

			if (destinationType == null) 
 			{
				throw new ArgumentNullException("destinationType");
 			}
 
 			if (value is EventQuery && destinationType == typeof(InstanceDescriptor))
			{ 
 				EventQuery obj = ((EventQuery)(value)); 
				ConstructorInfo ctor = typeof(EventQuery).GetConstructor(new Type[] {typeof(System.String)});
				if (ctor != null) 
				{
 					return new InstanceDescriptor(ctor, new object[] {obj.QueryString});
				}
 			}			 
 		
			if (value is ObjectQuery && destinationType == typeof(InstanceDescriptor)) 
 			{ 
				ObjectQuery obj = ((ObjectQuery)(value));
				ConstructorInfo ctor = typeof(ObjectQuery).GetConstructor(new Type[] {typeof(System.String)}); 
				if (ctor != null)
 				{
					return new InstanceDescriptor(ctor, new object[] {obj.QueryString});
 				} 
 			}
			return base.ConvertTo(context,culture,value,destinationType); 
 		} 
	}
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK