1
// Copyright 2006 Alp Toker <alp@atoker.com>
2
// This software is made available under the MIT License
3
// See COPYING for details
6
using System.Reflection;
7
using System.Reflection.Emit;
8
using System.Collections.Generic;
14
protected Connection conn;
16
ObjectPath object_path;
18
//protected BusObject ()
23
public BusObject (Connection conn, string bus_name, ObjectPath object_path)
26
this.bus_name = bus_name;
27
this.object_path = object_path;
30
public Connection Connection
44
public ObjectPath Path
51
public void ToggleSignal (string iface, string member, Delegate dlg, bool adding)
53
MatchRule rule = new MatchRule ();
54
rule.MessageType = MessageType.Signal;
55
rule.Fields.Add (FieldCode.Interface, new MatchTest (iface));
56
rule.Fields.Add (FieldCode.Member, new MatchTest (member));
57
rule.Fields.Add (FieldCode.Path, new MatchTest (object_path));
60
if (conn.Handlers.ContainsKey (rule))
61
conn.Handlers[rule] = Delegate.Combine (conn.Handlers[rule], dlg);
63
conn.Handlers[rule] = dlg;
64
conn.AddMatch (rule.ToString ());
67
conn.Handlers[rule] = Delegate.Remove (conn.Handlers[rule], dlg);
68
if (conn.Handlers[rule] == null) {
69
conn.RemoveMatch (rule.ToString ());
70
conn.Handlers.Remove (rule);
75
public void SendSignal (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception)
79
//TODO: don't ignore retVal, exception etc.
81
Signature outSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr);
83
Signal signal = new Signal (object_path, iface, member);
84
signal.message.Signature = outSig;
86
Message signalMsg = signal.message;
87
signalMsg.Body = writer.ToArray ();
89
conn.Send (signalMsg);
92
public object SendMethodCallOld (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception)
96
//TODO: don't ignore retVal, exception etc.
98
Signature inSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr);
100
MethodCall method_call = new MethodCall (object_path, iface, member, bus_name, inSig);
102
Message callMsg = method_call.message;
103
callMsg.Body = writer.ToArray ();
107
//TODO: complete out parameter support
109
Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ());
110
Signature outParmSig = Signature.GetSig (outParmTypes);
112
if (outParmSig != Signature.Empty)
113
throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'");
116
Type[] outTypes = new Type[1];
117
outTypes[0] = retType;
119
//we default to always requiring replies for now, even though unnecessary
120
//this is to make sure errors are handled synchronously
121
//TODO: don't hard code this
122
bool needsReply = true;
124
//if (mi.ReturnType == typeof (void))
125
// needsReply = false;
127
callMsg.ReplyExpected = needsReply;
128
callMsg.Signature = inSig;
135
#if PROTO_REPLY_SIGNATURE
137
Signature outSig = Signature.GetSig (outTypes);
138
callMsg.Header[FieldCode.ReplySignature] = outSig;
142
Message retMsg = conn.SendWithReplyAndBlock (callMsg);
144
object retVal = null;
146
//handle the reply message
147
switch (retMsg.Header.MessageType) {
148
case MessageType.MethodReturn:
149
object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes);
150
if (retVals.Length != 0)
151
retVal = retVals[retVals.Length - 1];
153
case MessageType.Error:
154
//TODO: typed exceptions
155
Error error = new Error (retMsg);
156
string errMsg = String.Empty;
157
if (retMsg.Signature.Value.StartsWith ("s")) {
158
MessageReader reader = new MessageReader (retMsg);
159
errMsg = reader.ReadString ();
161
exception = new Exception (error.ErrorName + ": " + errMsg);
164
throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error");
170
public MessageReader SendMethodCall (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception)
174
//TODO: don't ignore retVal, exception etc.
176
Signature inSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr);
178
MethodCall method_call = new MethodCall (object_path, iface, member, bus_name, inSig);
180
Message callMsg = method_call.message;
181
callMsg.Body = writer.ToArray ();
185
//TODO: complete out parameter support
187
Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ());
188
Signature outParmSig = Signature.GetSig (outParmTypes);
190
if (outParmSig != Signature.Empty)
191
throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'");
194
Type[] outTypes = new Type[1];
195
outTypes[0] = retType;
197
//we default to always requiring replies for now, even though unnecessary
198
//this is to make sure errors are handled synchronously
199
//TODO: don't hard code this
200
bool needsReply = true;
202
//if (mi.ReturnType == typeof (void))
203
// needsReply = false;
205
callMsg.ReplyExpected = needsReply;
206
callMsg.Signature = inSig;
213
#if PROTO_REPLY_SIGNATURE
215
Signature outSig = Signature.GetSig (outTypes);
216
callMsg.Header[FieldCode.ReplySignature] = outSig;
220
Message retMsg = conn.SendWithReplyAndBlock (callMsg);
222
MessageReader retVal = null;
224
//handle the reply message
225
switch (retMsg.Header.MessageType) {
226
case MessageType.MethodReturn:
227
retVal = new MessageReader (retMsg);
229
case MessageType.Error:
230
//TODO: typed exceptions
231
Error error = new Error (retMsg);
232
string errMsg = String.Empty;
233
if (retMsg.Signature.Value.StartsWith ("s")) {
234
MessageReader reader = new MessageReader (retMsg);
235
errMsg = reader.ReadString ();
237
exception = new Exception (error.ErrorName + ": " + errMsg);
240
throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error");
246
public void Invoke (MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception)
248
outArgs = new object[0];
252
MethodInfo mi = methodBase as MethodInfo;
254
if (mi != null && mi.IsSpecialName && (methodName.StartsWith ("add_") || methodName.StartsWith ("remove_"))) {
255
string[] parts = methodName.Split (new char[]{'_'}, 2);
256
string ename = parts[1];
257
Delegate dlg = (Delegate)inArgs[0];
259
ToggleSignal (Mapper.GetInterfaceName (mi), ename, dlg, parts[0] == "add");
264
Type[] inTypes = Mapper.GetTypes (ArgDirection.In, mi.GetParameters ());
265
Signature inSig = Signature.GetSig (inTypes);
267
MethodCall method_call;
270
//build the outbound method call message
272
//this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced
275
iface = Mapper.GetInterfaceName (mi);
277
//map property accessors
278
//TODO: this needs to be done properly, not with simple String.Replace
279
//note that IsSpecialName is also for event accessors, but we already handled those and returned
280
if (mi != null && mi.IsSpecialName) {
281
methodName = methodName.Replace ("get_", "Get");
282
methodName = methodName.Replace ("set_", "Set");
285
method_call = new MethodCall (object_path, iface, methodName, bus_name, inSig);
287
callMsg = method_call.message;
289
if (inArgs != null && inArgs.Length != 0) {
290
MessageWriter writer = new MessageWriter (Connection.NativeEndianness);
291
writer.connection = conn;
293
for (int i = 0 ; i != inTypes.Length ; i++)
294
writer.Write (inTypes[i], inArgs[i]);
296
callMsg.Body = writer.ToArray ();
300
//TODO: complete out parameter support
302
Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ());
303
Signature outParmSig = Signature.GetSig (outParmTypes);
305
if (outParmSig != Signature.Empty)
306
throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'");
309
Type[] outTypes = new Type[1];
310
outTypes[0] = mi.ReturnType;
312
//we default to always requiring replies for now, even though unnecessary
313
//this is to make sure errors are handled synchronously
314
//TODO: don't hard code this
315
bool needsReply = true;
317
//if (mi.ReturnType == typeof (void))
318
// needsReply = false;
320
callMsg.ReplyExpected = needsReply;
321
callMsg.Signature = inSig;
328
#if PROTO_REPLY_SIGNATURE
330
Signature outSig = Signature.GetSig (outTypes);
331
callMsg.Header[FieldCode.ReplySignature] = outSig;
335
Message retMsg = conn.SendWithReplyAndBlock (callMsg);
337
//handle the reply message
338
switch (retMsg.Header.MessageType) {
339
case MessageType.MethodReturn:
340
object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes);
341
if (retVals.Length != 0)
342
retVal = retVals[retVals.Length - 1];
344
case MessageType.Error:
345
//TODO: typed exceptions
346
Error error = new Error (retMsg);
347
string errMsg = String.Empty;
348
if (retMsg.Signature.Value.StartsWith ("s")) {
349
MessageReader reader = new MessageReader (retMsg);
350
errMsg = reader.ReadString ();
352
exception = new Exception (error.ErrorName + ": " + errMsg);
355
throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error");
361
public static object GetObject (Connection conn, string bus_name, ObjectPath object_path, Type declType)
363
Type proxyType = TypeImplementer.Root.GetImplementation (declType);
365
//BusObject inst = (BusObject)Activator.CreateInstance (proxyType);
366
object instObj = Activator.CreateInstance (proxyType);
367
BusObject inst = GetBusObject (instObj);
369
inst.bus_name = bus_name;
370
inst.object_path = object_path;
375
static Dictionary<object,BusObject> boCache = new Dictionary<object,BusObject>();
376
public static BusObject GetBusObject (object instObj)
378
if (instObj is BusObject)
379
return (BusObject)instObj;
382
if (boCache.TryGetValue (instObj, out inst))
385
inst = new BusObject ();
386
boCache[instObj] = inst;
391
public Delegate GetHookupDelegate (EventInfo ei)
393
DynamicMethod hookupMethod = TypeImplementer.GetHookupMethod (ei);
394
Delegate d = hookupMethod.CreateDelegate (ei.EventHandlerType, this);