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 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
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 override string ToString()
00196 {
00197 IntPtr iter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
00198 string key = "";
00199
00200
00201 bool notEmpty = dbus_message_iter_init(message.RawMessage, iter);
00202
00203 if (notEmpty) {
00204 do {
00205 char code = (char) dbus_message_iter_get_arg_type(iter);
00206 if (code == '\0')
00207 return key;
00208
00209 key += code;
00210 } while (dbus_message_iter_next(iter));
00211 }
00212
00213 Marshal.FreeCoTaskMem(iter);
00214
00215 return key;
00216 }
00217
00218
00219 public DBusType.IDBusType GetNext()
00220 {
00221 enumerator.MoveNext();
00222 return (DBusType.IDBusType) enumerator.Current;
00223 }
00224
00225
00226 public void InitAppending()
00227 {
00228 dbus_message_append_iter_init(message.RawMessage, appenderIter);
00229 }
00230
00231
00232 public IEnumerator GetEnumerator()
00233 {
00234 return new ArgumentsEnumerator(this);
00235 }
00236
00237 private class ArgumentsEnumerator : IEnumerator
00238 {
00239 private Arguments arguments;
00240 private bool started = false;
00241 private bool notEmpty = false;
00242 private IntPtr iter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
00243
00244 public ArgumentsEnumerator(Arguments arguments)
00245 {
00246 this.arguments = arguments;
00247 Reset();
00248 }
00249
00250 ~ArgumentsEnumerator()
00251 {
00252 Marshal.FreeCoTaskMem(iter);
00253 }
00254
00255 public bool MoveNext()
00256 {
00257 if (started) {
00258 return dbus_message_iter_next(iter);
00259 } else {
00260 started = true;
00261 return notEmpty;
00262 }
00263 }
00264
00265 public void Reset()
00266 {
00267 notEmpty = dbus_message_iter_init(arguments.message.RawMessage, iter);
00268 started = false;
00269 }
00270
00271 public object Current
00272 {
00273 get
00274 {
00275 object [] pars = new Object[2];
00276 pars[0] = iter;
00277 pars[1] = arguments.message.Service;
00278
00279 Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
00280 DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
00281
00282 return dbusType;
00283 }
00284 }
00285 }
00286
00287 [DllImport("dbus-1")]
00288 private extern static void dbus_message_append_iter_init(IntPtr rawMessage, IntPtr iter);
00289
00290 [DllImport("dbus-1")]
00291 private extern static bool dbus_message_iter_has_next(IntPtr iter);
00292
00293 [DllImport("dbus-1")]
00294 private extern static bool dbus_message_iter_next(IntPtr iter);
00295
00296 [DllImport("dbus-1")]
00297 private extern static bool dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
00298
00299 [DllImport("dbus-1")]
00300 private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
00301 }
00302 }