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 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 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 }