2 using System.Collections;
3 using System.Reflection;
4 using System.Runtime.InteropServices;
8 // Holds the arguments of a message. Provides methods for appending
9 // arguments and to assist in matching .NET types with D-BUS types.
10 public class Arguments : IEnumerable
12 // Must follow sizeof(DBusMessageIter)
13 internal const int DBusMessageIterSize = 14*4;
14 private static Hashtable dbusTypes = null;
15 private Message message;
16 private IntPtr appenderIter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
17 private IEnumerator enumerator = null;
25 Marshal.FreeCoTaskMem(appenderIter);
28 internal Arguments(Message message)
30 this.message = message;
33 // Checks the suitability of a D-BUS type for supporting a .NET
35 public static bool Suits(Type dbusType, Type type)
37 object [] pars = new object[1];
40 return (bool) dbusType.InvokeMember("Suits", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
43 // Find a suitable match for the given .NET type or throw an
44 // exception if one can't be found.
45 public static Type MatchType(Type type)
47 foreach(Type dbusType in DBusTypes.Values) {
48 if (Suits(dbusType, type)) {
53 throw new ApplicationException("No suitable DBUS type found for type '" + type + "'");
57 public static Hashtable DBusTypes {
60 if (dbusTypes == null) {
61 dbusTypes = new Hashtable();
63 foreach (Type type in Assembly.GetAssembly(typeof(DBusType.IDBusType)).GetTypes()) {
64 if (type != typeof(DBusType.IDBusType) && typeof(DBusType.IDBusType).IsAssignableFrom(type)) {
65 dbusTypes.Add(GetCode(type), type);
75 public void Append(DBusType.IDBusType dbusType)
77 dbusType.Append(appenderIter);
80 // Append an argument of the specified type
81 private void AppendType(Type type, object val)
83 object [] pars = new Object[2];
85 pars[1] = message.Service;
86 DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(MatchType(type), pars);
90 // Append the results of a method call
91 public void AppendResults(MethodInfo method, object retVal, object [] parameters)
95 if (method.ReturnType != typeof(void)) {
96 AppendType(method.ReturnType, retVal);
99 for (int i = 0; i < method.GetParameters().Length; i++) {
100 ParameterInfo par = method.GetParameters()[i];
101 if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
102 // It's an OUT or INOUT parameter.
103 AppendType(par.ParameterType.UnderlyingSystemType, parameters[i]);
108 // Get the parameters
109 public object[] GetParameters(MethodInfo method)
111 ParameterInfo[] pars = method.GetParameters();
112 ArrayList paramList = new ArrayList();
114 enumerator = GetEnumerator();
115 foreach (ParameterInfo par in pars) {
117 // It's an IN or INOUT paramter.
118 enumerator.MoveNext();
119 DBusType.IDBusType dbusType = (DBusType.IDBusType) enumerator.Current;
120 paramList.Add(dbusType.Get(par.ParameterType));
122 // It's an OUT so just create a parameter for it
128 return paramList.ToArray();
131 // Parse the IN & REF parameters to a method and return the types in a list.
132 public static object[] ParseInParameters(MethodInfo method)
134 ArrayList types = new ArrayList();
136 ParameterInfo[] pars = method.GetParameters();
137 foreach (ParameterInfo par in pars) {
139 types.Add(MatchType(par.ParameterType));
143 return types.ToArray();
146 // Parse the OUT & REF parameters to a method and return the types in a list.
147 public static object[] ParseOutParameters(MethodInfo method)
149 ArrayList types = new ArrayList();
151 ParameterInfo[] pars = method.GetParameters();
152 foreach (ParameterInfo par in pars) {
153 if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
154 types.Add(MatchType(par.ParameterType));
158 return types.ToArray();
161 // Get the appropriate constructor for a D-BUS type
162 public static ConstructorInfo GetDBusTypeConstructor(Type dbusType, Type type)
164 ConstructorInfo constructor = dbusType.GetConstructor(new Type[] {type.UnderlyingSystemType, typeof(Service)});
165 if (constructor == null)
166 throw new ArgumentException("There is no valid constructor for '" + dbusType + "' from type '" + type + "'");
171 // Get the type code for a given D-BUS type
172 public static char GetCode(Type dbusType)
174 return (char) dbusType.InvokeMember("Code", BindingFlags.Static | BindingFlags.GetField, null, null, null);
177 // Get a complete method signature
178 public override string ToString()
180 IntPtr iter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
183 // Iterate through the parameters getting the type codes to a string
184 dbus_message_iter_init(message.RawMessage, iter);
187 char code = (char) dbus_message_iter_get_arg_type(iter);
192 } while (dbus_message_iter_next(iter));
194 Marshal.FreeCoTaskMem(iter);
199 // Move to the next parameter
200 public DBusType.IDBusType GetNext()
202 enumerator.MoveNext();
203 return (DBusType.IDBusType) enumerator.Current;
207 public void InitAppending()
209 dbus_message_append_iter_init(message.RawMessage, appenderIter);
212 // Get the enumerator
213 public IEnumerator GetEnumerator()
215 return new ArgumentsEnumerator(this);
218 private class ArgumentsEnumerator : IEnumerator
220 private Arguments arguments;
221 private bool started = false;
222 private IntPtr iter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
224 public ArgumentsEnumerator(Arguments arguments)
226 this.arguments = arguments;
230 ~ArgumentsEnumerator()
232 Marshal.FreeCoTaskMem(iter);
235 public bool MoveNext()
238 return dbus_message_iter_next(iter);
247 dbus_message_iter_init(arguments.message.RawMessage, iter);
251 public object Current
255 object [] pars = new Object[2];
257 pars[1] = arguments.message.Service;
259 Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
260 DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
267 [DllImport("dbus-1")]
268 private extern static void dbus_message_append_iter_init(IntPtr rawMessage, IntPtr iter);
270 [DllImport("dbus-1")]
271 private extern static bool dbus_message_iter_has_next(IntPtr iter);
273 [DllImport("dbus-1")]
274 private extern static bool dbus_message_iter_next(IntPtr iter);
276 [DllImport("dbus-1")]
277 private extern static void dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
279 [DllImport("dbus-1")]
280 private extern static int dbus_message_iter_get_arg_type(IntPtr iter);