First checkin of the Mono bindings.
authorOwen Fraser-Green <owen@discobabe.net>
Tue, 23 Mar 2004 12:10:32 +0000 (12:10 +0000)
committerOwen Fraser-Green <owen@discobabe.net>
Tue, 23 Mar 2004 12:10:32 +0000 (12:10 +0000)
44 files changed:
ChangeLog
Makefile.am
configure.in
dbus-sharp.pc.in [new file with mode: 0644]
mono/Arguments.cs [new file with mode: 0644]
mono/Bus.cs [new file with mode: 0644]
mono/Connection.cs
mono/Custom.cs [new file with mode: 0644]
mono/DBus.cs [deleted file]
mono/DBusException.cs [new file with mode: 0644]
mono/DBusType/Array.cs [new file with mode: 0644]
mono/DBusType/Boolean.cs [new file with mode: 0644]
mono/DBusType/Byte.cs [new file with mode: 0644]
mono/DBusType/Custom.cs [new file with mode: 0644]
mono/DBusType/Dict.cs [new file with mode: 0644]
mono/DBusType/Double.cs [new file with mode: 0644]
mono/DBusType/IDBusType.cs [new file with mode: 0644]
mono/DBusType/Int32.cs [new file with mode: 0644]
mono/DBusType/Int64.cs [new file with mode: 0644]
mono/DBusType/Nil.cs [new file with mode: 0644]
mono/DBusType/ObjectPath.cs [new file with mode: 0644]
mono/DBusType/String.cs [new file with mode: 0644]
mono/DBusType/UInt32.cs [new file with mode: 0644]
mono/DBusType/UInt64.cs [new file with mode: 0644]
mono/Error.cs
mono/Handler.cs [new file with mode: 0644]
mono/InterfaceAttribute.cs [new file with mode: 0644]
mono/Introspector.cs [new file with mode: 0644]
mono/Makefile.am
mono/Message.cs
mono/MethodAttribute.cs [new file with mode: 0644]
mono/MethodCall.cs [new file with mode: 0644]
mono/MethodReturn.cs [new file with mode: 0644]
mono/ProxyBuilder.cs [new file with mode: 0644]
mono/README [new file with mode: 0644]
mono/Server.cs [new file with mode: 0644]
mono/Service.cs [new file with mode: 0644]
mono/Signal.cs [new file with mode: 0644]
mono/TODO [new file with mode: 0644]
mono/Test.cs
mono/example/EchoClient.cs [new file with mode: 0644]
mono/example/EchoServer.cs [new file with mode: 0644]
mono/example/Echoer.cs [new file with mode: 0644]
mono/example/Makefile.am [new file with mode: 0644]

index 194549e..30ae5ad 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2004-03-23  Owen Fraser-Green  <owen@discobabe.net>
+
+       First checkin of mono bindings.
+
+       * configure.in:
+       * Makefile.am:
+       Build stuff for the bindings
+       * dbus-sharp.pc.in: Added for pkgconfig
+       
 2004-03-21  Havoc Pennington  <hp@redhat.com>
 
        * test/test-service.c (main): remove debug spew
index 82fee34..aa6f0ec 100644 (file)
@@ -14,6 +14,7 @@ endif
 
 if DBUS_USE_MCS
    MONO_SUBDIR=mono
+   MONO_PC=dbus-sharp.pc
 endif
 
 if HAVE_PYTHON
@@ -30,16 +31,18 @@ dist-local:
 SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) $(PYTHON_SUBDIR) test tools
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = dbus-1.pc $(GLIB_PC)
+pkgconfig_DATA = dbus-1.pc $(GLIB_PC) $(MONO_PC)
 
 DISTCLEANFILES =               \
        dbus-1.pc               \
-       $(GLIB_PC)
+       $(GLIB_PC)              \
+       $(MONO_PC)
 
 EXTRA_DIST =                   \
        HACKING                 \
        dbus-1.pc.in            \
-       dbus-glib-1.pc.in
+       dbus-glib-1.pc.in       \
+       dbus-sharp.pc.in
 
 all-local: Doxyfile
 
