D-BUS C++: method marshalling objects

David Eriksson twogood at users.sourceforge.net
Tue Oct 11 02:13:20 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.

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.

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 -/-

        SynCE - http://synce.sourceforge.net
      ScummVM - http://scummvm.sourceforge.net
     Desquirr - http://desquirr.sourceforge.net



More information about the dbus mailing list