summaryrefslogtreecommitdiffstats
path: root/mono/Arguments.cs
diff options
context:
space:
mode:
Diffstat (limited to 'mono/Arguments.cs')
-rw-r--r--mono/Arguments.cs304
1 files changed, 304 insertions, 0 deletions
diff --git a/mono/Arguments.cs b/mono/Arguments.cs
new file mode 100644
index 00000000..ac88d6a7
--- /dev/null
+++ b/mono/Arguments.cs
@@ -0,0 +1,304 @@
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace DBus
+{
+ // Holds the arguments of a message. Provides methods for appending
+ // arguments and to assist in matching .NET types with D-BUS types.
+ public class Arguments : IEnumerable
+ {
+ // Must follow sizeof(DBusMessageIter)
+ internal const int DBusMessageIterSize = 14*4;
+ private static Hashtable dbusTypes = null;
+ private Message message;
+ private IntPtr appenderIter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
+ private IEnumerator enumerator = null;
+
+ internal Arguments()
+ {
+ }
+
+ ~Arguments()
+ {
+ Marshal.FreeCoTaskMem(appenderIter);
+ }
+
+ internal Arguments(Message message)
+ {
+ this.message = message;
+ }
+
+ // Checks the suitability of a D-BUS type for supporting a .NET
+ // type.
+ public static bool Suits(Type dbusType, Type type)
+ {
+ object [] pars = new object[1];
+ pars[0] = type;
+
+ return (bool) dbusType.InvokeMember("Suits", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
+ }
+
+ // Find a suitable match for the given .NET type or throw an
+ // exception if one can't be found.
+ public static Type MatchType(Type type)
+ {
+ foreach(Type dbusType in DBusTypes.Values) {
+ if (Suits(dbusType, type)) {
+ return dbusType;
+ }
+ }
+
+ throw new ApplicationException("No suitable DBUS type found for type '" + type + "'");
+ }
+
+ // The D-BUS types.
+ public static Hashtable DBusTypes {
+ get
+ {
+ if (dbusTypes == null) {
+ dbusTypes = new Hashtable();
+
+ foreach (Type type in Assembly.GetAssembly(typeof(DBusType.IDBusType)).GetTypes()) {
+ if (type != typeof(DBusType.IDBusType) && typeof(DBusType.IDBusType).IsAssignableFrom(type)) {
+ dbusTypes.Add(GetCode(type), type);
+ }
+ }
+ }
+
+ return dbusTypes;
+ }
+ }
+
+ // Append an argument
+ public void Append(DBusType.IDBusType dbusType)
+ {
+ if (dbusType.GetType() == typeof(DBusType.ObjectPath)) {
+ ((DBusType.ObjectPath) dbusType).SetService(message.Service);
+ }
+ dbusType.Append(appenderIter);
+ }
+
+ // Append an argument of the specified type
+ private void AppendType(Type type, object val)
+ {
+ object [] pars = new Object[1];
+ pars[0] = val;
+ DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(MatchType(type), pars);
+ Append(dbusType);
+ }
+
+ // Append the results of a method call
+ public void AppendResults(MethodInfo method, object retVal, object [] parameters)
+ {
+ InitAppending();
+
+ if (method.ReturnType != typeof(void)) {
+ AppendType(method.ReturnType, retVal);
+ }
+
+ for (int i = 0; i < method.GetParameters().Length; i++) {
+ ParameterInfo par = method.GetParameters()[i];
+ if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
+ // It's an OUT or INOUT parameter.
+ AppendType(par.ParameterType.UnderlyingSystemType, parameters[i]);
+ }
+ }
+ }
+
+ // Get the parameters
+ public object[] GetParameters(MethodInfo method)
+ {
+ ParameterInfo[] pars = method.GetParameters();
+ ArrayList paramList = new ArrayList();
+
+ enumerator = GetEnumerator();
+ foreach (ParameterInfo par in pars) {
+ if (!par.IsOut) {
+ // It's an IN or INOUT paramter.
+ enumerator.MoveNext();
+ DBusType.IDBusType dbusType = (DBusType.IDBusType) enumerator.Current;
+ paramList.Add(dbusType.Get(par.ParameterType));
+ } else {
+ // It's an OUT so just create a parameter for it
+ object var = null;
+ paramList.Add(var);
+ }
+ }
+
+ return paramList.ToArray();
+ }
+
+ // Parse the IN & REF parameters to a method and return the types in a list.
+ public static object[] ParseInParameters(MethodInfo method)
+ {
+ ArrayList types = new ArrayList();
+
+ ParameterInfo[] pars = method.GetParameters();
+ foreach (ParameterInfo par in pars) {
+ if (!par.IsOut) {
+ types.Add(MatchType(par.ParameterType));
+ }
+ }
+
+ return types.ToArray();
+ }
+
+ // Parse the OUT & REF parameters to a method and return the types in a list.
+ public static object[] ParseOutParameters(MethodInfo method)
+ {
+ ArrayList types = new ArrayList();
+
+ ParameterInfo[] pars = method.GetParameters();
+ foreach (ParameterInfo par in pars) {
+ if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
+ types.Add(MatchType(par.ParameterType));
+ }
+ }
+
+ return types.ToArray();
+ }
+
+ // Get the appropriate constructor for a D-BUS type
+ public static ConstructorInfo GetDBusTypeConstructor(Type dbusType, Type type)
+ {
+ ConstructorInfo constructor = dbusType.GetConstructor(new Type[] {type.UnderlyingSystemType});
+ if (constructor == null)
+ throw new ArgumentException("There is no valid constructor for '" + dbusType + "' from type '" + type + "'");
+
+ return constructor;
+ }
+
+ // Get the signature of a method
+ public static string ParseParameters(MethodInfo method)
+ {
+ ParameterInfo[] pars = method.GetParameters();
+ string key = "";
+
+ foreach (ParameterInfo par in pars) {
+ if (!par.IsOut) {
+ Type dbusType = MatchType(par.ParameterType);
+ key += GetCode(dbusType);
+ }
+ }
+
+ return key;
+ }
+
+ // Get the type code for a given D-BUS type
+ public static char GetCode(Type dbusType)
+ {
+ return (char) dbusType.InvokeMember("Code", BindingFlags.Static | BindingFlags.GetField, null, null, null);
+ }
+
+ // Get a complete method signature
+ public override string ToString()
+ {
+ IntPtr iter = Marshal.AllocCoTaskMem(DBusMessageIterSize);
+ string key = "";
+
+ // Iterate through the parameters getting the type codes to a string
+ dbus_message_iter_init(message.RawMessage, iter);
+
+ do {
+ char code = (char) dbus_message_iter_get_arg_type(iter);
+ if (code == '\0')
+ return key;
+
+ key += code;
+ } while (dbus_message_iter_next(iter));
+
+ Marshal.FreeCoTaskMem(iter);
+
+ return key;
+ }
+
+ // Move to the next parameter
+ public DBusType.IDBusType GetNext()
+ {
+ enumerator.MoveNext();
+ return (DBusType.IDBusType) enumerator.Current;
+ }
+
+ // Begin appending
+ public void InitAppending()
+ {
+ dbus_message_append_iter_init(message.RawMessage, appenderIter);
+ }
+
+ // Get the enumerator
+ public IEnumerator GetEnumerator()
+ {
+ return new ArgumentsEnumerator(this);
+ }
+
+ private class ArgumentsEnumerator : IEnumerator
+ {
+ private Arguments arguments;
+ private bool started = false;
+ private IntPtr iter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
+
+ public ArgumentsEnumerator(Arguments arguments)
+ {
+ this.arguments = arguments;
+ Reset();
+ }
+
+ ~ArgumentsEnumerator()
+ {
+ Marshal.FreeCoTaskMem(iter);
+ }
+
+ public bool MoveNext()
+ {
+ if (started) {
+ return dbus_message_iter_next(iter);
+ } else {
+ started = true;
+ return true;
+ }
+ }
+
+ public void Reset()
+ {
+ dbus_message_iter_init(arguments.message.RawMessage, iter);
+ started = false;
+ }
+
+ public object Current
+ {
+ get
+ {
+ object [] pars = new Object[1];
+ pars[0] = iter;
+
+ Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
+ DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
+
+ // Special case for ObjectPath
+ if (type == typeof(DBusType.ObjectPath)) {
+ ((DBusType.ObjectPath) dbusType).SetService(arguments.message.Service);
+ }
+
+ return dbusType;
+ }
+ }
+ }
+
+ [DllImport("dbus-1")]
+ private extern static void dbus_message_append_iter_init(IntPtr rawMessage, IntPtr iter);
+
+ [DllImport("dbus-1")]
+ private extern static bool dbus_message_iter_has_next(IntPtr iter);
+
+ [DllImport("dbus-1")]
+ private extern static bool dbus_message_iter_next(IntPtr iter);
+
+ [DllImport("dbus-1")]
+ private extern static void dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
+
+ [DllImport("dbus-1")]
+ private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
+ }
+}