index 5612f30..e92fdb1 100644 (file)
@@ -35,7 +35,7 @@ AC_ARG_ENABLE(doxygen-docs,     [  --enable-doxygen-docs     build DOXYGEN docum
 AC_ARG_ENABLE(gcov,             [  --enable-gcov         compile with coverage profiling instrumentation (gcc only)],enable_gcov=$enableval,enable_gcov=no)
 AC_ARG_ENABLE(abstract-sockets, [  --enable-abstract-sockets  use abstract socket namespace (linux only)],enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)
 AC_ARG_ENABLE(gcj,              [  --enable-gcj          build gcj bindings],enable_gcj=$enableval,enable_gcj=no)
-AC_ARG_ENABLE(mono,             [  --enable-mono         build mono bindings],enable_mono=$enableval,enable_mono=no)
+AC_ARG_ENABLE(mono,             [  --enable-mono         build mono bindings],enable_mono=$enableval,enable_mono=auto)
 AC_ARG_ENABLE(python,           [  --enable-python       build python bindings],enable_python=$enableval,enable_python=auto)
 
 
@@ -1022,6 +1022,7 @@ gcj/org/Makefile
 gcj/org/freedesktop/Makefile
 gcj/org/freedesktop/dbus/Makefile
 mono/Makefile
+mono/example/Makefile
 bus/Makefile
 tools/Makefile
 test/Makefile
@@ -1090,6 +1091,7 @@ echo "
         Building Qt bindings:     ${have_qt}
         Building GLib bindings:   ${have_glib}
         Building Python bindings: ${have_python}
+       Building Mono bindings:   ${enable_mono}
         Building GTK+ tools:      ${have_gtk}
         Building X11 code:        ${enable_x11}
         Building Doxygen docs:    ${enable_doxygen_docs}
diff --git a/dbus-sharp.pc.in b/dbus-sharp.pc.in
new file mode 100644 (file)
index 0000000..c6b7044
--- /dev/null
@@ -0,0 +1,8 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+
+Name: DBus#
+Description: DBus# - D-BUS .NET Bindings
+Version: 0.1
+
diff --git a/mono/Arguments.cs b/mono/Arguments.cs
new file mode 100644 (file)
index 0000000..ac88d6a
--- /dev/null
@@ -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);
+  }
+}
diff --git a/mono/Bus.cs b/mono/Bus.cs
new file mode 100644 (file)
index 0000000..963e819
--- /dev/null
@@ -0,0 +1,51 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  
+  public class Bus
+  {
+    // Keep in sync with C
+    private enum BusType 
+    {
+      Session = 0,
+      System = 1,
+      Activation = 2
+    }
+
+    public static Connection GetSessionBus() 
+    {
+      return GetBus(BusType.Session);
+    }
+
+    public static Connection GetSystemBus()
+    {
+      return GetBus(BusType.System);
+    }
+
+    private static Connection GetBus(BusType busType) 
+    {
+      Error error = new Error();
+      error.Init();
+      
+      IntPtr rawConnection = dbus_bus_get((int) busType, ref error);
+      
+      if (rawConnection != IntPtr.Zero) {
+       Connection connection = Connection.Wrap(rawConnection);
+       connection.SetupWithMain();
+       dbus_connection_unref(rawConnection);
+
+       return connection;
+      } else {
+       throw new DBusException(error);
+      }
+    }
+
+    [DllImport ("dbus-1")]
+    private extern static IntPtr dbus_bus_get (int which, ref Error error);
+
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_unref (IntPtr ptr);
+  }
+}
index 56dcb7a..406e779 100644 (file)
-namespace DBus {
+namespace DBus 
+{
   
   using System;
   using System.Runtime.InteropServices;
   using System.Diagnostics;
+  using System.Reflection;
+  using System.IO;
+  using System.Collections;
   
-  public class Connection {
+  public class Connection 
+  {
+    /// <summary>
+    /// A pointer to the underlying Connection structure
+    /// </summary>
+    private IntPtr rawConnection;
+    
+    /// <summary>
+    /// The current slot number
+    /// </summary>
+    private static int slot = -1;
+    
+    private int timeout = -1;
 
-    public Connection (string address) {
+    internal Connection(IntPtr rawConnection)
+    {
+      RawConnection = rawConnection;
+    }
+    
+    public Connection(string address)
+    {
       // the assignment bumps the refcount
-      Error error = new Error ();
-      error.Init ();
-      raw = dbus_connection_open (address, ref error);
-      if (raw != IntPtr.Zero) {
-        dbus_connection_unref (raw);
+      Error error = new Error();
+      error.Init();
+      RawConnection = dbus_connection_open(address, ref error);
+      if (RawConnection != IntPtr.Zero) {
+       dbus_connection_unref(RawConnection);
       } else {
-        Exception e = new Exception (ref error);
-        error.Free ();
-        throw e;
+       throw new DBusException(error);
       }
-      dbus_connection_setup_with_g_main (raw, IntPtr.Zero);
-    }
 
-    // Keep in sync with C
-    public enum BusType {
-      Session = 0,
-      System = 1,
-      Activation = 2
+      SetupWithMain();
     }
 
-    public static Connection GetBus (BusType bus) {
-      Error error = new Error ();
-
-      error.Init ();
-      
-      IntPtr ptr = dbus_bus_get ((int) bus, ref error);
-      if (ptr != IntPtr.Zero) {
-        Connection c = Wrap (ptr);
-        dbus_connection_unref (ptr);
-        return c;
-      } else {
-        Exception e = new Exception (ref error);
-        error.Free ();
-        throw e;   
-      }
+    public void SetupWithMain() 
+    {      
+      dbus_connection_setup_with_g_main(RawConnection, IntPtr.Zero);
     }
     
-    public void Send (Message m,
-                      ref int serial) {
-      if (!dbus_connection_send (raw, m.raw, ref serial))
-        throw new OutOfMemoryException ();
-    }
-
-    public void Send (Message m) {
-      int ignored = 0;
-      Send (m, ref ignored);
-    }
-
-    public void Flush () {
-      dbus_connection_flush (raw);
-    }
-
-    public void Disconnect () {
-      dbus_connection_disconnect (raw);
+    ~Connection () 
+    {
+      if (RawConnection != IntPtr.Zero) 
+       {
+         dbus_connection_disconnect(rawConnection);
+       }
+      RawConnection = IntPtr.Zero; // free the native object
     }
     
-    public static Connection Wrap (IntPtr ptr) {
-      IntPtr gch_ptr;
-      
-      gch_ptr = dbus_connection_get_data (ptr, wrapper_slot);
-      if (gch_ptr != IntPtr.Zero) {
-        return (DBus.Connection) ((GCHandle)gch_ptr).Target;
-      } else {
-        return new Connection (ptr);
-      }
-    }
-
-    // surely there's a convention for this pattern with the property
-    // and the real member
-    IntPtr raw_;
-    internal IntPtr raw {
-      get {
-        return raw_; 
-      }
-      set {
-        if (value == raw_)
-          return;
-        
-        if (raw_ != IntPtr.Zero) {
-          IntPtr gch_ptr;
-          
-          gch_ptr = dbus_connection_get_data (raw_,
-                                              wrapper_slot);
-          Debug.Assert (gch_ptr != IntPtr.Zero);
-
-          dbus_connection_set_data (raw_, wrapper_slot,
-                                    IntPtr.Zero, IntPtr.Zero);
-          
-          ((GCHandle) gch_ptr).Free ();
-          
-          dbus_connection_unref (raw_);
-        }
-        
-        raw_ = value;
-
-        if (raw_ != IntPtr.Zero) {
-          GCHandle gch;
-
-          dbus_connection_ref (raw_);
-
-          // We store a weak reference to the C# object on the C object
-          gch = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection);
-          
-          dbus_connection_set_data (raw_, wrapper_slot,
-                                    (IntPtr) gch, IntPtr.Zero);
-        }
-      }
+    internal static Connection Wrap(IntPtr rawConnection) 
+    {
+      if (slot > -1) {
+       // If we already have a Connection object associated with this rawConnection then return it
+       IntPtr rawThis = dbus_connection_get_data (rawConnection, slot);
+       return (DBus.Connection) ((GCHandle)rawThis).Target;
+      } 
+      else 
+       {
+         // If it doesn't exist then create a new connection around it
+         return new Connection(rawConnection);
+       }
     }
 
-    ~Connection () {
-      if (raw != IntPtr.Zero) {
-        Disconnect ();
-      }
-      raw = IntPtr.Zero; // free the native object
+    public int Timeout
+    {
+      get
+       {
+         return this.timeout;
+       }
+      set
+       {
+         this.timeout = value;
+       }
     }
     
-    Connection (IntPtr r) {
-      raw = r;
+    private int Slot
+    {
+      get 
+       {
+         if (slot == -1) 
+           {
+             // We need to initialize the slot
+             if (!dbus_connection_allocate_data_slot (ref slot))
+               throw new OutOfMemoryException ();
+             
+             Debug.Assert (slot >= 0);
+           }
+         
+         return slot;
+       }
     }
     
-    // static constructor runs before any methods 
-    static Connection () {
-      DBus.Internals.Init ();
-      
-      Debug.Assert (wrapper_slot == -1);
-      
-      if (!dbus_connection_allocate_data_slot (ref wrapper_slot))
-        throw new OutOfMemoryException ();
-
-      Debug.Assert (wrapper_slot >= 0);
+    internal IntPtr RawConnection 
+    {
+      get 
+       {
+         return rawConnection;
+       }
+      set 
+       {
+         if (value == rawConnection)
+           return;
+         
+         if (rawConnection != IntPtr.Zero) 
+           {
+             // Get the reference to this
+             IntPtr rawThis = dbus_connection_get_data (rawConnection, Slot);
+             Debug.Assert (rawThis != IntPtr.Zero);
+             
+             // Blank over the reference
+             dbus_connection_set_data (rawConnection, Slot, IntPtr.Zero, IntPtr.Zero);
+             
+             // Free the reference
+             ((GCHandle) rawThis).Free();
+             
+             // Unref the connection
+             dbus_connection_unref(rawConnection);
+           }
+         
+         this.rawConnection = value;
+         
+         if (rawConnection != IntPtr.Zero) 
+           {
+             GCHandle rawThis;
+             
+             dbus_connection_ref (rawConnection);
+             
+             // We store a weak reference to the C# object on the C object
+             rawThis = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection);
+             
+             dbus_connection_set_data(rawConnection, Slot, (IntPtr) rawThis, IntPtr.Zero);
+           }
+       }
     }
 
-    // slot used to store the C# object on the C object
-    static int wrapper_slot = -1;
+    [DllImport("dbus-glib-1")]
+    private extern static void dbus_connection_setup_with_g_main(IntPtr rawConnection,
+                                                            IntPtr rawContext);
     
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_open")]
-      private extern static IntPtr dbus_connection_open (string address,
-                                                         ref Error error);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_unref")]
-      private extern static void dbus_connection_unref (IntPtr ptr);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_ref")]
-      private extern static void dbus_connection_ref (IntPtr ptr);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_allocate_data_slot")]
-      private extern static bool dbus_connection_allocate_data_slot (ref int slot);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_free_data_slot")]
-      private extern static void dbus_connection_free_data_slot (ref int slot);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_set_data")]
-      private extern static bool dbus_connection_set_data (IntPtr ptr,
-                                                           int    slot,
-                                                           IntPtr data,
-                                                           IntPtr free_data_func);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_send")]
-      private extern static bool dbus_connection_send (IntPtr  ptr,
-                                                       IntPtr  message,
-                                                       ref int client_serial);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_flush")]
-      private extern static void dbus_connection_flush (IntPtr  ptr);
+    [DllImport ("dbus-1")]
+    private extern static IntPtr dbus_connection_open (string address, ref Error error);
     
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_bus_get")]
-      private extern static IntPtr dbus_bus_get (int        which,
-                                                 ref Error  error);
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_unref (IntPtr ptr);
     
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_get_data")]
-      private extern static IntPtr dbus_connection_get_data (IntPtr ptr,
-                                                             int    slot);
-
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_connection_disconnect")]
-      private extern static void dbus_connection_disconnect (IntPtr ptr);
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_ref (IntPtr ptr);
+    
+    [DllImport ("dbus-1")]
+    private extern static bool dbus_connection_allocate_data_slot (ref int slot);
+    
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_free_data_slot (ref int slot);
+    
+    [DllImport ("dbus-1")]
+    private extern static bool dbus_connection_set_data (IntPtr ptr,
+                                                        int    slot,
+                                                        IntPtr data,
+                                                        IntPtr free_data_func);
+    
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_flush (IntPtr  ptr);
     
-    [DllImport (DBus.Internals.DBusGLibname, EntryPoint="dbus_connection_setup_with_g_main")]
-      private extern static void dbus_connection_setup_with_g_main (IntPtr ptr,
-                                                                    IntPtr context);
+    [DllImport ("dbus-1")]
+    private extern static IntPtr dbus_connection_get_data (IntPtr ptr,
+                                                          int    slot);
     
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_disconnect (IntPtr ptr);
   }
 }
diff --git a/mono/Custom.cs b/mono/Custom.cs
new file mode 100644 (file)
index 0000000..f96562b
--- /dev/null
@@ -0,0 +1,18 @@
+using System;
+
+using DBus;
+
+namespace DBus
+{
+  public struct Custom
+  {
+    public string Name;
+    public byte[] Data;
+    
+    public Custom(string name, byte[] data) 
+    {
+      Name = name;
+      Data = data;
+    }
+  }
+}
diff --git a/mono/DBus.cs b/mono/DBus.cs
deleted file mode 100644 (file)
index 377af74..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace DBus {
-
-  using System;
-  using System.Runtime.InteropServices;
-  
-  public class Exception : ApplicationException {
-    internal Exception (ref Error error)
-      : base (Runtime.InteropServices.Marshal.PtrToStringAnsi (error.message)) { }
-  }
-  
-  internal class Internals {
-    internal const string DBusLibname = "libdbus-1.so.0";
-    internal const string DBusGLibname = "libdbus-glib-1.so.0";
-    internal const string GLibname = "libglib-2.0.so.0";
-    internal const string GThreadname = "libgthread-2.0.so.0";
-    
-    internal static void Init () {
-        dbus_gthread_init ();
-    }
-    
-    [DllImport (DBus.Internals.DBusGLibname, EntryPoint="dbus_gthread_init")]
-      private extern static void dbus_gthread_init ();
-  }
-}
diff --git a/mono/DBusException.cs b/mono/DBusException.cs
new file mode 100644 (file)
index 0000000..5c912cc
--- /dev/null
@@ -0,0 +1,12 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  
+  public class DBusException : ApplicationException 
+  {
+    internal DBusException (Error error) : base (error.Message) { 
+      error.Free();
+    }
+  }
+}
diff --git a/mono/DBusType/Array.cs b/mono/DBusType/Array.cs
new file mode 100644 (file)
index 0000000..3bce3af
--- /dev/null
@@ -0,0 +1,130 @@
+using System;
+using System.Collections;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// Array.
+  /// </summary>
+  public class Array : IDBusType
+  {
+    public const char Code = 'a';
+    private System.Array val;
+    private ArrayList elements;
+    private Type elementType;
+    
+    private Array()
+    {
+    }
+    
+    public Array(System.Array val) 
+    {
+      this.val = val;
+      this.elementType = Arguments.MatchType(val.GetType().UnderlyingSystemType);
+    }
+
+    public Array(IntPtr iter)
+    {
+      IntPtr arrayIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
+      
+      int elementTypeCode;
+      dbus_message_iter_init_array_iterator(iter, arrayIter, out elementTypeCode);
+      this.elementType = (Type) Arguments.DBusTypes[(char) elementTypeCode];
+
+      elements = new ArrayList();
+
+      do {
+       object [] pars = new Object[1];
+       pars[0] = arrayIter;
+       DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
+       elements.Add(dbusType);
+      } while (dbus_message_iter_next(arrayIter));
+      
+      Marshal.FreeCoTaskMem(arrayIter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      IntPtr arrayIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
+
+      if (!dbus_message_iter_append_array(iter,
+                                         arrayIter,
+                                         (int) Arguments.GetCode(this.elementType))) {
+       throw new ApplicationException("Failed to append INT32 argument:" + val);
+      }
+
+      foreach (object element in this.val) {
+       object [] pars = new Object[1];
+       pars[0] = element;
+       DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
+       dbusType.Append(arrayIter);
+      }
+
+      Marshal.FreeCoTaskMem(arrayIter);
+    }    
+
+    public static bool Suits(System.Type type) 
+    {
+      if (type.IsArray) {
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_Ref);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Castclass, type);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_Ref);
+      }
+    }
+    
+    public object Get() 
+    {
+      throw new ArgumentException("Cannot call Get on an Array without specifying type.");
+    }
+
+    public object Get(System.Type type)
+    {
+      if (Arguments.Suits(elementType, type.UnderlyingSystemType)) {
+       this.val = System.Array.CreateInstance(type.UnderlyingSystemType, elements.Count);
+       int i = 0;
+       foreach (DBusType.IDBusType element in elements) {
+         this.val.SetValue(element.Get(type.UnderlyingSystemType), i++);
+       }       
+      } else {
+       throw new ArgumentException("Cannot cast DBus.Type.Array to type '" + type.ToString() + "'");
+      }
+       
+       return this.val;
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static void dbus_message_iter_init_array_iterator(IntPtr iter,
+                                                                    IntPtr arrayIter,
+                                                                    out int elementType);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_array(IntPtr iter, 
+                                                             IntPtr arrayIter,
+                                                             int elementType);
+
+    [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);
+  }
+}
diff --git a/mono/DBusType/Boolean.cs b/mono/DBusType/Boolean.cs
new file mode 100644 (file)
index 0000000..ef8ed49
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// Boolean
+  /// </summary>
+  public class Boolean : IDBusType
+  {
+    public const char Code = 'b';
+    private System.Boolean val;
+    
+    private Boolean()
+    {
+    }
+    
+    public Boolean(System.Boolean val) 
+    {
+      this.val = val;
+    }
+
+    public Boolean(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_boolean(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_boolean(iter, val))
+       throw new ApplicationException("Failed to append BOOLEAN argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.Boolean":
+      case "System.Boolean&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_I1);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_I1);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I1);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) {
+      case "System.Boolean":
+      case "System.Boolean&":
+       return this.val;
+      default:
+       throw new ArgumentException("Cannot cast DBus.Type.Boolean to type '" + type.ToString() + "'");
+      }
+    }
+
+    [DllImport("dbus-1")]
+    private extern static System.Boolean dbus_message_iter_get_boolean(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_boolean(IntPtr iter, System.Boolean value);
+  }
+}
diff --git a/mono/DBusType/Byte.cs b/mono/DBusType/Byte.cs
new file mode 100644 (file)
index 0000000..eaffd26
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// Byte
+  /// </summary>
+  public class Byte : IDBusType
+  {
+    public const char Code = 'y';
+    private System.Byte val;
+    
+    private Byte()
+    {
+    }
+    
+    public Byte(System.Byte val) 
+    {
+      this.val = val;
+    }
+
+    public Byte(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_byte(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_byte(iter, val))
+       throw new ApplicationException("Failed to append BYTE argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.Byte":
+      case "System.Byte&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_U1);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_U1);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I1);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) {
+      case "System.Byte":
+      case "System.Byte&":
+       return this.val;
+      default:
+       throw new ArgumentException("Cannot cast DBus.Type.Byte to type '" + type.ToString() + "'");
+      }
+    }
+
+    [DllImport("dbus-1")]
+    private extern static System.Byte dbus_message_iter_get_byte(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_byte(IntPtr iter, System.Byte value);
+  }
+}
diff --git a/mono/DBusType/Custom.cs b/mono/DBusType/Custom.cs
new file mode 100644 (file)
index 0000000..d3eb762
--- /dev/null
@@ -0,0 +1,109 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// A named byte array, used for custom types.
+  /// </summary>
+  public class Custom : IDBusType
+  {
+    public const char Code = 'c';
+    private DBus.Custom val;
+    
+    private Custom()
+    {
+    }
+    
+    public Custom(DBus.Custom val) 
+    {
+      this.val = val;
+    }
+
+    public Custom(IntPtr iter)
+    {
+      string name;
+      IntPtr value;
+      int len;
+
+      if (!dbus_message_iter_get_custom(iter, out name, out value, out len)) {
+       throw new ApplicationException("Failed to get CUSTOM argument.");
+      }
+
+      this.val.Name = name;
+      this.val.Data = new byte[len];
+      Marshal.Copy(value, this.val.Data, 0, len);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      IntPtr data = Marshal.AllocCoTaskMem(this.val.Data.Length);
+      try {
+       Marshal.Copy(this.val.Data, 0, data, this.val.Data.Length);
+       if (!dbus_message_iter_append_custom(iter, this.val.Name, data, this.val.Data.Length)) {
+         throw new ApplicationException("Failed to append CUSTOM argument:" + val);
+       }
+      } finally {
+       Marshal.FreeCoTaskMem(data);
+      }
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "DBus.Custom":
+      case "DBus.Custom&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldobj, type);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldobj, type);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stobj, type);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) {
+      case "DBus.Custom":
+      case "DBus.Custom&":
+       return this.val;
+      default:
+       throw new ArgumentException("Cannot cast DBus.Type.Custom to type '" + type.ToString() + "'");
+      }
+    }
+
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_get_custom(IntPtr iter,
+                                                           out string name,
+                                                           out IntPtr value,
+                                                           out int len);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_custom(IntPtr iter, 
+                                                              string name,
+                                                              IntPtr data,
+                                                              int len);
+  }
+}
diff --git a/mono/DBusType/Dict.cs b/mono/DBusType/Dict.cs
new file mode 100644 (file)
index 0000000..e6fce15
--- /dev/null
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// Dict.
+  /// </summary>
+  public class Dict : IDBusType
+  {
+    public const char Code = 'm';
+    private Hashtable val;
+    
+    private Dict()
+    {
+    }
+    
+    public Dict(IDictionary val)
+    {
+      this.val = new Hashtable();
+      foreach (DictionaryEntry entry in val) {
+       this.val.Add(entry.Key, entry.Value);
+      }
+    }
+
+    public Dict(IntPtr iter)
+    {
+      IntPtr dictIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
+      
+      dbus_message_iter_init_dict_iterator(iter, dictIter);
+
+      this.val = new Hashtable();
+
+      do {
+       string key = dbus_message_iter_get_dict_key(dictIter);
+
+       // Get the argument type and get the value
+       Type elementType = (Type) DBus.Arguments.DBusTypes[(char) dbus_message_iter_get_arg_type(dictIter)];
+       object [] pars = new Object[1];
+       pars[0] = dictIter;
+       DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
+       this.val.Add(key, dbusType);
+      } while (dbus_message_iter_next(dictIter));
+      
+      Marshal.FreeCoTaskMem(dictIter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      IntPtr dictIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
+
+      if (!dbus_message_iter_append_dict(iter,
+                                        dictIter)) {
+       throw new ApplicationException("Failed to append DICT argument:" + val);
+      }
+
+      foreach (DictionaryEntry entry in this.val) {
+       if (!dbus_message_iter_append_dict_key(dictIter, (string) entry.Key)) {
+         throw new ApplicationException("Failed to append DICT key:" + entry.Key);
+       }
+       
+       // Get the element type
+       Type elementType = Arguments.MatchType(entry.Value.GetType());
+       object [] pars = new Object[1];
+       pars[0] = entry.Value;
+       DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
+       dbusType.Append(dictIter);
+      }
+
+      Marshal.FreeCoTaskMem(dictIter);
+    }    
+
+    public static bool Suits(System.Type type) 
+    {
+      if (typeof(IDictionary).IsAssignableFrom(type)) {
+       return true;
+      }
+            
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_Ref);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Castclass, type);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_Ref);
+      }
+    }
+    
+    public object Get() 
+    {
+      return Get(typeof(Hashtable));
+    }
+
+    public object Get(System.Type type)
+    {
+      IDictionary retVal;
+
+      if (Suits(type)) {
+       retVal = (IDictionary) Activator.CreateInstance(type, new object[0]);
+       foreach (DictionaryEntry entry in this.val) {
+         retVal.Add(entry.Key, ((IDBusType) entry.Value).Get());
+       }
+      } else {
+       throw new ArgumentException("Cannot cast DBus.Type.Dict to type '" + type.ToString() + "'");
+      }
+       
+      return retVal;
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static void dbus_message_iter_init_dict_iterator(IntPtr iter,
+                                                                   IntPtr dictIter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_dict(IntPtr iter, 
+                                                            IntPtr dictIter);
+
+    [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 string dbus_message_iter_get_dict_key (IntPtr dictIter);  
+
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_dict_key (IntPtr dictIter,
+                                                                 string value);
+    [DllImport("dbus-1")]
+    private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
+  }
+}
diff --git a/mono/DBusType/Double.cs b/mono/DBusType/Double.cs
new file mode 100644 (file)
index 0000000..d578822
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// IEEE 754 double
+  /// </summary>
+  public class Double : IDBusType
+  {
+    public const char Code = 'd';
+    private System.Double val;
+    
+    private Double()
+    {
+    }
+    
+    public Double(System.Double val) 
+    {
+      this.val = val;
+    }
+
+    public Double(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_double(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_double(iter, val))
+       throw new ApplicationException("Failed to append DOUBLE argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.Double":
+      case "System.Double&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_R8);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_R8);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_R8);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) {
+      case "System.Double":
+      case "System.Double&":
+       return this.val;
+      default:
+       throw new ArgumentException("Cannot cast DBus.Type.Double to type '" + type.ToString() + "'");
+      }
+    }
+
+    [DllImport("dbus-1")]
+    private extern static System.Double dbus_message_iter_get_double(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_double(IntPtr iter, System.Double value);
+  }
+}
diff --git a/mono/DBusType/IDBusType.cs b/mono/DBusType/IDBusType.cs
new file mode 100644 (file)
index 0000000..447c820
--- /dev/null
@@ -0,0 +1,16 @@
+using System;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// Base class for DBusTypes
+  /// </summary>
+  public interface IDBusType
+  {
+    object Get();
+    
+    object Get(System.Type type);  
+
+    void Append(IntPtr iter);
+  }
+}
diff --git a/mono/DBusType/Int32.cs b/mono/DBusType/Int32.cs
new file mode 100644 (file)
index 0000000..b617a9a
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// 32-bit integer.
+  /// </summary>
+  public class Int32 : IDBusType
+  {
+    public const char Code = 'i';
+    private System.Int32 val;
+    
+    private Int32()
+    {
+    }
+    
+    public Int32(System.Int32 val) 
+    {
+      this.val = val;
+    }
+
+    public Int32(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_int32(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_int32(iter, val))
+       throw new ApplicationException("Failed to append INT32 argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.Int32":
+      case "System.Int32&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_I4);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_I4);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I4);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) {
+      case "System.Int32":
+      case "System.Int32&":
+       return this.val;
+      default:
+       throw new ArgumentException("Cannot cast DBus.Type.Int32 to type '" + type.ToString() + "'");
+      }
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static System.Int32 dbus_message_iter_get_int32(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_int32(IntPtr iter, System.Int32 value);
+  }
+}
diff --git a/mono/DBusType/Int64.cs b/mono/DBusType/Int64.cs
new file mode 100644 (file)
index 0000000..0905af7
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// 64-bit integer.
+  /// </summary>
+  public class Int64 : IDBusType
+  {
+    public const char Code = 'x';
+    private System.Int64 val;
+    
+    private Int64()
+    {
+    }
+    
+    public Int64(System.Int64 val) 
+    {
+      this.val = val;
+    }
+
+    public Int64(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_int64(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_int64(iter, val))
+       throw new ApplicationException("Failed to append INT64 argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.Int64":
+      case "System.Int64&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_I8);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_I8);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I8);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) {
+      case "System.Int64":
+      case "System.Int64&":
+       return this.val;
+      default:
+       throw new ArgumentException("Cannot cast DBus.Type.Int64 to type '" + type.ToString() + "'");
+      }
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static System.Int64 dbus_message_iter_get_int64(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_int64(IntPtr iter, System.Int64 value);
+  }
+}
diff --git a/mono/DBusType/Nil.cs b/mono/DBusType/Nil.cs
new file mode 100644 (file)
index 0000000..e39b64a
--- /dev/null
@@ -0,0 +1,68 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// Marks a "void"/"unset"/"nonexistent"/"null" argument.
+  /// </summary>
+  public class Nil : IDBusType
+  {
+    public const char Code = 'v';
+    
+    private Nil()
+    {
+    }
+    
+    public Nil(object nil) 
+    {
+    }
+
+    public Nil(IntPtr iter)
+    {
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_nil(iter))
+       throw new ApplicationException("Failed to append NIL argument");
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_I1);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_I1);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I1);
+      }
+    }
+    
+    public object Get() 
+    {
+      return null;
+    }
+
+    public object Get(System.Type type)
+    {
+      throw new ArgumentException("Cannot cast DBus.Type.Nil to type '" + type.ToString() + "'");
+    }
+
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_nil(IntPtr iter);
+  }
+}
diff --git a/mono/DBusType/ObjectPath.cs b/mono/DBusType/ObjectPath.cs
new file mode 100644 (file)
index 0000000..e20ae18
--- /dev/null
@@ -0,0 +1,110 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// An object path.
+  /// </summary>
+  public class ObjectPath : IDBusType
+  {
+    public const char Code = 'o';
+    private string pathName = null;
+    private object val = null;
+    private Service service = null;
+    
+    private ObjectPath()
+    {
+    }
+    
+    public ObjectPath(object val) 
+    {
+      this.val = val;
+    }
+    
+    public ObjectPath(IntPtr iter)
+    {
+      
+      this.pathName = Marshal.PtrToStringAnsi(dbus_message_iter_get_object_path(iter));
+    }
+
+    public void SetService(Service service) 
+    {
+      this.service = service;
+    }
+
+    private string PathName 
+    {
+      get {
+       if (this.pathName == null && this.val != null) {
+         Handler handler = this.service.GetHandler(this.val);
+         this.pathName = handler.PathName;
+       }
+       
+       return this.pathName;
+      }
+    }
+
+    public void Append(IntPtr iter) 
+    {
+      if (PathName == null) {
+       throw new ApplicationException("Unable to append ObjectPath before calling SetService()");
+      }
+      
+      if (!dbus_message_iter_append_object_path(iter, Marshal.StringToHGlobalAnsi(PathName)))
+       throw new ApplicationException("Failed to append OBJECT_PATH argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      object[] attributes = type.GetCustomAttributes(typeof(InterfaceAttribute), true);
+      if (attributes.Length == 1) {
+       return true;
+      } else {
+       return false;
+      }
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_Ref);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Castclass, type);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_Ref);
+      }
+    }
+
+    public object Get() 
+    {
+      throw new ArgumentException("Cannot call Get on an ObjectPath without specifying type.");
+    }
+
+    public object Get(System.Type type)
+    {
+      if (this.service == null) {
+       throw new ApplicationException("Unable to get ObjectPath before calling SetService()");
+      }
+      
+      try {
+       return this.service.GetObject(type, PathName);
+      } catch(Exception ex) {
+       throw new ArgumentException("Cannot cast object pointed to by Object Path to type '" + type.ToString() + "': " + ex);
+      }
+    }
+
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_iter_get_object_path(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_object_path(IntPtr iter, IntPtr pathName);
+  }
+}
diff --git a/mono/DBusType/String.cs b/mono/DBusType/String.cs
new file mode 100644 (file)
index 0000000..1eda1f2
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// A string.
+  /// </summary>
+  public class String : IDBusType
+  {
+    public const char Code = 's';
+    private string val;
+    
+    private String()
+    {
+    }
+    
+    public String(string val) 
+    {
+      this.val = val;
+    }
+    
+    public String(IntPtr iter)
+    {
+      this.val = Marshal.PtrToStringAnsi(dbus_message_iter_get_string(iter));
+    }
+
+    public void Append(IntPtr iter) 
+    {
+      if (!dbus_message_iter_append_string(iter, Marshal.StringToHGlobalAnsi(val)))
+       throw new ApplicationException("Failed to append STRING argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.String":
+      case "System.String&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_Ref);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Castclass, type);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_Ref);
+      }
+    }
+
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) 
+       {
+       case "System.String":
+       case "System.String&":
+         return this.val;
+       default:
+         throw new ArgumentException("Cannot cast DBus.Type.String to type '" + type.ToString() + "'");
+       }
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_iter_get_string(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_string(IntPtr iter, IntPtr value);
+  }
+}
diff --git a/mono/DBusType/UInt32.cs b/mono/DBusType/UInt32.cs
new file mode 100644 (file)
index 0000000..9c0e350
--- /dev/null
@@ -0,0 +1,87 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// 32-bit unsigned integer.
+  /// </summary>
+  public class UInt32 : IDBusType
+  {
+    public const char Code = 'u';
+    private System.UInt32 val;
+    
+    private UInt32()
+    {
+    }
+    
+    public UInt32(System.UInt32 val) 
+    {
+      this.val = val;
+    }
+
+    public UInt32(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_uint32(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_uint32(iter, val))
+       throw new ApplicationException("Failed to append UINT32 argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.UInt32":
+      case "System.UInt32&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_U4);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_U4);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I4);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) 
+       {
+       case "System.UInt32":
+       case "System.UInt32&":
+         return this.val;
+       default:
+         throw new ArgumentException("Cannot cast DBus.Type.UInt32 to type '" + type.ToString() + "'");
+       }
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static System.UInt32 dbus_message_iter_get_uint32(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_uint32(IntPtr iter, System.UInt32 value);
+  }
+}
diff --git a/mono/DBusType/UInt64.cs b/mono/DBusType/UInt64.cs
new file mode 100644 (file)
index 0000000..2e47479
--- /dev/null
@@ -0,0 +1,87 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection.Emit;
+
+using DBus;
+
+namespace DBus.DBusType
+{
+  /// <summary>
+  /// 64-bit unsigned integer.
+  /// </summary>
+  public class UInt64 : IDBusType
+  {
+    public const char Code = 't';
+    private System.UInt64 val;
+    
+    private UInt64()
+    {
+    }
+    
+    public UInt64(System.UInt64 val) 
+    {
+      this.val = val;
+    }
+
+    public UInt64(IntPtr iter)
+    {
+      this.val = dbus_message_iter_get_uint64(iter);
+    }
+    
+    public void Append(IntPtr iter)
+    {
+      if (!dbus_message_iter_append_uint64(iter, val))
+       throw new ApplicationException("Failed to append UINT64 argument:" + val);
+    }
+
+    public static bool Suits(System.Type type) 
+    {
+      switch (type.ToString()) {
+      case "System.UInt64":
+      case "System.UInt64&":
+       return true;
+      }
+      
+      return false;
+    }
+
+    public static void EmitMarshalIn(ILGenerator generator, Type type)
+    {
+      if (type.IsByRef) {
+       generator.Emit(OpCodes.Ldind_I8);
+      }
+    }
+
+    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
+    {
+      generator.Emit(OpCodes.Unbox, type);
+      generator.Emit(OpCodes.Ldind_I8);
+      if (!isReturn) {
+       generator.Emit(OpCodes.Stind_I8);
+      }
+    }
+    
+    public object Get() 
+    {
+      return this.val;
+    }
+
+    public object Get(System.Type type)
+    {
+      switch (type.ToString()) 
+       {
+       case "System.UInt64":
+       case "System.UInt64&":
+         return this.val;
+       default:
+         throw new ArgumentException("Cannot cast DBus.Type.UInt64 to type '" + type.ToString() + "'");
+       }
+    }    
+
+    [DllImport("dbus-1")]
+    private extern static System.UInt64 dbus_message_iter_get_uint64(IntPtr iter);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_iter_append_uint64(IntPtr iter, System.UInt64 value);
+  }
+}
index dab4df1..d89a013 100644 (file)
@@ -1,29 +1,60 @@
-namespace DBus {
-
+namespace DBus 
+{
+  
   using System;
   using System.Runtime.InteropServices;
+  using System.Diagnostics;
   
   // FIXME add code to verify that size of DBus.Error
   // matches the C code.
-
+  
   [StructLayout (LayoutKind.Sequential)]
-  internal struct Error {
+  internal struct Error
+  {
     internal IntPtr name;
     internal IntPtr message;
     private int dummies;
     private IntPtr padding1;
-
-    internal void Init () {
-      dbus_error_init (ref this);
+    
+    public void Init() 
+    {
+      dbus_error_init(ref this);
+    }
+    
+    public void Free() 
+    {
+      dbus_error_free(ref this);
     }
     
-    internal void Free () {
-      dbus_error_free (ref this);
+    public string Message
+    {
+      get
+       {
+         return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(message);
+       }
     }
     
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_error_init")]
+    public string Name
+    {
+      get
+       {
+         return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name);
+       }
+    }
+
+    public bool IsSet
+    {
+      get
+       {
+         return (name != IntPtr.Zero);
+       }
+    }
+    
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_error_init")]
     private extern static void dbus_error_init (ref Error error);
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_error_free")]
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_error_free")]
     private extern static void dbus_error_free (ref Error error);
   }
 }
diff --git a/mono/Handler.cs b/mono/Handler.cs
new file mode 100644 (file)
index 0000000..d565b7e
--- /dev/null
@@ -0,0 +1,256 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  using System.Reflection;
+  using System.Collections;
+
+  internal class Handler
+  {
+    private string[] path = null;
+    private string pathName = null;
+    private Introspector introspector = null;
+    private object handledObject = null;
+    private Hashtable handledMethods = null;
+    private DBusObjectPathVTable vTable;
+    private Connection connection;
+    private Service service;
+    private DBusHandleMessageFunction filterCalled;
+    
+    internal delegate void DBusObjectPathUnregisterFunction(IntPtr rawConnection,
+                                                           IntPtr userData);
+
+    internal delegate int DBusObjectPathMessageFunction(IntPtr rawConnection,
+                                                       IntPtr rawMessage,
+                                                       IntPtr userData);
+
+    internal delegate int DBusHandleMessageFunction(IntPtr rawConnection,
+                                                   IntPtr rawMessage,
+                                                   IntPtr userData);
+
+
+    private enum Result 
+    {
+      Handled = 0,
+      NotYetHandled = 1,
+      NeedMemory = 2
+    }
+
+    [StructLayout (LayoutKind.Sequential)]
+    private struct DBusObjectPathVTable 
+    {
+      public DBusObjectPathUnregisterFunction unregisterFunction;
+      public DBusObjectPathMessageFunction messageFunction;
+      public IntPtr padding1;
+      public IntPtr padding2;
+      public IntPtr padding3;
+      public IntPtr padding4;
+    
+      public DBusObjectPathVTable(DBusObjectPathUnregisterFunction unregisterFunction,
+                                 DBusObjectPathMessageFunction messageFunction) 
+      {
+       this.unregisterFunction = unregisterFunction;
+       this.messageFunction = messageFunction;
+       this.padding1 = IntPtr.Zero;
+       this.padding2 = IntPtr.Zero;
+       this.padding3 = IntPtr.Zero;
+       this.padding4 = IntPtr.Zero;
+      }
+    }
+
+    ~Handler() 
+    {
+      if (Connection != null && Connection.RawConnection != IntPtr.Zero && path != null) {
+       dbus_connection_unregister_object_path(Connection.RawConnection,
+                                              Path);
+      } 
+    }
+
+    public Handler(object handledObject, 
+                      string pathName, 
+                      Service service)
+    {
+      Service = service;
+      Connection = service.Connection;
+      HandledObject = handledObject;
+
+      // Strip the leading / off if there is one and get the path as an array
+      pathName = pathName.TrimStart('/');
+      this.path = pathName.Split('/');
+      this.pathName = "/" + pathName;
+
+      // Create the vTable and register the path
+      vTable = new DBusObjectPathVTable(new DBusObjectPathUnregisterFunction(Unregister_Called), 
+                                       new DBusObjectPathMessageFunction(Message_Called));
+      
+      if (!dbus_connection_register_object_path(Connection.RawConnection,
+                                               Path,
+                                               ref vTable,
+                                               IntPtr.Zero))
+       throw new OutOfMemoryException();
+      
+      // Setup the filter function
+      this.filterCalled = new DBusHandleMessageFunction(Filter_Called);
+      if (!dbus_connection_add_filter(Connection.RawConnection,
+                                     this.filterCalled,
+                                     IntPtr.Zero,
+                                     IntPtr.Zero))
+       throw new OutOfMemoryException();
+    }
+
+    private void RegisterMethod(MethodInfo method) 
+    {
+      string key = method.Name + " " + Arguments.ParseParameters(method);
+      handledMethods.Add(key, method);
+    }
+
+    public object HandledObject 
+    {
+      get 
+       {
+         return this.handledObject;
+       }
+      
+      set
+       {
+         this.handledObject = value;
+
+         object[] attributes;
+
+         // Register the methods
+         this.handledMethods = new Hashtable();
+         this.introspector = new Introspector(value.GetType());
+         
+         foreach (MethodInfo method in this.introspector.Methods) {
+           RegisterMethod(method);
+         }  
+       }
+    }
+    
+    public int Filter_Called(IntPtr rawConnection,
+                            IntPtr rawMessage,
+                            IntPtr userData) 
+    {
+      Message message = Message.Wrap(rawMessage, Service);
+      
+      if (message.Type == Message.MessageType.Signal) {
+       Signal signal = (Signal) message;
+      } else if (message.Type == Message.MessageType.MethodCall) {
+       MethodCall methodCall = (MethodCall) message;
+      }
+      
+      return (int) Result.NotYetHandled;
+    }
+
+    public void Unregister_Called(IntPtr rawConnection, 
+                                 IntPtr userData)
+    {
+      System.Console.WriteLine("FIXME: Unregister called.");
+    }
+
+    private int Message_Called(IntPtr rawConnection, 
+                              IntPtr rawMessage, 
+                              IntPtr userData) 
+    {
+      Message message = Message.Wrap(rawMessage, Service);
+
+      switch (message.Type) {
+      case Message.MessageType.Signal:
+       System.Console.WriteLine("FIXME: Signal called.");
+       break;
+      case Message.MessageType.MethodCall:
+       return (int) HandleMethod((MethodCall) message);
+      }
+
+      return (int) Result.NotYetHandled;
+    }
+    
+    private Result HandleMethod(MethodCall methodCall)
+    {
+      methodCall.Service = service;
+
+      // Check the interface name matches
+      if (methodCall.InterfaceName != this.introspector.InterfaceName) {
+       return Result.NotYetHandled;
+      }
+
+      // Iterate through getting the type codes
+      string key = methodCall.Name + " " + methodCall.Arguments;
+
+      // Check it's one of our methods
+      if (!handledMethods.Contains(key)) {
+       return Result.NotYetHandled;
+      }
+
+      // Got it!
+      MethodInfo method = (MethodInfo) handledMethods[key];
+
+      // Now call the method. FIXME: Error handling
+      object [] args = methodCall.Arguments.GetParameters(method);
+      object retVal = method.Invoke(this.handledObject, args);
+
+      // Create the reply and send it
+      MethodReturn methodReturn = new MethodReturn(methodCall);
+      methodReturn.Arguments.AppendResults(method, retVal, args);
+      methodReturn.Send();
+
+      return Result.Handled;
+    }
+
+    internal string[] Path 
+    {
+      get 
+       {
+         return path;
+       }
+    }
+
+    public string PathName
+    {
+      get
+       {
+         return pathName;
+       }
+    }
+
+    internal Connection Connection 
+    {
+      get
+       {
+         return connection;
+       }
+      
+      set 
+       {
+         this.connection = value;
+       }
+    }
+
+    public Service Service
+    {
+      get
+       {
+         return service;
+       }
+      
+      set 
+       {
+         this.service = value;
+       }
+    }    
+
+    [DllImport ("dbus-1")]
+    private extern static bool dbus_connection_register_object_path (IntPtr rawConnection, string[] path, ref DBusObjectPathVTable vTable, IntPtr userData);
+
+    [DllImport ("dbus-1")]
+    private extern static void dbus_connection_unregister_object_path (IntPtr rawConnection, string[] path);
+
+    [DllImport ("dbus-1")]
+    private extern static bool dbus_connection_add_filter(IntPtr rawConnection,
+                                                         DBusHandleMessageFunction filter,
+                                                         IntPtr userData,
+                                                         IntPtr freeData);
+
+  }
+}
diff --git a/mono/InterfaceAttribute.cs b/mono/InterfaceAttribute.cs
new file mode 100644 (file)
index 0000000..2a6e9bb
--- /dev/null
@@ -0,0 +1,23 @@
+using System;
+
+namespace DBus
+{
+  [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
+  public class InterfaceAttribute : Attribute 
+  {
+    private string interfaceName;
+
+    public InterfaceAttribute(string interfaceName) 
+    {
+      this.interfaceName = interfaceName;
+    }
+
+    public string InterfaceName
+    {
+      get
+       {
+         return this.interfaceName;
+       }
+    }
+  }
+}
diff --git a/mono/Introspector.cs b/mono/Introspector.cs
new file mode 100644 (file)
index 0000000..c7b9d05
--- /dev/null
@@ -0,0 +1,106 @@
+namespace DBus 
+{
+  
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  using System.Collections;
+  using System.Reflection;
+  
+  internal class Introspector
+  {
+    private Type type;
+    private string interfaceName;
+    
+    public Introspector(Type type)    {
+      object[] attributes = type.GetCustomAttributes(typeof(InterfaceAttribute), true);
+      if (attributes.Length != 1)
+       throw new ApplicationException("Type '" + type + "' is not a D-BUS interface.");
+      
+      InterfaceAttribute interfaceAttribute = (InterfaceAttribute) attributes[0];
+     
+      this.interfaceName = interfaceAttribute.InterfaceName;
+      this.type = type;
+    }
+    
+    public string InterfaceName
+    {
+      get
+       {
+         return this.interfaceName;
+       }
+    }
+
+    public ConstructorInfo Constructor
+    {
+      get
+       {
+         ConstructorInfo ret = this.type.GetConstructor(new Type[0]);
+         if (ret != null) {
+           return ret;
+         } else {
+           return typeof(object).GetConstructor(new Type[0]);
+         }
+       }
+    }
+
+    public IntrospectorMethods Methods
+    {
+      get
+       {
+         return new IntrospectorMethods(this.type);
+       }
+    }
+
+    public class IntrospectorMethods : IEnumerable
+    {
+      private Type type;
+      
+      public IntrospectorMethods(Type type)
+      {
+       this.type = type;
+      }
+
+      public IEnumerator GetEnumerator()
+      {
+       return new MethodEnumerator(this.type.GetMethods(BindingFlags.Public|BindingFlags.Instance).GetEnumerator());
+      }
+
+      private class MethodEnumerator : IEnumerator
+      {
+       private IEnumerator enumerator;
+       
+       public MethodEnumerator(IEnumerator enumerator)
+       {
+         this.enumerator = enumerator;
+       }
+       
+       public bool MoveNext()
+       {
+         while (enumerator.MoveNext()) {
+           MethodInfo method = (MethodInfo) enumerator.Current;
+           object[] attributes = method.GetCustomAttributes(typeof(MethodAttribute), true);
+           if (attributes.GetLength(0) > 0) {
+             return true;
+           }
+         }
+         
+         return false;
+       }
+       
+       public void Reset()
+       {
+         enumerator.Reset();
+       }
+       
+       public object Current
+       {
+         get
+           {
+             return enumerator.Current;
+           }
+       }
+      }
+    }
+  }
+}
index efd61b4..6483f4e 100644 (file)
@@ -1,9 +1,41 @@
 DESTDIR=
 
 DLLS=dbus-sharp.dll
-NOINST_EXES=test-dbus-sharp
+NOINST_EXES=test-dbus-sharp.exe
+
+DBUS_SHARP_FILES=              \
+       Arguments.cs            \
+       Bus.cs                  \
+       Connection.cs           \
+       Custom.cs               \
+       DBusException.cs        \
+       Error.cs                \
+       Handler.cs              \
+       InterfaceAttribute.cs   \
+       Introspector.cs         \
+       Message.cs              \
+       MethodAttribute.cs      \
+       MethodCall.cs           \
+       MethodReturn.cs         \
+       ProxyBuilder.cs         \
+       Server.cs               \
+       Service.cs              \
+       Signal.cs               \
+       DBusType/IDBusType.cs   \
+       DBusType/Array.cs       \
+       DBusType/Boolean.cs     \
+       DBusType/Byte.cs        \
+       DBusType/Custom.cs      \
+       DBusType/Dict.cs        \
+       DBusType/Double.cs      \
+       DBusType/Int32.cs       \
+       DBusType/Int64.cs       \
+       DBusType/Nil.cs         \
+       DBusType/ObjectPath.cs  \
+       DBusType/String.cs      \
+       DBusType/UInt32.cs      \
+       DBusType/UInt64.cs
 
-DBUS_SHARP_FILES= DBus.cs Message.cs Connection.cs Error.cs
 TEST_DBUS_SHARP_FILES=Test.cs
 
 all: $(DLLS) $(NOINST_EXES)
@@ -11,8 +43,8 @@ all: $(DLLS) $(NOINST_EXES)
 dbus-sharp.dll: $(DBUS_SHARP_FILES)
        $(MCS) $(MCSFLAGS) --unsafe --target library -o dbus-sharp.dll $(DBUS_SHARP_FILES)
 
-test-dbus-sharp: $(TEST_DBUS_SHARP_FILES)
-       $(MCS) $(MCSFLAGS) --unsafe --target exe -L . -r dbus-sharp.dll -o test-dbus-sharp $(TEST_DBUS_SHARP_FILES)
+test-dbus-sharp.exe: $(TEST_DBUS_SHARP_FILES)
+       $(MCS) $(MCSFLAGS) --unsafe --target exe -L . -r dbus-sharp.dll -r gtk-sharp.dll -o test-dbus-sharp.exe $(TEST_DBUS_SHARP_FILES)
 
 clean:
        rm -f $(DLLS) $(NOINST_EXES)
index 8f6db00..2f5270d 100644 (file)
-namespace DBus {
+namespace DBus 
+{
   
   using System;
   using System.Runtime.InteropServices;
   using System.Diagnostics;
+  using System.Collections;
   
-  public class Message {
+  public class Message 
+  {
+    
+    /// <summary>
+    /// A pointer to the underlying Message structure
+    /// </summary>
+    private IntPtr rawMessage;
+    
+    /// <summary>
+    /// The current slot number
+    /// </summary>
+    private static int slot = -1;
+    
+    // Keep in sync with C
+    public enum MessageType 
+    {
+      Invalid = 0,
+      MethodCall = 1,
+      MethodReturn = 2,
+      Error = 3,
+      Signal = 4
+    }
 
-    public Message (string name,
-                    string dest_service) {
+    private Arguments arguments = null;
+
+    protected Service service = null;
+    protected string pathName = null;
+    protected string interfaceName = null;
+    protected string name = null;    
+
+    protected Message()
+    {
+      // An empty constructor for the sake of sub-classes which know how to construct theirselves.
+    }
+    
+    protected Message(IntPtr rawMessage, Service service)
+    {
+      RawMessage = rawMessage;
+      this.service = service;
+    }
+    
+    protected Message(MessageType messageType) 
+    {
       // the assignment bumps the refcount
-      raw = dbus_message_new (name, dest_service);
-      if (raw == IntPtr.Zero)
-        throw new OutOfMemoryException ();
-      dbus_message_unref (raw);
+      RawMessage = dbus_message_new((int) messageType);
+      
+      if (RawMessage == IntPtr.Zero) {
+       throw new OutOfMemoryException();
+      }
+      
+      dbus_message_unref(RawMessage);
     }
-
-    public string Name {
-      get {
-        return dbus_message_get_name (raw);
+    
+    protected Message(MessageType messageType, Service service) : this(messageType) 
+    {
+      this.service = service;
+    }
+    
+    ~Message() 
+    {
+      RawMessage = IntPtr.Zero; // free the native object
+    }
+    
+    public static Message Wrap(IntPtr rawMessage, Service service) 
+    {
+      if (slot > -1) {
+       // If we already have a Message object associated with this rawMessage then return it
+       IntPtr rawThis = dbus_message_get_data(rawMessage, slot);
+       if (rawThis != IntPtr.Zero)
+         return (DBus.Message) ((GCHandle)rawThis).Target;
+      } 
+      // If it doesn't exist then create a new Message around it
+      Message message = null;
+      
+      switch ((MessageType) dbus_message_get_type(rawMessage)) {
+      case MessageType.Signal:
+       message = new Signal(rawMessage, service);
+       break;
+      case MessageType.MethodCall:
+       message = new MethodCall(rawMessage, service);
+       break;
       }
+
+      return message;
+    }
+    
+    internal IntPtr RawMessage 
+    {
+      get 
+       {
+         return rawMessage;
+       }
+      set 
+       {
+         if (value == rawMessage) 
+           return;
+         
+         if (rawMessage != IntPtr.Zero) 
+           {
+             // Get the reference to this
+             IntPtr rawThis = dbus_message_get_data(rawMessage, Slot);
+             Debug.Assert (rawThis != IntPtr.Zero);
+             
+             // Blank over the reference
+             dbus_message_set_data(rawMessage, Slot, IntPtr.Zero, IntPtr.Zero);
+             
+             // Free the reference
+             ((GCHandle) rawThis).Free();
+             
+             // Unref the connection
+             dbus_message_unref(rawMessage);
+           }
+         
+         this.rawMessage = value;
+         
+         if (rawMessage != IntPtr.Zero) 
+           {
+             GCHandle rawThis;
+             
+             dbus_message_ref(rawMessage);
+             
+             // We store a weak reference to the C# object on the C object
+             rawThis = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection);
+             
+             dbus_message_set_data(rawMessage, Slot, (IntPtr) rawThis, IntPtr.Zero);
+           }
+       }
+    }
+    
+    public void Send(ref int serial) 
+    {
+      if (!dbus_connection_send (Service.Connection.RawConnection, RawMessage, ref serial))
+       throw new OutOfMemoryException ();
+    }
+    
+    public void Send() 
+    {
+      int ignored = 0;
+      Send(ref ignored);
     }
 
-    public static Message Wrap (IntPtr ptr) {
-      IntPtr gch_ptr;
+    public void SendWithReply() 
+    {
+      IntPtr rawPendingCall = IntPtr.Zero;
       
-      gch_ptr = dbus_message_get_data (ptr, wrapper_slot);
-      if (gch_ptr != IntPtr.Zero) {
-        return (DBus.Message) ((GCHandle)gch_ptr).Target;
-      } else {
-        return new Message (ptr);
-      }
+      if (!dbus_connection_send_with_reply (Service.Connection.RawConnection, RawMessage, rawPendingCall, Service.Connection.Timeout))
+       throw new OutOfMemoryException();
     }
+     
+    public MethodReturn SendWithReplyAndBlock()
+    {
+      Error error = new Error();
+      error.Init();
 
-    // surely there's a convention for this pattern with the property
-    // and the real member
-    IntPtr raw_;
-    internal IntPtr raw {
-      get {
-        return raw_; 
-      }
-      set {
-        if (value == raw_)
-          return;
-        
-        if (raw_ != IntPtr.Zero) {
-          IntPtr gch_ptr;
-          
-          gch_ptr = dbus_message_get_data (raw_,
-                                           wrapper_slot);
-          Debug.Assert (gch_ptr != IntPtr.Zero);
-
-          dbus_message_set_data (raw_, wrapper_slot,
-                                 IntPtr.Zero, IntPtr.Zero);
-          
-          ((GCHandle) gch_ptr).Free ();
-          
-          dbus_message_unref (raw_);
-        }
-        
-        raw_ = value;
-
-        if (raw_ != IntPtr.Zero) {
-          GCHandle gch;
-
-          dbus_message_ref (raw_);
-
-          // We store a weak reference to the C# object on the C object
-          gch = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection);
-          
-          dbus_message_set_data (raw_, wrapper_slot,
-                                 (IntPtr) gch, IntPtr.Zero);
-        }
+      IntPtr rawMessage = dbus_connection_send_with_reply_and_block(Service.Connection.RawConnection, 
+                                                                   RawMessage, 
+                                                                   Service.Connection.Timeout, 
+                                                                   ref error);
+
+      if (rawMessage != IntPtr.Zero) {
+       MethodReturn methodReturn = new MethodReturn(rawMessage, Service);
+       return methodReturn;
+      } else {
+       throw new DBusException(error);
       }
     }
 
-    ~Message () {
-      raw = IntPtr.Zero; // free the native object
+    public MessageType Type
+    {
+      get 
+       {
+         return (MessageType) dbus_message_get_type(RawMessage);
+       }
     }
     
-    Message (IntPtr r) {
-      raw = r;
+    public Service Service
+    {
+      set 
+       {
+         if (this.service != null && (value.Name != this.service.Name)) {
+           if (!dbus_message_set_destination(RawMessage, value.Name)) {
+             throw new OutOfMemoryException();
+           }
+         }
+         
+         this.service = value;
+       }
+      get 
+       {
+         return this.service;
+       }
     }
     
-    // static constructor runs before any methods 
-    static Message () {
-      DBus.Internals.Init ();
-      
-      Debug.Assert (wrapper_slot == -1);
-      
-      if (!dbus_message_allocate_data_slot (ref wrapper_slot))
-        throw new OutOfMemoryException ();
+    protected virtual string PathName
+    {
+      set 
+       {
+         if (value != this.pathName) 
+           {
+             if (!dbus_message_set_path(RawMessage, value)) {
+               throw new OutOfMemoryException();
+             }
+             
+             this.pathName = value;
+           }
+       }
+      get 
+       {
+         if (this.pathName == null) {
+           this.pathName = Marshal.PtrToStringAnsi(dbus_message_get_path(RawMessage));
+         }
+         
+         return this.pathName;
+       }
+    }
+    
+    protected virtual string InterfaceName
+    {
+      set 
+       {
+         if (value != this.interfaceName)
+           {
+             dbus_message_set_interface (RawMessage, value);
+             this.interfaceName = value;
+           }
+       }
+      get 
+       {
+         if (this.interfaceName == null) {
+           this.interfaceName = Marshal.PtrToStringAnsi(dbus_message_get_interface(RawMessage));
+         }
 
-      Debug.Assert (wrapper_slot >= 0);
+         return this.interfaceName;
+       }
     }
+    
+    protected virtual string Name
+    {
+      set 
+       {
+         if (value != this.name)
+           {
+             dbus_message_set_member (RawMessage, value);
+             this.name = value;
+           }
+       }
+      get 
+       {
+         if (this.name == null) {
+           this.name = Marshal.PtrToStringAnsi(dbus_message_get_member(RawMessage));
+         }
+
 
-    // slot used to store the C# object on the C object
-    static int wrapper_slot = -1;
+         return this.name;
+       }
+    }
+
+    public Arguments Arguments
+    {
+      get 
+       {
+         if (this.arguments == null) {
+           this.arguments = new Arguments(this);
+         }
+         
+         return this.arguments;
+       }
+    }
+
+    protected int Slot
+    {
+      get 
+       {
+         if (slot == -1) 
+           {
+             // We need to initialize the slot
+             if (!dbus_message_allocate_data_slot (ref slot))
+               throw new OutOfMemoryException ();
+             
+             Debug.Assert (slot >= 0);
+           }
+         
+         return slot;
+       }
+    }
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_message_new")]
+    protected extern static IntPtr dbus_message_new (int messageType);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_message_unref")]
+    protected extern static void dbus_message_unref (IntPtr ptr);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_message_ref")]
+    protected extern static void dbus_message_ref (IntPtr ptr);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_message_allocate_data_slot")]
+    protected extern static bool dbus_message_allocate_data_slot (ref int slot);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_message_free_data_slot")]
+    protected extern static void dbus_message_free_data_slot (ref int slot);
     
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_new")]
-      private extern static IntPtr dbus_message_new (string name,
-                                                     string dest_service);
+    [DllImport ("dbus-1", EntryPoint="dbus_message_set_data")]
+    protected extern static bool dbus_message_set_data (IntPtr ptr,
+                                                       int    slot,
+                                                       IntPtr data,
+                                                       IntPtr free_data_func);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_message_get_data")]
+    protected extern static IntPtr dbus_message_get_data (IntPtr ptr,
+                                                         int    slot);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_connection_send")]
+    private extern static bool dbus_connection_send (IntPtr  ptr,
+                                                    IntPtr  message,
+                                                    ref int client_serial);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_connection_send_with_reply")]
+    private extern static bool dbus_connection_send_with_reply (IntPtr rawConnection, IntPtr rawMessage, IntPtr rawPendingCall, int timeout);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_unref")]
-      private extern static void dbus_message_unref (IntPtr ptr);
+    [DllImport ("dbus-1", EntryPoint="dbus_connection_send_with_reply_and_block")]
+    private extern static IntPtr dbus_connection_send_with_reply_and_block (IntPtr rawConnection, IntPtr  message, int timeout, ref Error error);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_ref")]
-      private extern static void dbus_message_ref (IntPtr ptr);
+    [DllImport("dbus-1")]
+    private extern static int dbus_message_get_type(IntPtr rawMessage);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_get_name")]
-      private extern static string dbus_message_get_name (IntPtr ptr);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_set_path(IntPtr rawMessage, string pathName);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_allocate_data_slot")]
-      private extern static bool dbus_message_allocate_data_slot (ref int slot);
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_get_path(IntPtr rawMessage);
+    
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_set_interface (IntPtr rawMessage, string interfaceName);
+
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_get_interface(IntPtr rawMessage);
+    
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_set_member (IntPtr rawMessage, string name);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_free_data_slot")]
-      private extern static void dbus_message_free_data_slot (ref int slot);
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_get_member(IntPtr rawMessage);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_set_data")]
-      private extern static bool dbus_message_set_data (IntPtr ptr,
-                                                        int    slot,
-                                                        IntPtr data,
-                                                        IntPtr free_data_func);
+    [DllImport("dbus-1")]
+    private extern static bool dbus_message_set_destination(IntPtr rawMessage, string serviceName);
 
-    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_get_data")]
-      private extern static IntPtr dbus_message_get_data (IntPtr ptr,
-                                                          int    slot);
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_get_destination(IntPtr rawMessage);
   }
 }
diff --git a/mono/MethodAttribute.cs b/mono/MethodAttribute.cs
new file mode 100644 (file)
index 0000000..db5da24
--- /dev/null
@@ -0,0 +1,12 @@
+using System;
+
+namespace DBus
+{
+  [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
+  public class MethodAttribute : Attribute 
+  {
+    public MethodAttribute() 
+    {
+    }
+  }
+}
diff --git a/mono/MethodCall.cs b/mono/MethodCall.cs
new file mode 100644 (file)
index 0000000..ab7a4a3
--- /dev/null
@@ -0,0 +1,80 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  
+  public class MethodCall : Message
+  {
+    public MethodCall() : base(MessageType.MethodCall)
+    {
+    }
+    
+    internal MethodCall(IntPtr rawMessage, Service service) : base(rawMessage, service)
+    {
+    }
+
+    public MethodCall(Service service) : base(MessageType.MethodCall, service)
+    {
+    }
+
+    public MethodCall(Service service, string pathName, string interfaceName, string name)
+    {
+      this.service = service;
+
+      RawMessage = dbus_message_new_method_call(service.Name, pathName, interfaceName, name);
+      
+      if (RawMessage == IntPtr.Zero) {
+       throw new OutOfMemoryException();
+      }
+      
+      this.pathName = pathName;
+      this.interfaceName = interfaceName;
+      this.name = name;
+
+      dbus_message_unref(RawMessage);
+    }
+    
+    public new string PathName
+    {
+      get
+       {
+         return base.PathName;
+       }
+
+      set
+       {
+         base.PathName = value;
+       }
+    }
+
+    public new string InterfaceName
+    {
+      get
+       {
+         return base.InterfaceName;
+       }
+
+      set
+       {
+         base.InterfaceName = value;
+       }
+    }
+
+    public new string Name
+    {
+      get
+       {
+         return base.Name;
+       }
+
+      set
+       {
+         base.Name = value;
+       }
+    }
+    
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_new_method_call(string serviceName, string pathName, string interfaceName, string name);
+  }
+}
diff --git a/mono/MethodReturn.cs b/mono/MethodReturn.cs
new file mode 100644 (file)
index 0000000..1e7731d
--- /dev/null
@@ -0,0 +1,57 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  
+  public class MethodReturn : Message
+  {
+    private MethodReturn() : base(MessageType.MethodReturn)
+    {
+    }    
+
+    internal MethodReturn(IntPtr rawMessage, Service service) : base(rawMessage, service)
+    {
+    }
+    
+    public MethodReturn(MethodCall methodCall)
+    {
+      this.service = methodCall.Service;
+      
+      RawMessage = dbus_message_new_method_return(methodCall.RawMessage);
+      
+      if (RawMessage == IntPtr.Zero) {
+       throw new OutOfMemoryException();
+      }
+      
+      dbus_message_unref(RawMessage);
+    }
+    
+    public new string PathName
+    {
+      get
+       {
+         return base.PathName;
+       }
+    }
+
+    public new string InterfaceName
+    {
+      get
+       {
+         return base.InterfaceName;
+       }
+    }
+
+    public new string Name
+    {
+      get
+       {
+         return base.Name;
+       }
+    }
+    
+    [DllImport("dbus-1")]
+    private extern static IntPtr dbus_message_new_method_return(IntPtr rawMessage);
+  }
+}
diff --git a/mono/ProxyBuilder.cs b/mono/ProxyBuilder.cs
new file mode 100644 (file)
index 0000000..8e170c7
--- /dev/null
@@ -0,0 +1,301 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  using System.Collections;
+  using System.Threading;
+  using System.Reflection;
+  using System.Reflection.Emit;
+
+  internal class ProxyBuilder
+  {
+    private Service service= null;
+    private string pathName = null;
+    private Type type = null;
+    private Introspector introspector = null;
+    private AssemblyBuilder proxyAssembly;
+    
+    private static MethodInfo Service_NameMI = typeof(Service).GetMethod("get_Name", 
+                                                                           new Type[0]);
+    private static MethodInfo Service_ConnectionMI = typeof(Service).GetMethod("get_Connection",
+                                                                                 new Type[0]);
+    private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments",
+                                                                                new Type[0]);
+    private static MethodInfo Arguments_InitAppendingMI = typeof(Arguments).GetMethod("InitAppending",
+                                                                                         new Type[0]);
+    private static MethodInfo Arguments_AppendMI = typeof(Arguments).GetMethod("Append",
+                                                                                 new Type[] {typeof(DBusType.IDBusType)});
+    private static MethodInfo Message_SendWithReplyAndBlockMI = typeof(Message).GetMethod("SendWithReplyAndBlock",
+                                                                                            new Type[0]);
+    private static MethodInfo Arguments_GetEnumeratorMI = typeof(Arguments).GetMethod("GetEnumerator",
+                                                                                         new Type[0]);
+    private static MethodInfo IEnumerator_MoveNextMI = typeof(System.Collections.IEnumerator).GetMethod("MoveNext",
+                                                                                                       new Type[0]);
+    private static MethodInfo IEnumerator_CurrentMI = typeof(System.Collections.IEnumerator).GetMethod("get_Current",
+                                                                                                      new Type[0]);
+    private static MethodInfo Type_GetTypeFromHandleMI = typeof(System.Type).GetMethod("GetTypeFromHandle",
+                                                                                      new Type[] {typeof(System.RuntimeTypeHandle)});
+    private static MethodInfo IDBusType_GetMI = typeof(DBusType.IDBusType).GetMethod("Get",
+                                                                                    new Type[] {typeof(System.Type)});
+    private static ConstructorInfo MethodCall_C = typeof(MethodCall).GetConstructor(new Type[] {typeof(Service),
+                                                                                               typeof(string),
+                                                                                               typeof(string),
+                                                                                               typeof(string)});
+    
+                                                                                       
+
+    public ProxyBuilder(Service service, Type type, string pathName)
+    {
+      this.service = service;
+      this.pathName = pathName;
+      this.type = type;
+      this.introspector = new Introspector(type);
+    }
+
+    private void BuildMethod(MethodInfo method, 
+                            ref TypeBuilder typeB, 
+                            FieldInfo serviceF,
+                            FieldInfo interfaceF,
+                            FieldInfo pathF)
+    {
+      ParameterInfo[] pars = method.GetParameters();
+      Type[] parTypes = new Type[pars.Length];
+      for (int parN = 0; parN < pars.Length; parN++) {
+       parTypes[parN] = pars[parN].ParameterType;
+      }
+
+      // Generate the code
+      MethodBuilder methodBuilder = typeB.DefineMethod(method.Name, 
+                                                      MethodAttributes.Public |
+                                                      MethodAttributes.HideBySig |
+                                                      MethodAttributes.Virtual, 
+                                                      method.ReturnType, 
+                                                      parTypes);
+      ILGenerator generator = methodBuilder.GetILGenerator();
+
+      for (int parN = 0; parN < pars.Length; parN++) {
+       methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name);
+      }
+
+      // Generate the locals
+      LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall));
+      methodCallL.SetLocalSymInfo("methodCall");
+      LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn));
+      replyL.SetLocalSymInfo("reply");
+      LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
+      enumeratorL.SetLocalSymInfo("enumerator");
+
+      if (method.ReturnType != typeof(void)) {
+       LocalBuilder retvalL = generator.DeclareLocal(method.ReturnType);
+       retvalL.SetLocalSymInfo("retval");
+      }
+
+      //generator.EmitWriteLine("MethodCall methodCall = new MethodCall(...)");
+      generator.Emit(OpCodes.Ldsfld, serviceF);
+      generator.Emit(OpCodes.Ldarg_0);
+      generator.Emit(OpCodes.Ldfld, pathF);
+      generator.Emit(OpCodes.Ldsfld, interfaceF);
+      generator.Emit(OpCodes.Ldstr, method.Name);
+      generator.Emit(OpCodes.Newobj, MethodCall_C);
+      generator.Emit(OpCodes.Stloc_0);
+
+      //generator.EmitWriteLine("methodCall.Arguments.InitAppending()");
+      generator.Emit(OpCodes.Ldloc_0);
+      generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
+      generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null);
+
+      for (int parN = 0; parN < pars.Length; parN++) {
+       ParameterInfo par = pars[parN];
+       if (!par.IsOut) {
+         EmitIn(generator, par.ParameterType, parN);
+       }
+      }
+      
+      //generator.EmitWriteLine("MethodReturn reply = methodCall.SendWithReplyAndBlock()");
+      generator.Emit(OpCodes.Ldloc_0);
+      generator.EmitCall(OpCodes.Callvirt, Message_SendWithReplyAndBlockMI, null);      
+      generator.Emit(OpCodes.Stloc_1);
+
+      //generator.EmitWriteLine("IEnumerator enumeartor = reply.Arguments.GetEnumerator()");
+      generator.Emit(OpCodes.Ldloc_1);
+      generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
+      generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
+      generator.Emit(OpCodes.Stloc_2);
+
+      // handle the return value
+      if (method.ReturnType != typeof(void)) {
+       EmitOut(generator, method.ReturnType, 0);
+      }
+
+      for (int parN = 0; parN < pars.Length; parN++) {
+       ParameterInfo par = pars[parN];
+       if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
+         EmitOut(generator, par.ParameterType, parN);
+       }
+      }
+
+      if (method.ReturnType != typeof(void)) {
+       generator.Emit(OpCodes.Ldloc_3);
+      }
+      
+      generator.Emit(OpCodes.Ret);
+
+      // Generate the method
+      typeB.DefineMethodOverride(methodBuilder, method);
+    }
+
+    private void EmitIn(ILGenerator generator, Type parType, int parN)
+    {
+      Type inParType = Arguments.MatchType(parType);
+      //generator.EmitWriteLine("methodCall.Arguments.Append(...)");
+      generator.Emit(OpCodes.Ldloc_0);
+      generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
+      generator.Emit(OpCodes.Ldarg_S, parN + 1);
+
+      // Call the DBusType EmitMarshalIn to make it emit itself
+      object[] pars = new object[] {generator, parType};
+      inParType.InvokeMember("EmitMarshalIn", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
+
+      generator.Emit(OpCodes.Newobj, Arguments.GetDBusTypeConstructor(inParType, parType));
+      generator.EmitCall(OpCodes.Callvirt, Arguments_AppendMI, null);
+    }
+
+    private void EmitOut(ILGenerator generator, Type parType, int parN)
+    {
+      Type outParType = Arguments.MatchType(parType);
+      //generator.EmitWriteLine("enumerator.MoveNext()");
+      generator.Emit(OpCodes.Ldloc_2);
+      generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
+
+      //generator.EmitWriteLine("return (" + parType + ") ((DBusType.IDBusType) enumerator.Current).Get(typeof(" + parType + "))");
+      generator.Emit(OpCodes.Pop);
+      if (parN > 0) {
+       generator.Emit(OpCodes.Ldarg_S, parN + 1);
+      }
+      
+      generator.Emit(OpCodes.Ldloc_2);
+      generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null);
+      generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType));
+      generator.Emit(OpCodes.Ldtoken, parType);
+      generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null);
+      generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null);
+
+      // Call the DBusType EmitMarshalOut to make it emit itself
+      object[] pars = new object[] {generator, parType, parN == 0};
+      outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
+      
+      if (parN == 0) {
+       generator.Emit(OpCodes.Stloc_3);
+      }
+    }
+    
+    public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo interfaceF, FieldInfo pathF)
+    {
+      Type[] pars = {typeof(Service), typeof(string), typeof(string)};
+      ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | 
+                                                              MethodAttributes.Public,
+                                                              CallingConventions.Standard, pars);
+
+      ILGenerator generator = constructor.GetILGenerator();
+      generator.Emit(OpCodes.Ldarg_0);
+      generator.Emit(OpCodes.Call, this.introspector.Constructor);
+      generator.Emit(OpCodes.Ldarg_1);
+      generator.Emit(OpCodes.Stsfld, serviceF);
+      generator.Emit(OpCodes.Ldarg_2);
+      generator.Emit(OpCodes.Stsfld, interfaceF);
+      generator.Emit(OpCodes.Ldarg_0);
+      generator.Emit(OpCodes.Ldarg_3);
+      generator.Emit(OpCodes.Stfld, pathF);
+
+      generator.Emit(OpCodes.Ret);
+    }
+    
+    public object GetProxy() 
+    {      
+      
+      // Build the type
+      TypeBuilder typeB = ServiceModuleBuilder.DefineType(ProxyName, TypeAttributes.Public, this.type);
+      //type.AddInterfaceImplementation(typeof(IProxy));
+      
+      FieldBuilder serviceF = typeB.DefineField("service", 
+                                               typeof(Service), 
+                                               FieldAttributes.Private | 
+                                               FieldAttributes.Static);
+      FieldBuilder interfaceF = typeB.DefineField("interfaceName", 
+                                                 typeof(string), 
+                                                 FieldAttributes.Private | 
+                                                 FieldAttributes.Static);
+      FieldBuilder pathF = typeB.DefineField("pathName", 
+                                            typeof(string), 
+                                            FieldAttributes.Private);
+
+      BuildConstructor(ref typeB, serviceF, interfaceF, pathF);
+
+      // Build the methods
+      foreach (MethodInfo method in this.introspector.Methods) {
+       BuildMethod(method, ref typeB, serviceF, interfaceF, pathF);
+      }
+      
+      Type [] parTypes = new Type[] {typeof(Service), typeof(string), typeof(string)};
+      object [] pars = new object[] {Service, this.introspector.InterfaceName, pathName};
+      
+      Type proxyType = typeB.CreateType();
+
+      // Uncomment the following line to produce a DLL of the
+      // constructed assembly which can then be examined using
+      // monodis. Note that in order for this to work you should copy
+      // the client assembly as a dll file so that monodis can pick it
+      // up.
+      //ProxyAssembly.Save("proxy.dll");
+
+      ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
+      object instance = constructor.Invoke(pars);
+      return instance;
+    }
+
+    private ModuleBuilder ServiceModuleBuilder
+    {
+      get
+       {
+         if (Service.module == null) {
+           Service.module = ProxyAssembly.DefineDynamicModule(Service.Name, "proxy.dll", true);
+         }
+         
+         return Service.module;
+       }
+    }
+  
+  private Service Service
+    {
+      get
+       {
+         return this.service;
+       }
+    }
+
+    private string ProxyName
+    {
+      get
+       {
+         return this.introspector.InterfaceName + ".Proxy";
+       }
+    }
+
+    private AssemblyBuilder ProxyAssembly
+    {
+      get
+       {
+         if (this.proxyAssembly == null){
+           AssemblyName assemblyName = new AssemblyName();
+           assemblyName.Name = "DBusProxy";
+           this.proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, 
+                                                                         AssemblyBuilderAccess.RunAndSave);
+         }
+         
+         return this.proxyAssembly;
+       }
+    }
+  }
+}
+
diff --git a/mono/README b/mono/README
new file mode 100644 (file)
index 0000000..2d1b08b
--- /dev/null
@@ -0,0 +1,118 @@
+D-BUS Mono Bindings
+===
+
+These bindings are a 'thick' wrapper around the D-BUS API. For now
+they rely on the main loop provided by the GLib bindings but this
+dependancy will be removed in the near future.
+
+The wrapper serves two main functions: firstly, it has the know-how to
+introspect live objects passed to it by a server and service requests
+to those objects via the D-BUS. Secondly, it can create a proxy for
+clients who can pretend they are making calls to the regular
+objects. This latter piece of magic is implemented using
+Reflection.Emit to create an assembly on-the-fly containing
+sub-classes of the classes the client thinks it's really using. These
+sub-classes simply marshal each method's parameters off to the D-BUS,
+demarshal the results and return them to the client as if nothing
+happened.
+
+Usage
+===
+
+A server do should something like this:
+
+       namespace Foo
+       {
+       using System;
+       using DBus;
+       using Gtk;
+
+       public class MyServer
+       {
+       public static int Main(string [] args)
+       {
+               Application.Init();
+       
+1              Connection connection = Bus.GetSessionBus();
+2              Service service = new Service(connection, "org.foo");
+3              MyObject myObject = new MyObject();
+4              service.RegisterObject(myObject, "/org/foo/MyObject");
+               
+               Application.Run();
+
+               return 0;
+       }
+       }
+       }
+
+In line 1 we get a connection to the session bus. Then, in line 2 we
+create a service which will listen for requests to org.foo to
+service. In line 3 we create a MyObject object and register it with an
+object path in line 4. It's almost that simple. All that's missing is
+to mark MyObject in such a way that dbus-sharp knows how to export
+it. This is done using the attributes, Interface and Method,
+as in the following example:
+
+       namespace Foo
+       {
+       using System;
+       using DBus;
+
+       [Interface("org.foo.MyObject")]
+       public class MyObject
+       {
+       [Method]
+       public virtual string Echo(string message)
+       {
+               return "Reply: " + message;
+       }
+       }
+       }
+
+Note that the Methods should also be declared virtual in order for
+the client to use same class declaration.
+
+Now for the client:
+
+       namespace Foo
+       {
+       using System;
+       using DBus;
+
+       public class MyClient
+       {
+       public static int Main(string [] args)
+       {
+1              Connection connection = Bus.GetSessionBus();
+2              Service service = Service.Get(connection, "org.foo");
+3              MyObject myObject = (MyObject) 
+                  service.GetObject(typeof(MyObject), "/org/foo/MyObject");
+4              System.Console.WriteLine(testObject.Echo("Hello world!"));
+
+               return 0;
+       }
+       }
+       }
+
+Here we start off the same by getting a connection to the session
+bus. This time though, in line 2, we get the existing service rather
+than creating it. In line 3, we ask the service to get the object
+"/org/foo/MyObject" as registered by the server and that return it as
+a MyObject. Once obtained we can use it like any normal object as in
+line 4. This supposes, of course, that you've just written MyObject
+and happen to have it readily available. If that were not the case,
+for example if you wanted to call a method on one of the well-known
+services, then you will need to write a stub class, like the MyObject
+class above, which has the method calls you need correctly defined but
+needn't actually have any implementation.
+
+
+Working Example
+===
+
+The example directory contains a working example similar to that
+described above. It uses the session bus so first run dbus-launch and
+then export DBUS_SESSION_BUS_ADDRESS, as displayed by dbus-launch, to
+two terminals, one to run the server and one for the client. Then,
+start the server in one terminal, the client in the other and cross
+your fingers.
diff --git a/mono/Server.cs b/mono/Server.cs
new file mode 100644 (file)
index 0000000..e39b7ca
--- /dev/null
@@ -0,0 +1,148 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  
+  public class Server
+  {
+    private IntPtr rawServer;
+    
+    /// <summary>
+    /// The current slot number
+    /// </summary>
+    private static int slot = -1;
+
+    private string address = null;
+    
+    private Server(IntPtr rawServer)
+    {
+      RawServer = rawServer;
+    }
+    
+    public Server(string address)
+    {
+      Error error = new Error();
+      error.Init();
+      RawServer = dbus_server_listen(address, ref error);
+      if (RawServer != IntPtr.Zero){
+       dbus_server_unref(RawServer);
+      } else {
+       throw new DBusException(error);
+      }
+    }
+    
+    ~Server()
+    {
+      if (RawServer != IntPtr.Zero) {
+       dbus_server_unref(rawServer);
+      }
+      
+      RawServer = IntPtr.Zero;
+    }
+    
+    public string Address 
+    {
+      get
+       {
+         if (address == null) {
+           address = dbus_server_get_address(rawServer);
+         }
+         
+         return address;
+       }
+    }
+
+    private int Slot
+    {
+      get 
+       {
+         if (slot == -1) 
+           {
+             // We need to initialize the slot
+             if (!dbus_server_allocate_data_slot (ref slot))
+               throw new OutOfMemoryException ();
+             
+             Debug.Assert (slot >= 0);
+           }
+         
+         return slot;
+       }
+    }
+
+    internal IntPtr RawServer 
+    {
+      get 
+       {
+         return rawServer;
+       }
+      set 
+       {
+         if (value == rawServer)
+           return;
+         
+         if (rawServer != IntPtr.Zero) 
+           {
+             // Get the reference to this
+             IntPtr rawThis = dbus_server_get_data (rawServer, Slot);
+             Debug.Assert (rawThis != IntPtr.Zero);
+             
+             // Blank over the reference
+             dbus_server_set_data (rawServer, Slot, IntPtr.Zero, IntPtr.Zero);
+             
+             // Free the reference
+             ((GCHandle) rawThis).Free();
+             
+             // Unref the connection
+             dbus_server_unref(rawServer);
+           }
+         
+         this.rawServer = value;
+         
+         if (rawServer != IntPtr.Zero) 
+           {
+             GCHandle rawThis;
+             
+             dbus_server_ref (rawServer);
+             
+             // We store a weak reference to the C# object on the C object
+             rawThis = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection);
+             
+             dbus_server_set_data(rawServer, Slot, (IntPtr) rawThis, IntPtr.Zero);
+           }
+       }
+    }
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_listen")]
+    private extern static IntPtr dbus_server_listen(string address, ref Error error);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_unref")]
+    private extern static IntPtr dbus_server_unref(IntPtr rawServer);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_ref")]
+    private extern static void dbus_server_ref(IntPtr rawServer);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_disconnect")]
+    private extern static void dbus_server_disconnect(IntPtr rawServer);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_get_address")]
+    private extern static string dbus_server_get_address(IntPtr rawServer);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_set_data")]
+    private extern static bool dbus_server_set_data(IntPtr rawServer,
+                                                   int slot,
+                                                   IntPtr data,
+                                                   IntPtr freeDataFunc);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_get_data")]
+    private extern static IntPtr dbus_server_get_data(IntPtr rawServer,
+                                                     int slot);
+
+    [DllImport ("dbus-1", EntryPoint="dbus_server_allocate_data_slot")]
+    private extern static bool dbus_server_allocate_data_slot (ref int slot);
+    
+    [DllImport ("dbus-1", EntryPoint="dbus_server_free_data_slot")]
+    private extern static void dbus_server_free_data_slot (ref int slot);
+
+  }
+}
diff --git a/mono/Service.cs b/mono/Service.cs
new file mode 100644 (file)
index 0000000..a3c2a31
--- /dev/null
@@ -0,0 +1,115 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  using System.Collections;
+  using System.Reflection;
+  using System.Reflection.Emit;
+  
+  public class Service
+  {
+    private Connection connection;
+    private string name;
+    private bool local = false;
+    private Hashtable registeredHandlers = new Hashtable();
+    internal ModuleBuilder module = null;
+
+    internal Service(string name, Connection connection)
+    {
+      this.name = name;
+      this.connection = connection;
+    }
+
+    public Service(Connection connection, string name)
+    {
+      Error error = new Error();
+      error.Init();
+      
+      // This isn't used for now
+      uint flags = 0;
+
+      if (dbus_bus_acquire_service(connection.RawConnection, name, flags, ref error) == -1) {
+       throw new DBusException(error);
+      }
+
+      this.connection = connection;
+      this.name = name;
+      this.local = true;
+    }
+
+    public static bool Exists(Connection connection, string name)
+    {
+      Error error = new Error();
+      error.Init();
+      
+      if (dbus_bus_service_exists(connection.RawConnection, 
+                                 name, 
+                                 ref error)) {
+       return true;
+      } else {
+       if (error.IsSet) {
+         throw new DBusException(error);
+       }
+       return false;
+      }
+    }
+
+    public static Service Get(Connection connection, string name)
+    {
+      if (Exists(connection, name)) {
+       return new Service(name, connection);
+      } else {
+       throw new ApplicationException("Service '" + name + "' does not exist.");
+      }
+    }
+
+    public void RegisterObject(object handledObject, 
+                              string pathName) 
+    {
+      Handler handler = new Handler(handledObject, 
+                                           pathName, 
+                                           this);
+      registeredHandlers.Add(handledObject, handler);
+    }
+
+    internal Handler GetHandler(object handledObject) 
+    {
+      return (Handler) registeredHandlers[handledObject];
+    }
+
+    public object GetObject(Type type, string pathName)
+    {
+      ProxyBuilder builder = new ProxyBuilder(this, type, pathName);
+      object proxy = builder.GetProxy();
+      return proxy;
+    }
+
+    public string Name
+    {
+      get
+       {
+         return this.name;
+       }
+    }
+
+    public Connection Connection 
+    {
+      get
+       {
+         return connection;
+       }
+      
+      set 
+       {
+         this.connection = value;
+       }
+    }
+
+    [DllImport ("dbus-1")]
+    private extern static int dbus_bus_acquire_service (IntPtr rawConnection, string serviceName, uint flags, ref Error error);
+
+    [DllImport ("dbus-1")]
+    private extern static bool dbus_bus_service_exists (IntPtr rawConnection, string serviceName, ref Error error);    
+  }
+}
diff --git a/mono/Signal.cs b/mono/Signal.cs
new file mode 100644 (file)
index 0000000..a9209fe
--- /dev/null
@@ -0,0 +1,60 @@
+namespace DBus
+{
+  using System;
+  using System.Runtime.InteropServices;
+  using System.Diagnostics;
+  
+  public class Signal : Message
+  {    
+    public Signal() : base(MessageType.Signal)
+    {  
+    }
+
+    internal Signal(IntPtr rawMessage, Service service) : base(rawMessage, service)
+    {
+    }
+
+    public Signal(Service service) : base(MessageType.Signal, service) 
+    {
+    }
+
+    public new string PathName
+    {
+      get
+       {
+         return base.PathName;
+       }
+
+      set
+       {
+         base.PathName = value;
+       }
+    }
+
+    public new string InterfaceName
+    {
+      get
+       {
+         return base.InterfaceName;
+       }
+
+      set
+       {
+         base.InterfaceName = value;
+       }
+    }
+
+    public new string Name
+    {
+      get
+       {
+         return base.Name;
+       }
+
+      set
+       {
+         base.Name = value;
+       }
+    }
+  }
+}
diff --git a/mono/TODO b/mono/TODO
new file mode 100644 (file)
index 0000000..e44c2a9
--- /dev/null
+++ b/mono/TODO
@@ -0,0 +1,8 @@
+- Clean up memory leakages. Call _unref functions etc.
+
+- Convert strings to/from UTF-8
+
+- Implement own main loop. The current implementation depends on the
+  GLib mainloop.
+
+- Get test working. Probably a threading issue.
index e92176f..028986c 100644 (file)
@@ -1,53 +1,70 @@
-
 using System;
