D-BUS C++: method marshalling objects
Murray Cumming
murrayc at murrayc.com
Fri Oct 14 01:17:30 PDT 2005
> Murray Cumming, Paul Durante, and others who might be interested:
>
> After studying Paul's "cbus" code I have made numerous improvements to
> my own C++ wrapper for D-BUS. It is still very much a work in progress
> but I have implemented an IMHO quite neat feature that you might know
> how to make even better.
>
> The template juggling is partly inspired by libsigc++ so Murray will
> probably have ideas for improvement.
Well done. I chose to delay thinking about this particular problem. It's
something that's probably much easier in dynamic languages like python.
How about actually depending on libsigc++? It's not a controversial
dependency. I think we have a base class that could be used in the API as
a generic method/callback parameter.
If necessary, we can think about API additions to libsigc++.
> About my design:
>
> I have one abstract base class for each interface I expose via D-BUS,
> for example "Device". I have an implementation of this interface, for
> example "DeviceImpl".
>
> For each interface I expose via D-BUS I have a class (e.g.
> "DeviceHandler") to handle method calls made to this interface for any
> object.
>
> In order to make this letter as short as possible I have left out a lot,
> maybe too much. If you want to know more, just ask.
I'd like to see what the macros do. Could you put a tarball or cvs
repository online somewhere?
> Improvements:
>
> Previously I had a "HandleMessage" method in the handler class (for
> example "DeviceHandler") that examined the member property of the
> incoming message and called a method to marshall that method.
>
> After looking at Paul's code I pulled myself together and replaced the
> "HandleMessage" method with code to register the functions that
> marshalled the individual D-BUS method calls.
>
> However, I wasn't satisfied. The marshalling functions always looked the
> same:
>
> 1. Decode parameters from incoming message
> 2. Call the corresponding method on the implementation object (eg. a
> "DeviceImpl" object) with those parameters
> 3. Create reply message
> 4. Write return value (if any) to reply message
>
> So I asked myself: how can I avoid writing that code again and again?
>
> I had this function to register a method handler:
>
> template<class U>
> void RegisterMethod(
> const std::string& name,
> Message_ptr (U::*handler)(Object_ptr, Message_ptr))
>
> But I wanted something like this:
>
> void RegisterMethod(const std::string& name, method)
>
> After some thinking and looking at libsigc++ I came up with multiple
> functions like this, where T is the interface (e.g. "Device"):
>
> template <class T_return>
> void RegisterMethod(const std::string& name, T_return (T::*handler)())
>
> template <class T_return, class T_arg1>
> void RegisterMethod(const std::string& name, T_return
> (T::*handler)(T_arg1))
>
> These functions create something I call (in lack of better knowledge of
> the English language) "method marshalling objects", for example:
>
> template <class T_object, class T_return,
> class T_arg1>
> class Method1 : public MethodBase<T_object>
> {
> public:
> typedef boost::shared_ptr<T_object> Object_ptr;
> typedef T_return (T_object::*HandlerType)(
> T_arg1);
>
> private:
> HandlerType mHandler;
>
> public:
> Method1(
> const std::string& name,
> HandlerType handler) :
> MethodBase<T_object>(name),
> mHandler(handler)
> {
> }
>
> virtual ~Method1()
> {}
>
> virtual Message_ptr HandleMessage(
> Object_ptr object,
> Message_ptr message)
> {
> T_arg1 arg1;
>
> *message >> arg1;
>
> Message_ptr reply(
> Message::NewMethodReturn(message) );
>
> *reply << (*object.*mHandler) (arg1);
>
> return reply;
> }
> };
>
>
> And voila! As long as I have a RegisterMethod function and a method
> marshalling object for the right number of parameters, it's very simple
> to add or remove methods on my D-BUS objects. Example from the
> "DeviceHandler" constructor:
>
> #define REGISTER_METHOD(method) RegisterMethod(#method, &Device::method)
> REGISTER_METHOD(Disconnect);
> REGISTER_METHOD(GetAddress);
> REGISTER_METHOD(GetName);
> REGISTER_METHOD(GetProperties);
> REGISTER_METHOD(GetState);
> #undef REGISTER_METHOD
>
>
> One obstacle was void methods, so I have special RegisterMethod
> functions and a method marshalling objects for those.
>
> Another obstacle was that some of my interfaces passed parameters by
> reference, for example const std::string&. This obviously does not work
> with the implementation of my method marshalling objects seen above, so
> I changed my interfaces to pass the strings by value instead.
>
> The method marshalling objects would probably benefit from being
> generated (like for example signal.h in libsigc++) but that's a future
> improvement.
>
> Is this any good or am I wasting my time?
>
> --
> Regards,
> -\- David Eriksson -/-
Murray Cumming
murrayc at murrayc.com
www.murrayc.com
www.openismus.com
More information about the dbus
mailing list