dbus-glib是dbus底层接口的一个封装。本讲我们用dbus-glib做一个dus接口,并写一个客户程序。
1、接口描述文件
首先编写接口描述文件.我们要实现的连接的公共名是"org.freedesktop.messagetestcuiyf",接口描述文件如下:
$cat messagetest.xml
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/org/freedesktop/MessageTest/Device">
<interface name="org.freedesktop.MessageTest">
<method name="SendMessage">
<arg name="number" type="s"/>
<arg name="contents" type="s"/>
<arg name="featuremap" type="a{sv}"/>
<arg type="i" direction="out"/>
</method>
<signal name="IncomingMessage">
<arg name="address" type="s"/>
<arg name="contents" type="s"/>
<arg name="features" type="a{sv}"/>
</signal>
</interface>
</node>
我们要在连接"org.freedesktop.messagetestcuiyf"中实现对象"/org/freedesktop/MessageTest/Device"。这个对象有接口"org.freedesktop.MessageTest",接口有方法SendMessage和信号"IncomingMessage"
SendMessage方法和IncomingMessage信号除了两个字符串参数外,还有一个a{sv}参数,这是一个哈希表,即python的字典。 键-值对的键类型是字符串,值类型是VARIANT。这个接口是openmoko fso接口的一部分。 但为简单起见,本例在哈希表部分,只用三个键值。
- 键"alphabet"对应的值类型是字符串。
- 键"csm_num"对应的值类型是INT32。
- 键"csm_seq"对应的值类型是INT32。
请注意方法和信号名应采用单词连写,首字母大写的格式
由接口描述文件生成绑定文件
有一个叫dbus-binding-tool的工具,它读入接口描述文件,产生一个绑定文件。这个文件包含了dbus对象的接口信息。 在主程序中我们通过dbus_g_object_type_install_info函数向dbus-glib登记对象信息(DBusGObjectInfo结构)。
直接执行命令即可生成绑定文件
dbus-binding-tool --prefix=gsm_messagetest --mode=glib-server --output=messagetest-glue.h messagetest.xml
本例使用了autotool,在Makefile.am中可以这样调用dbus-binding-tool:
messagetest-glue.h: messagetest.xml
$(LIBTOOL) --mode=execute dbus-binding-tool --prefix=gsm_messagetest --mode=glib-server --output=messagetest-glue.h $(srcdir)/messagetest.xml
"--prefix"参数定义了对象前缀。设对象前缀是$(prefix),则生成的DBusGObjectInfo结构变量名就是dbus_glib_$(prefix)_object_info。 绑定文件会为接口方法定义回调函数。回调函数的名称是这样的:首先将xml中的方法名称转换到全部小写,下划线分隔的格式,然后增加前缀"$(prefix)_"。 例如:如果xml中有方法SendMessage,绑定文件就会引用一个名称为$(prefix)_send_message的函数。
绑定文件还会为接口方法生成用于散集(Unmarshaling)的函数。在dbus消息中,方法参数是以流格式存在的。 该函数将方法参数由数据流还原到glib的数据格式,并传入方法的回调函数。 本例中,dbus-binding-tool生成以下的messagetest-glue.h:
/* Generated by dbus-binding-tool; do not edit! */
/* This file is generated by glib-genmarshal, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */
#include <glib-object.h>
#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
#define g_marshal_value_peek_char(v) g_value_get_schar (v)
#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
#define g_marshal_value_peek_int(v) g_value_get_int (v)
#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
#define g_marshal_value_peek_long(v) g_value_get_long (v)
#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
#define g_marshal_value_peek_float(v) g_value_get_float (v)
#define g_marshal_value_peek_double(v) g_value_get_double (v)
#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v) g_value_get_param (v)
#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
#define g_marshal_value_peek_object(v) g_value_get_object (v)
#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
* Do not access GValues directly in your code. Instead, use the
* g_value_get_*() functions
*/
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
#define g_marshal_value_peek_char(v) (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
#define g_marshal_value_peek_long(v) (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v) (v)->data[0].v_float
#define g_marshal_value_peek_double(v) (v)->data[0].v_double
#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */
/* Prototype for -Wmissing-prototypes */
G_BEGIN_DECLS
extern
void dbus_glib_marshal_gsm_messagetest_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
G_END_DECLS
void
dbus_glib_marshal_gsm_messagetest_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER) (gpointer data1,
gpointer arg1,
gpointer arg2,
gpointer arg3,
gpointer arg4,
gpointer arg5,