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, IDisposable
12 // Must follow sizeof(DBusMessageIter)
13 internal static readonly int DBusMessageIterSize = Marshal.SizeOf (typeof(_DBusMessageIter));
14 private static Hashtable dbusTypes = null;
15 private Message message;
16 private IntPtr appenderIter;
17 private IEnumerator enumerator = null;
19 internal Arguments (Message message)
21 this.appenderIter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
22 this.message = message;
25 private void Dispose (bool disposing)
27 Marshal.FreeCoTaskMem(appenderIter);
30 public void Dispose ()
33 GC.SuppressFinalize (this);
41 // Checks the suitability of a D-BUS type for supporting a .NET
43 public static bool Suits(Type dbusType, Type type)
45 object [] pars = new object[1];
48 return (bool) dbusType.InvokeMember("Suits", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
51 // Find a suitable match for the given .NET type or throw an
52 // exception if one can't be found.
53 public static Type MatchType(Type type)
55 foreach(Type dbusType in DBusTypes.Values) {
56 if (Suits(dbusType, type)) {
61 throw new ApplicationException("No suitable DBUS type found for type '" + type + "'");
65 public static Hashtable DBusTypes {
68 if (dbusTypes == null) {
69 dbusTypes = new Hashtable();
71 foreach (Type type in Assembly.GetAssembly(typeof(DBusType.IDBusType)).GetTypes()) {
72 if (type != typeof(DBusType.IDBusType) && typeof(DBusType.IDBusType).IsAssignableFrom(type)) {
73 dbusTypes.Add(GetCode(type), type);
83 public void Append(DBusType.IDBusType dbusType)
85 dbusType.Append(appenderIter);
88 // Append an argument of the specified type
89 private void AppendType(Type type, object val)
91 object [] pars = new Object[2];
93 pars[1] = message.Service;
94 DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(MatchType(type), pars);
98 // Append the results of a method call
99 public void AppendResults(MethodInfo method, object retVal, object [] parameters)
103 if (method.ReturnType != typeof(void)) {
104 AppendType(method.ReturnType, retVal);
107 for (int i = 0; i < method.GetParameters().Length; i++) {
108 ParameterInfo par = method.GetParameters()[i];
109 if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
110 // It's an OUT or INOUT parameter.
111 AppendType(par.ParameterType.UnderlyingSystemType, parameters[i]);
116 // Get the parameters
117 public object[] GetParameters(MethodInfo method)
119 ParameterInfo[] pars = method.GetParameters();
120 ArrayList paramList = new ArrayList();
122 enumerator = GetEnumerator();
123 foreach (ParameterInfo par in pars) {
125 // It's an IN or INOUT paramter.
126 enumerator.MoveNext();
127 DBusType.IDBusType dbusType = (DBusType.IDBusType) enumerator.Current;
128 paramList.Add(dbusType.Get(par.ParameterType));
130 // It's an OUT so just create a parameter for it
136 return paramList.ToArray();
139 // Parse the IN & REF parameters to a method and return the types in a list.
140 public static object[] ParseInParameters(MethodInfo method)
142 ArrayList types = new ArrayList();
144 ParameterInfo[] pars = method.GetParameters();
145 foreach (ParameterInfo par in pars) {
147 types.Add(MatchType(par.ParameterType));
151 return types.ToArray();
154 // Parse the OUT & REF parameters to a method and return the types in a list.
155 public static object[] ParseOutParameters(MethodInfo method)
157 ArrayList types = new ArrayList();
159 ParameterInfo[] pars = method.GetParameters();
160 foreach (ParameterInfo par in pars) {
161 if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
162 types.Add(MatchType(par.ParameterType));
166 return types.ToArray();
169 // Get the appropriate constructor for a D-BUS type
170 public static ConstructorInfo GetDBusTypeConstructor(Type dbusType, Type type)
172 Type constructorType;
175 constructorType = typeof (System.Array);
176 else if (type.IsEnum)
177 constructorType = Enum.GetUnderlyingType (type);
179 constructorType = type.UnderlyingSystemType;
181 ConstructorInfo constructor = dbusType.GetConstructor(new Type[] {constructorType, typeof(Service)});
182 if (constructor == null)
183 throw new ArgumentException("There is no valid constructor for '" + dbusType + "' from type '" + type + "'");
188 // Get the type code for a given D-BUS type
189 public static char GetCode(Type dbusType)
191 return (char) dbusType.InvokeMember("Code", BindingFlags.Static | BindingFlags.GetField, null, null, null);
194 // Get the type code for a given D-BUS type as a string
195 public static string GetCodeAsString (Type dbusType)
197 return GetCode (dbusType).ToString ();
200 // Get a complete method signature
201 public override string ToString()
203 IntPtr iter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
206 // Iterate through the parameters getting the type codes to a string
207 bool notEmpty = dbus_message_iter_init(message.RawMessage, iter);
211 char code = (char) dbus_message_iter_get_arg_type(iter);
216 } while (dbus_message_iter_next(iter));
219 Marshal.FreeCoTaskMem(iter);
224 // Move to the next parameter
225 public DBusType.IDBusType GetNext()
227 enumerator.MoveNext();
228 return (DBusType.IDBusType) enumerator.Current;
232 public void InitAppending()
234 dbus_message_iter_init_append(message.RawMessage, appenderIter);
237 // Get the enumerator
238 public IEnumerator GetEnumerator()
240 return new ArgumentsEnumerator(this);
243 [StructLayout(LayoutKind.Sequential)]
244 private class _DBusMessageIter
262 private class ArgumentsEnumerator : IEnumerator
264 private Arguments arguments;
265 private bool started = false;
266 private bool notEmpty = false;
267 private IntPtr iter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
269 public ArgumentsEnumerator(Arguments arguments)
271 this.arguments = arguments;
275 ~ArgumentsEnumerator()
277 Marshal.FreeCoTaskMem(iter);
280 public bool MoveNext()
283 return dbus_message_iter_next(iter);
292 notEmpty = dbus_message_iter_init(arguments.message.RawMessage, iter);
296 public object Current
300 object [] pars = new Object[2];
302 pars[1] = arguments.message.Service;
304 Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
305 DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
312 [DllImport("dbus-1")]
313 private extern static void dbus_message_iter_init_append(IntPtr rawMessage, IntPtr iter);
315 [DllImport("dbus-1")]
316 private extern static bool dbus_message_iter_has_next(IntPtr iter);
318 [DllImport("dbus-1")]
319 private extern static bool dbus_message_iter_next(IntPtr iter);
321 [DllImport("dbus-1")]
322 private extern static bool dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
324 [DllImport("dbus-1")]
325 private extern static int dbus_message_iter_get_arg_type(IntPtr iter);