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 static readonly int DBusMessageIterSize = Marshal.SizeOf (typeof(_DBusMessageIter));
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     [StructLayout(LayoutKind.Sequential)]
00244     private class _DBusMessageIter
00245     {
00246        IntPtr dummy1;
00247        IntPtr dummy2;
00248        int    dummy3;
00249        int    dummy4;
00250        int    dummy5;
00251        int    dummy6;
00252        int    dummy7;
00253        int    dummy8;
00254        int    dummy9;
00255        int    dummy10;
00256        int    dummy11;
00257        int    pad1;
00258        int    pad2;
00259        IntPtr pad3;
00260    }
00261             
00262     private class ArgumentsEnumerator : IEnumerator
00263     {
00264       private Arguments arguments;
00265       private bool started = false;
00266       private bool notEmpty = false;
00267       private IntPtr iter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
00268       
00269       public ArgumentsEnumerator(Arguments arguments)
00270       {
00271         this.arguments = arguments;
00272         Reset();
00273       }
00274       
00275       ~ArgumentsEnumerator()
00276       {
00277         Marshal.FreeCoTaskMem(iter);
00278       }
00279 
00280       public bool MoveNext()
00281       {
00282         if (started) {
00283           return dbus_message_iter_next(iter);
00284         } else {
00285           started = true;
00286           return notEmpty;
00287         }
00288       }
00289       
00290       public void Reset()
00291       {
00292         notEmpty = dbus_message_iter_init(arguments.message.RawMessage, iter);
00293         started = false;
00294       }
00295       
00296       public object Current
00297       {
00298         get
00299           {
00300             object [] pars = new Object[2];
00301             pars[0] = iter;
00302             pars[1] = arguments.message.Service;
00303             
00304             Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
00305             DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
00306 
00307             return dbusType;
00308           }
00309       }
00310     }
00311 
00312     [DllImport("dbus-1")]
00313     private extern static void dbus_message_iter_init_append(IntPtr rawMessage, IntPtr iter);
00314 
00315     [DllImport("dbus-1")]
00316     private extern static bool dbus_message_iter_has_next(IntPtr iter);
00317 
00318     [DllImport("dbus-1")]
00319     private extern static bool dbus_message_iter_next(IntPtr iter);
00320 
00321     [DllImport("dbus-1")]
00322     private extern static bool dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
00323 
00324     [DllImport("dbus-1")]
00325     private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
00326   }
00327 }

Generated on Wed Feb 27 10:13:37 2008 for D-BUS by  doxygen 1.4.6