-using System.Runtime.InteropServices;
+using System.Threading;
+using DBus;
+using Gtk;
 
-class Test {  
-  static void Main() {    
-    g_thread_init (IntPtr.Zero);
+namespace DBus.Test
+{
+  public class Test
+  {
+    public static Service service = null;
+    public static Connection connection = null;
     
-    DBus.Connection c;
+    public static int Main(string [] args)
+    {
+      TestServer testServer = new TestServer();
+      Thread serverThread = new Thread(new ThreadStart(testServer.StartServer));
+      serverThread.Start();
 
-    // c = new DBus.Connection ("unix:path=/tmp/foobar");
+      connection = Bus.GetSessionBus();
+      service = Service.Get(connection, "org.freedesktop.Test");      
 
-    try { 
-      c = DBus.Connection.GetBus (DBus.Connection.BusType.Session);
-    }
-    catch (DBus.Exception e) {
-      Console.Error.WriteLine ("Failed to open connection: {0}",
-                               e.Message);
-      return;
-    }
+      TestObject testObject = (TestObject) service.GetObject(typeof(TestObject), "/org/freedesktop/Test/TestObject");
       
-    DBus.Message m = new DBus.Message ("org.freedesktop.Foo",
-                                       "org.freedesktop.DBus.Broadcast");
+      System.Console.WriteLine(testObject.Test1("Hello"));
 
-    c.Send (m);
-    c.Flush ();
+      //RunTests(testObject);
 
-    IntPtr loop = g_main_loop_new (IntPtr.Zero, false);
-
-    g_main_loop_run (loop);
+      return 0;
+    }
 
-    g_main_loop_unref (loop);
+    public static void RunTests(TestObject testObject) 
+    {
+      System.Console.WriteLine(testObject.Test1("Hello"));
+    }
   }
 
-  internal const string GLibname = "libglib-2.0.so.0";
-  internal const string GThreadname = "libgthread-2.0.so.0";
-  
-  [DllImport (GLibname, EntryPoint="g_main_loop_new")]
-    private extern static IntPtr g_main_loop_new (IntPtr context,
-                                                  bool   is_running);
+  public class TestServer
+  {
+    public Connection connection;
+    public Service service;
 
-  [DllImport (GLibname, EntryPoint="g_main_loop_unref")]
-    private extern static void g_main_loop_unref (IntPtr loop);
+    public TestServer()
+    {
+      Application.Init();
+      
+      System.Console.WriteLine("Starting server...");
 
-  [DllImport (GLibname, EntryPoint="g_main_loop_run")]
-    private extern static void g_main_loop_run (IntPtr loop);
+      connection = Bus.GetSessionBus();
+      service = new Service(connection, "org.freedesktop.Test");
+      TestObject testObject = new TestObject();
+      service.RegisterObject(testObject, "/org/freedesktop/Test/TestObject");
+    }
+    
+    public void StartServer()
+    {
+      Application.Run();
+    }
+  }
 
-  [DllImport (GLibname, EntryPoint="g_main_loop_quit")]
-    private extern static void g_main_loop_quit (IntPtr loop);
-  
-  [DllImport (GThreadname, EntryPoint="g_thread_init")]
-    private extern static void g_thread_init (IntPtr vtable);
+  [Interface("org.freedesktop.Test.TestObject")]
+  public class TestObject
+  {
+    [Method]
+    public virtual int Test1(string x)
+    {
+      System.Console.WriteLine("Called: " + x);
+      return 5;
+    }
+  }    
 }
diff --git a/mono/example/EchoClient.cs b/mono/example/EchoClient.cs
new file mode 100644 (file)
index 0000000..dc20771
--- /dev/null
@@ -0,0 +1,19 @@
+namespace Foo
+{
+  using System;
+  using DBus;
+
+  public class EchoClient
+  {
+    public static int Main(string [] args)
+    {
+      Connection connection = Bus.GetSessionBus();
+      Service service = Service.Get(connection, "org.freedesktop.Test");
+      Echoer echoer = (Echoer) 
+       service.GetObject(typeof(Echoer), "/org/freedesktop/Test/Echoer");
+      System.Console.WriteLine(echoer.Echo("Hello world!"));
+      
+      return 0;
+    }
+  }
+}
diff --git a/mono/example/EchoServer.cs b/mono/example/EchoServer.cs
new file mode 100644 (file)
index 0000000..243a273
--- /dev/null
@@ -0,0 +1,23 @@
+namespace Foo
+{
+  using System;
+  using DBus;
+  using Gtk;
+
+  public class EchoServer
+  {
+    public static int Main(string [] args)
+    {
+      Application.Init();
+      
+      Connection connection = Bus.GetSessionBus();
+      Service service = new Service(connection, "org.freedesktop.Test");
+      Echoer echoer = new Echoer();
+      service.RegisterObject(echoer, "/org/freedesktop/Test/Echoer");
+      
+      Application.Run();
+      
+      return 0;
+    }
+  }
+}
diff --git a/mono/example/Echoer.cs b/mono/example/Echoer.cs
new file mode 100644 (file)
index 0000000..bc5a843
--- /dev/null
@@ -0,0 +1,16 @@
+namespace Foo
+{
+  using System;
+  using DBus;
+
+  [Interface("org.freedesktop.Test.Echoer")]
+  public class Echoer
+  {
+    [Method]
+    public virtual string Echo(string message)
+    {
+      System.Console.WriteLine("I received: " + message);
+      return "Reply: " + message;
+    }
+  }
+}
diff --git a/mono/example/Makefile.am b/mono/example/Makefile.am
new file mode 100644 (file)
index 0000000..2355bf3
--- /dev/null
@@ -0,0 +1,19 @@
+DESTDIR=
+
+NOINST_EXES=echo-server.exe echo-client.exe
+
+all: $(NOINST_EXES)
+
+echo-server.exe: EchoServer.cs Echoer.cs
+       $(MCS) $(MCSFLAGS) --unsafe --target exe -L .. -r dbus-sharp.dll -r gtk-sharp -o echo-server.exe EchoServer.cs Echoer.cs
+
+echo-client.exe: EchoClient.cs Echoer.cs
+       $(MCS) $(MCSFLAGS) --unsafe --target exe -L .. -r dbus-sharp.dll -o echo-client.exe EchoClient.cs Echoer.cs
+
+clean:
+       rm -f $(NOINST_EXES)
+
+install: all
+
+EXTRA_DIST=EchoServer.cs EchoClient.cs Echoer.cs
+