在此先感谢http://blog./u3/111961/showart_2187819.html 。这是篇极好的文章。 在上次学习中,我们写了client小例子,非常简单,而且通过dbus-binding-tool生成的头文件,非常规范。相比执行,server稍微复杂些,仍然使用上次的xml文件,但是去掉annotation,更为本原一些。文件wei.xml如下: <?xml version="1.0" encoding="UTF-8" ?> <node name="/com/wei/MyObject"> <interface name="com.wei.MyObject.Sample"> <method name="Test"> <arg name="x" type="u" direction="in" /> <arg name="d_ret" type="d" direction="out" /> </method > </interface > </node >
客户端小程序上次学习给出,正好用于实验。下面详细讲述步骤。 步骤一:生成头文件 dbus-binding-tool --mode=glib-server --prefix=com_wei wei.xml > wei_server.h
注意,--prefix是不可缺少的参数,在有些文章中,没有提到这个,至少我在Moblin的操作系统中测试是需要的。通常来讲,对于项目,也需要提供一个区分的命名空间,无论是否必须,建议加上。"--prefix"参数定义了对象前缀。设对象前缀是$(prefix),则生成的DBusGObjectInfo结构变量名就是dbus_glib_$(prefix)_object_info。 生成了头文件wei_server.h如下: /* Generated by dbus-binding-tool; do not edit! */
#ifndef __dbus_glib_marshal_com_wei_MARSHAL_H__ #define __dbus_glib_marshal_com_wei_MARSHAL_H__
#include <glib-object.h>
G_BEGIN_DECLS
#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_char (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) #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 #endif /* !G_ENABLE_DEBUG */
/* BOOLEAN:UINT,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.OI8HBV:1) */ extern void dbus_glib_marshal_com_wei_BOOLEAN__UINT_POINTER_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); void dbus_glib_marshal_com_wei_BOOLEAN__UINT_POINTER_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gboolean (*GMarshalFunc_BOOLEAN__UINT_POINTER_POINTER) (gpointer data1, guint arg_1, gpointer arg_2, gpointer arg_3, gpointer data2); register GMarshalFunc_BOOLEAN__UINT_POINTER_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; gboolean v_return;
g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 4);
if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_BOOLEAN__UINT_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
v_return = callback (data1, g_marshal_value_peek_uint (param_values + 1), g_marshal_value_peek_pointer (param_values + 2), g_marshal_value_peek_pointer (param_values + 3), data2);
g_value_set_boolean (return_value, v_return); }
G_END_DECLS
#endif /* __dbus_glib_marshal_com_wei_MARSHAL_H__ */
#include <dbus/dbus-glib.h> static const DBusGMethodInfo dbus_glib_com_wei_methods[] = { { (GCallback) com_wei_test , dbus_glib_marshal_com_wei_BOOLEAN__UINT_POINTER_POINTER, 0 }, };
const DBusGObjectInfo dbus_glib_com_wei_object_info = { 0, dbus_glib_com_wei_methods, 1, "com.wei.MyObject.Sample/0Test/0S/0x/0I/0u/0d_ret/0O/0F/0N/0d/0/0/0", "/0", "/0" };
步骤二:编写Object文件 在D-Bus学习(五) 和学习(六)中 ,我们给出了底层的例子,直接进行通信操作,没有涉及到对象的概念,使用Glib的高层接口编写的例子,我们可以生成对象,在对象中定义接口中方法和信令的操作。说实在,我对非JAVA的对象都不太熟悉,GObject更是……,不过工具嘛,照着用就是了。既然我们在xml中给出对象的路径,我们可以将对象命名为ComWeiMyObject。头文件com_wei_myobject.h如下: #ifndef COM_WEI_MYOBJECT_H #define COM_WEI_MYOBJECT_H
typedef struct ComWeiMyObject ComWeiMyObject; typedef struct ComWeiMyObjectClass ComWeiMyObjectClass;
struct ComWeiMyObject { GObject parent; };
struct ComWeiMyObjectClass { GObjectClass parent; };
#define COM_WEI_MYOBJECT_TYPE (com_wei_myobject_get_type())
GType com_wei_myobject_get_type(void); gboolean com_wei_test(ComWeiMyObject * obj , const guint IN_x, gdouble * OUT_d_ret, GError ** error);
#endif
在头文件,我们定义了一个方法处理函数com_wei_test,这个函数也就是wei_server.h中com_wei_test。它的第一个参数就是对象,后面是这个方法的参数,包括输入和输出。下面是com_wei_myobject.c文件: #include "com_wei_myobject.h"
G_DEFINE_TYPE(ComWeiMyObject,com_wei_myobject,G_TYPE_OBJECT)
static void com_wei_myobject_init(ComWeiMyObject * object) {//这个两个init函数大概是GObject的套路,在这个简单的小例子中,没有什么特别的初始化处理 } static void com_wei_myobject_class_init(ComWeiMyObjectClass * klass) { }
gboolean com_wei_test (ComWeiMyObject * obj, const guint IN_x, gdouble* OUT_d_ret, GError ** error) { //我们只做测试,简单检测输入参数,直接回复输出结果 printf("com_wei_test() get input param: x= %d/n",IN_x); * OUT_d_ret = 0.99; return TRUE; }
实验例子尽量简单,在这个ComWeiMyObject的对象中实现了com.wei.MyObject.Sample接口的Test方法:com_wei_test。 步骤三:写Server程序 OK,我们已经准备好写Server程序,由于Server需要长期监听,因此需要加入Loop循环。Loop已经在D-Bus学习四 的异步例子中学过。我们注意到使用GLib中函数与底层libdbus API的差异,例如底层API使用dbus_bus_get,高层GLib使用dbus_g_bus_get。这种命名方式,在我们提供更高层的接口时可以借鉴。GLib的D-Bus的API参考为http://dbus./doc/api/html/group__DBusGLib.html #include "com_wei_myobject.h" #include "wei_server.h" //注意此两头文件的先后顺序
int main(int argc, char ** argv) { DBusGConnection * conn; GMainLoop * main_loop = NULL; ComWeiMyObject * obj; GError * error = NULL; DBusGProxy * bus_proxy; int request_name_result;
g_type_init(); main_loop = g_main_loop_new(NULL,FALSE); //在自动生成的wei_server.h中定义了DBusGObjectInfo dbus_glib_com_wei_object_info, Install introspection information about the given object GType sufficient to allow methods on the object to be invoked by name. 这样,可以在收到信息的时候,可以触发调用它的方法。 dbus_g_object_type_install_info(COM_WEI_MYOBJECT_TYPE , & dbus_glib_com_wei_object_info ); //建议与session dbus的连接,在以前学习过 conn = dbus_g_bus_get(DBUS_BUS_SESSION,&error); if(conn == NULL){ g_printerr("Failed to connect D-Bus session Daemon!"); g_error_free(error); return 1; } //为连接起一个名字,对于GLib,这个处理比底层的API接口复杂,需要向系统DBus的管理者org.freedesktop.DBus,调用它的接口的方法"RequestName"来实现。居然更复杂,比较奇怪。 bus_proxy = dbus_g_proxy_new_for_name(conn, "org.freedesktop.DBus","/","org.freedesktop.DBus"); if(!dbus_g_proxy_call(bus_proxy,"RequestName ",&error, G_TYPE_STRING,"com.wei.test", G_TYPE_UINT,0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)){ g_printerr("Request Name error : %s/n",error->message); return 1; } obj = g_object_new(COM_WEI_MYOBJECT_TYPE,NULL); //将对象在指定的path注册到连接上。 Registers a GObject at the given path. 当有消息通过连接,经过路径,找到对象后,根据前面前面的dbus_g_object_type_insall_info,能够调用对应的处理方式。 dbus_g_connection_register_g_object(conn, "/com/wei/MyObject",G_OBJECT(obj));
g_main_loop_run(main_loop); return 0; }
OK,完成。如果我们像上一次学习在xml中对方法加上<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="wei_response" />,则该方法的调用函数不是自动生成的com_wei_test,而是wei_response。通过这种方式,我们可以指定我们想使用的名字,这在tutorial 中详细介绍。
|