dbus/mono/Arguments.cs

295 lines
7.9 KiB
C#
Raw Normal View History

2004-03-23 12:10:32 +00:00
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)
{
dbusType.Append(appenderIter);
}
// Append an argument of the specified type
private void AppendType(Type type, object val)
{
object [] pars = new Object[2];
2004-03-23 12:10:32 +00:00
pars[0] = val;
pars[1] = message.Service;
2004-03-23 12:10:32 +00:00
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)
{
Type constructorType;
if (type.IsArray)
constructorType = typeof (System.Array);
else if (type.IsEnum)
constructorType = Enum.GetUnderlyingType (type);
else
constructorType = type.UnderlyingSystemType;
ConstructorInfo constructor = dbusType.GetConstructor(new Type[] {constructorType, typeof(Service)});
2004-03-23 12:10:32 +00:00
if (constructor == null)
throw new ArgumentException("There is no valid constructor for '" + dbusType + "' from type '" + type + "'");
return constructor;
}
// 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
2004-05-01 19:59:58 +00:00
bool notEmpty = dbus_message_iter_init(message.RawMessage, iter);
2004-03-23 12:10:32 +00:00
2004-05-01 19:59:58 +00:00
if (notEmpty) {
2004-05-01 19:56:27 +00:00
do {
char code = (char) dbus_message_iter_get_arg_type(iter);
if (code == '\0')
return key;
key += code;
} while (dbus_message_iter_next(iter));
}
2004-03-23 12:10:32 +00:00
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;
2004-05-01 19:59:58 +00:00
private bool notEmpty = false;
2004-03-23 12:10:32 +00:00
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;
2004-05-01 19:59:58 +00:00
return notEmpty;
2004-03-23 12:10:32 +00:00
}
}
public void Reset()
{
2004-05-01 19:59:58 +00:00
notEmpty = dbus_message_iter_init(arguments.message.RawMessage, iter);
2004-03-23 12:10:32 +00:00
started = false;
}
public object Current
{
get
{
object [] pars = new Object[2];
2004-03-23 12:10:32 +00:00
pars[0] = iter;
pars[1] = arguments.message.Service;
2004-03-23 12:10:32 +00:00
Type type = (Type) DBusTypes[(char) dbus_message_iter_get_arg_type(iter)];
DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(type, pars);
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")]
2004-05-01 19:56:27 +00:00
private extern static bool dbus_message_iter_init(IntPtr rawMessage, IntPtr iter);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
}
}