1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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.
|