00001 using System;
00002 using System.Collections;
00003 using System.Reflection;
00004 using System.Runtime.InteropServices;
00005
00006 namespace DBus
00007 {
00008
00009
00010 public class Arguments : IEnumerable, IDisposable
00011 {
00012
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
00042
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
00052
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
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
00083 public void Append(DBusType.IDBusType dbusType)
00084 {
00085 dbusType.Append(appenderIter);
00086 }
00087
00088
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
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
00111 AppendType(par.ParameterType.UnderlyingSystemType, parameters[i]);
00112 }
00113 }
00114 }
00115
00116
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
00126 enumerator.MoveNext();
00127 DBusType.IDBusType dbusType = (DBusType.IDBusType) enumerator.Current;
00128 paramList.Add(dbusType.Get(par.ParameterType));
00129 } else {
00130
00131 object var = null;
00132 paramList.Add(var);
00133 }
00134 }
00135
00136 return paramList.ToArray();
00137 }
00138
00139
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
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
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
00189 public static char GetCode(Type dbusType)
00190 {
00191 return (char) dbusType.InvokeMember("Code", BindingFlags.Static | BindingFlags.GetField, null, null, null);
00192 }
00193
00194
00195 public static string GetCodeAsString (Type dbusType)
00196 {
00197 return GetCode (dbusType).ToString ();
00198 }
00199
00200
00201 public override string ToString()
00202 {
00203 IntPtr iter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
00204 string key = "";
00205
00206
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
00225 public DBusType.IDBusType GetNext()
00226 {
00227 enumerator.MoveNext();
00228 return (DBusType.IDBusType) enumerator.Current;
00229 }
00230
00231
00232 public void InitAppending()
00233 {
00234 dbus_message_iter_init_append(message.RawMessage, appenderIter);
00235 }
00236
00237
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 }