Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Related Pages

Arguments.cs

00001 using System;
00002 using System.Collections;
00003 using System.Reflection;
00004 using System.Runtime.InteropServices;
00005 
00006 namespace DBus
00007 {
00008   // Holds the arguments of a message. Provides methods for appending
00009   // arguments and to assist in matching .NET types with D-BUS types.
00010         public class Arguments : IEnumerable, IDisposable
00011   {
00012     // Must follow sizeof(DBusMessageIter)
00013     internal const int DBusMessageIterSize = 14*4;
00014     private static Hashtable dbusTypes = null;
00015     private Message message;
00016     private IntPtr appenderIter;
00017     private IEnumerator enumerator = null;
00018     
00019     internal Arguments (Message message)
00020     {
00021       this.appenderIter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
00022       this.message = message;
00023     }
00024 
00025     private void Dispose (bool disposing)
00026     {
00027       Marshal.FreeCoTaskMem(appenderIter);
00028     }
00029 
00030     public void Dispose ()
00031     {
00032       Dispose (true);
00033       GC.SuppressFinalize (this);
00034     }
00035 
00036     ~Arguments()
00037     {
00038       Dispose (false);
00039     }
00040 
00041     // Checks the suitability of a D-BUS type for supporting a .NET
00042     // type.
00043     public static bool Suits(Type dbusType, Type type) 
00044     {
00045       object [] pars = new object[1];
00046       pars[0] = type;
00047       
00048       return (bool) dbusType.InvokeMember("Suits", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
00049     }
00050     
00051     // Find a suitable match for the given .NET type or throw an
00052     // exception if one can't be found.
00053     public static Type MatchType(Type type) 
00054     {      
00055       foreach(Type dbusType in DBusTypes.Values) {
00056         if (Suits(dbusType, type)) {
00057           return dbusType;
00058         }
00059       }
00060       
00061       throw new ApplicationException("No suitable DBUS type found for type '" + type + "'");
00062     }
00063     
00064     // The D-BUS types.
00065     public static Hashtable DBusTypes {
00066       get 
00067         {
00068           if (dbusTypes == null) {
00069             dbusTypes = new Hashtable();
00070 
00071             foreach (Type type in Assembly.GetAssembly(typeof(DBusType.IDBusType)).GetTypes()) {
00072               if (type != typeof(DBusType.IDBusType) && typeof(DBusType.IDBusType).IsAssignableFrom(type)) {
00073                 dbusTypes.Add(GetCode(type), type);
00074               }
00075             }
00076           }
00077           
00078           return dbusTypes;
00079         }
00080     }
00081     
00082     // Append an argument
00083     public void Append(DBusType.IDBusType dbusType)
00084     {
00085       dbusType.Append(appenderIter);
00086     }
00087     
00088     // Append an argument of the specified type
00089     private void AppendType(Type type, object val)
00090     {
00091       object [] pars = new Object[2];
00092       pars[0] = val;
00093       pars[1] = message.Service;
00094       DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(MatchType(type), pars);
00095       Append(dbusType);
00096     }
00097     
00098     // Append the results of a method call
00099     public void AppendResults(MethodInfo method, object retVal, object [] parameters) 
00100     {
00101       InitAppending();
00102 
00103       if (method.ReturnType != typeof(void)) {
00104         AppendType(method.ReturnType, retVal);
00105       }
00106       
00107       for (int i = 0; i < method.GetParameters().Length; i++) {
00108         ParameterInfo par = method.GetParameters()[i];
00109         if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
00110           // It's an OUT or INOUT parameter.
00111           AppendType(par.ParameterType.UnderlyingSystemType, parameters[i]);
00112         }
00113       }
00114     }
00115     
00116     // Get the parameters
00117     public object[] GetParameters(MethodInfo method) 
00118     {
00119       ParameterInfo[] pars = method.GetParameters();
00120       ArrayList paramList = new ArrayList();
00121       
00122       enumerator = GetEnumerator();
00123       foreach (ParameterInfo par in pars) {
00124         if (!par.IsOut) {
00125           // It's an IN or INOUT paramter.
00126           enumerator.MoveNext();
00127           DBusType.IDBusType dbusType = (DBusType.IDBusType) enumerator.Current;
00128           paramList.Add(dbusType.Get(par.ParameterType));
00129         } else {
00130           // It's an OUT so just create a parameter for it
00131           object var = null;
00132           paramList.Add(var);
00133         }
00134       }
00135       
00136       return paramList.ToArray();
00137     }
00138 
00139     // Parse the IN & REF parameters to a method and return the types in a list.
00140     public static object[] ParseInParameters(MethodInfo method)
00141     {
00142       ArrayList types = new ArrayList();
00143 
00144       ParameterInfo[] pars = method.GetParameters();
00145       foreach (ParameterInfo par in pars) {
00146         if (!par.IsOut) {
00147           types.Add(MatchType(par.ParameterType));
00148         }
00149       }
00150 
00151       return types.ToArray();
00152     }
00153 
00154     // Parse the OUT & REF parameters to a method and return the types in a list.
00155     public static object[] ParseOutParameters(MethodInfo method)
00156     {
00157       ArrayList types = new ArrayList();
00158 
00159       ParameterInfo[] pars = method.GetParameters();
00160       foreach (ParameterInfo par in pars) {
00161         if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
00162           types.Add(MatchType(par.ParameterType));
00163         }
00164       }
00165 
00166       return types.ToArray();
00167     }
00168     
00169     // Get the appropriate constructor for a D-BUS type
00170     public static ConstructorInfo GetDBusTypeConstructor(Type dbusType, Type type) 
00171     {
00172       Type constructorType;
00173 
00174       if (type.IsArray)
00175         constructorType = typeof (System.Array);
00176       else if (type.IsEnum)
00177         constructorType = Enum.GetUnderlyingType (type);
00178       else
00179         constructorType = type.UnderlyingSystemType;
00180 
00181       ConstructorInfo constructor = dbusType.GetConstructor(new Type[] {constructorType, typeof(Service)});
00182       if (constructor == null)
00183         throw new ArgumentException("There is no valid constructor for '" + dbusType + "' from type '" + type + "'");
00184       
00185       return constructor;
00186     }
00187 
00188     // Get the type code for a given D-BUS type
00189     public static char GetCode(Type dbusType) 
00190     {
00191       return (char) dbusType.InvokeMember("Code", BindingFlags.Static | BindingFlags.GetField, null, null, null);
00192     }
00193 
00194     // Get the type code for a given D-BUS type as a string
00195     public static string GetCodeAsString (Type dbusType)
00196     {
00197       return GetCode (dbusType).ToString ();
00198     }
00199 
00200     // Get a complete method signature
00201     public override string ToString() 
00202     {
00203       IntPtr iter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
00204       string key = "";
00205 
00206       // Iterate through the parameters getting the type codes to a string
00207       bool notEmpty = dbus_message_iter_init(message.RawMessage, iter);
00208 
00209       if (notEmpty) {
00210         do {
00211           char code = (char) dbus_message_iter_get_arg_type(iter);
00212           if (code == '\0')
00213             return key;
00214           
00215           key += code;
00216         } while (dbus_message_iter_next(iter));
00217       }
00218 
00219       Marshal.FreeCoTaskMem(iter);
00220 
00221       return key;
00222     }
00223     
00224     // Move to the next parameter
00225     public DBusType.IDBusType GetNext() 
00226     {
00227       enumerator.MoveNext();
00228       return (DBusType.IDBusType) enumerator.Current;
00229     }
00230 
00231     // Begin appending
00232     public void InitAppending() 
00233     {
00234       dbus_message_iter_init_append(message.RawMessage, appenderIter);
00235     }
00236 
00237     // Get the enumerator
00238     public IEnumerator GetEnumerator()
00239     {
00240       return new ArgumentsEnumerator(this);
00241     }
00242 
00243     private class ArgumentsEnumerator : IEnumerator
00244     {
00245       private Arguments arguments;
00246       private bool started = false;
00247       private bool notEmpty = false;
00248       private IntPtr iter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
00249       
00250       public ArgumentsEnumerator(Arguments arguments)
00251       {
00252         this.arguments = arguments;
00253         Reset();
00254       }
00255       
00256       ~ArgumentsEnumerator()
00257       {
00258         Marshal.FreeCoTaskMem(iter);
00259       }
00260 
00261       public bool MoveNext()
00262       {
00263         if (started) {
00264           return dbus_message_iter_next(iter);
00265         } else {
00266           started = true;
00267           return notEmpty;
00268         }
00269       }
00270       
00271       public void Reset()
00272       {
00273         notEmpty = dbus_message_iter_init(arguments.message.RawMessage, iter);
00274         started = false;
00275       }
00276       
00277       public object Current
00278       {
00279         get
00280           {
00281             object [] pars = new Object[2];
00282             pars[0] = iter;
00283             pars[1] = arguments.message.Service;
00284             
00285             Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
00286             DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
00287 
00288             return dbusType;
00289           }
00290       }
00291     }
00292 
00293     [DllImport("dbus-1")]
00294     private extern static void dbus_message_iter_init_append(IntPtr rawMessage, IntPtr iter);
00295 
00296     [DllImport("dbus-1")]
00297     private extern static bool dbus_message_iter_has_next(IntPtr iter);
00298 
00299     [DllImport("dbus-1")]
00300     private extern static bool dbus_message_iter_next(IntPtr iter);
00301 
00302     [DllImport("dbus-1")]
00303     private extern static bool dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
00304 
00305     [DllImport("dbus-1")]
00306     private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
00307   }
00308 }

Generated on Tue Sep 13 01:28:06 2005 for D-BUS by  doxygen 1.4.4