From beb9cd2eb219e04f9872c6a4dd743d5d1c36b4b1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 13 Jun 2005 03:01:30 +0000 Subject: 2005-06-12 Colin Walters Async signals and various bugfixes and testing by Ross Burton . * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. (dbus_gvalue_genmarshal_name_from_type) (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. (dbus_g_value_types_init, dbus_gtype_from_signature) (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) (dbus_gtypes_from_arg_signature): New function prototypes. (dbus_gvalue_demarshal): Take context and error arguments. (dbus_gvalue_demarshal_variant): New function. (dbus_gvalue_demarshal_message): New function. (dbus_gvalue_store): Delete. * glib/dbus-gvalue.c: File has been almost entirely rewritten; now we special-case more types such as DBUS_TYPE_SIGNATURE, handle arrays and hash tables correctly, etc. Full support for recursive values is not yet complete. * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last argument of signal to G_TYPE_POINTER since we now pass a structure. (lookup_g_marshaller): Delete in favor of _dbus_gobject_lookup_marshaller. (marshal_dbus_message_to_g_marshaller): Use _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message to handle remote signal callbacks. (dbus_g_proxy_new_from_proxy): New function; creates a new DBusGProxy by copying an existing one. (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) (dbus_g_proxy_get_path): New functions. (dbus_g_proxy_marshal_args_to_message): New function; factored out of existing code. (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments from a varargs array. (dbus_g_proxy_begin_call_internal): New function. (dbus_g_proxy_end_call_internal): New function. (dbus_g_proxy_begin_call): Take GTypes instead of DBus types as arguments; simply invoke dbus_g_proxy_begin_call_internal after collecting args into value array. (dbus_g_proxy_end_call): Take GTypes instead of DBus types; invoke dbus_g_proxy_end_call_internal. (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and end_call_internal. (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus types. (array_free_all): New function. (dbus_g_proxy_add_signal): Take GTypes. * glib/dbus-gobject.h: (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): Prototype. * glib/dbus-gobject.c: Add a global marshal_table hash which stores mappings from type signatures to marshallers. Change lots of invocations of dbus_gtype_to_dbus_type to dbus_gtype_to_signature. (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. (introspect_signals): Fix test for query.return_type. (set_object_property): Update invocation of dbus_gvalue_demarshal. (invoke_object_method): Many changes. Handle asynchronous invocations. Convert arguments with dbus_gvalue_demarshal_message. Handle errors. Use DBusSignatureIter instead of strlen on args. Handle all arguments generically. Special-case variants. (dbus_g_method_return, dbus_g_method_return_error): New function. (DBusGSignalClosure): New structure, closes over signal information. (dbus_g_signal_closure_new): New function. (dbus_g_signal_closure_finalize): New function. (signal_emitter_marshaller): New function; is special marshaller which emits signals on bus. (export_signals): New function; introspects object signals and connects to them. (dbus_g_object_type_install_info): Take GType instead of GObjectClass. (dbus_g_connection_register_g_object): Invoke export_signals. (dbus_g_connection_lookup_g_object): New function. (DBusGFuncSignature) New structure; used for mapping type signatures to marshallers. (funcsig_hash): New function; hashes DBusGFuncSignature. (funcsig_equal): New function; compares DBusGFuncSignature. (_dbus_gobject_lookup_marshaller): New function. (dbus_g_object_register_marshaller): New function; used to register a marshaller at runtime for a particular signature. * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC which notes a server method implementation should be asynchronous. * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call dbus_g_value_types_init. (write_formal_parameters): Use dbus_gtype_from_signature. Handle variants specially. (dbus_g_type_get_lookup_function): Turn GType into an invocation of a lookup function. (write_args_for_direction): Use dbus_g_type_get_lookup_function. (write_untyped_out_args): New method; write output arguments. (write_formal_declarations_for_direction): Function for writing prototypes. (write_formal_parameters_for_direction): Function for writing implementations. (write_typed_args_for_direction): Function for writing arguments prefixed with GTypes. (write_async_method_client): Write out async version of method. * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. (dbus_g_type_get_marshal_name): Move mapping from GType to marshal name into here. (dbus_g_type_get_c_name): Move into here. (compute_marshaller): Convert signature to type with dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. (compute_marshaller_name): Ditto. (compute_marshaller): Handle async signal annotations. (gather_marshallers): Return if we don't have a known prefix. (generate_glue): Collect introspection blob here, and write all of the blob at the end. This allows an object with multiple interfaces to work. Mark async methods in introspection blob. * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add dbus-gtype-specialized.c, dbus-gtype-specialized.h, dbus-gvalue-utils.h, dbus-gvalue-utils.c. * dbus/dbus-glib.h: Don't include dbus-protocol.h; this avoids people accidentally using DBUS_TYPE_* which should not be necessary anymore. Do include dbus-gtype-specialized.h, which are utilities for GLib container types. Add various #defines for types such as DBUS_TYPE_G_BOOLEAN_ARRAY. (DBusGValueIterator, DBusGValue): Define, not fully used yet. (dbus_g_value_get_g_type): Type for recursive value. (dbus_g_value_open, dbus_g_value_iterator_get_value) (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) (dbus_g_value_free): Prototypes. (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. (dbus_g_proxy_set_interface): Prototype. (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus types. (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): Accessors. (DBusGAsyncData, DBusGMethodInvocation): Structures for doing async invocations. (dbus_g_method_return, dbus_g_method_return_error): Prototypes. * doc/dbus-tutorial.xml: Update GLib section. * tools/dbus-viewer.c (load_child_nodes): Update for new invocation type of dbus_g_proxy_end_call. (load_from_service_thread_func): Ditto. * tools/print-introspect.c (main): Ditto. * tools/dbus-names-model.c (have_names_notify) (names_model_reload, names_model_set_connection) Use GTypes. * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, needed since Python bindings use GLib bindings. * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. Add --prefix argument. * tools/Makefile.am: Define DBUS_COMPILATION. Remove unneeded --ignore-unsupported arg. * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: * test/glib/test-dbus-glib.c: Add many more tests. --- doc/TODO | 9 +- doc/dbus-tutorial.xml | 680 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 613 insertions(+), 76 deletions(-) (limited to 'doc') diff --git a/doc/TODO b/doc/TODO index 28a772d5..659dde15 100644 --- a/doc/TODO +++ b/doc/TODO @@ -39,12 +39,11 @@ Important for 1.0 Important for 1.0 GLib Bindings === - - finish dbus-glib-tool support for adding introspection - data to GObject and autoexporting GObject using same + - Annotations for "do not take ownership of this return value" on server - - Need to make sure that dbus-glib.h never returns any - dbus_malloc() memory, only g_malloc(). - dbus_g_proxy_end_call() is the major offender. + - Fix signals + + - Fix errors - need to get specific error back, not UnmappedError crap - DBusGProxy doesn't emit "destroy" when it should diff --git a/doc/dbus-tutorial.xml b/doc/dbus-tutorial.xml index 22906ac9..6ee32927 100644 --- a/doc/dbus-tutorial.xml +++ b/doc/dbus-tutorial.xml @@ -449,20 +449,294 @@ GLib API: Using Remote Objects - The GLib binding is defined in the header file - <dbus/dbus-glib.h>. The API is very small, in sharp contrast to the - low-level <dbus/dbus.h>. - + <dbus/dbus-glib.h>. - - The GLib bindings are incomplete, see the TODO file and comments in the - source code. - - - -Here is a D-BUS program using the GLib bindings. + + D-BUS - GLib type mappings + + The heart of the GLib bindings for D-BUS is the mapping it + provides between D-BUS "type signatures" and GLib types + (GType). The D-BUS type system is composed of + a number of "basic" types, along with several "container" types. + + + Basic type mappings + + Below is a list of the basic types, along with their associated + mapping to a GType. + + + + + D-BUS basic type + GType + Free function + Notes + + + + + BYTE + G_TYPE_UCHAR + + + + BOOLEAN + G_TYPE_BOOLEAN + + + + INT16 + G_TYPE_INT + + Will be changed to a G_TYPE_INT16 once GLib has it + + UINT16 + G_TYPE_UINT + + Will be changed to a G_TYPE_UINT16 once GLib has it + + INT32 + G_TYPE_INT + + Will be changed to a G_TYPE_INT32 once GLib has it + + UINT32 + G_TYPE_UINT + + Will be changed to a G_TYPE_UINT32 once GLib has it + + INT64 + G_TYPE_GINT64 + + + + UINT64 + G_TYPE_GUINT64 + + + + DOUBLE + G_TYPE_DOUBLE + + + + STRING + G_TYPE_STRING + g_free + + + OBJECT_PATH + DBUS_TYPE_G_PROXY + g_object_unref + The returned proxy does not have an interface set; use dbus_g_proxy_set_interface to invoke methods + + + + + As you can see, the basic mapping is fairly straightforward. + + + + Container type mappings + + The D-BUS type system also has a number of "container" + types, such as DBUS_TYPE_ARRAY and + DBUS_TYPE_STRUCT. The D-BUS type system + is fully recursive, so one can for example have an array of + array of strings (i.e. type signature + aas). + + + However, not all of these types are in common use; for + example, at the time of this writing the author knows of no + one using DBUS_TYPE_STRUCT, or a + DBUS_TYPE_ARRAY containing any non-basic + type. The approach the GLib bindings take is pragmatic; try + to map the most common types in the most obvious way, and + let using less common and more complex types be less + "natural". + + + First, D-BUS type signatures which have an "obvious" + corresponding builtin GLib type are mapped using that type: + + + + + D-BUS type signature + Description + GType + C typedef + Free function + Notes + + + + + as + Array of strings + G_TYPE_STRV + char ** + g_strfreev + + + v + Generic value container + G_TYPE_VALUE + GValue * + g_value_unset + The calling conventions for values expect that method callers have allocated return values; see below. + + + + + + + The next most common recursive type signatures are arrays of + basic values. The most obvious mapping for arrays of basic + types is a GArray. Now, GLib does not + provide a builtin GType for + GArray. However, we actually need more than + that - we need a "parameterized" type which includes the + contained type. Why we need this we will see below. + + + The approach taken is to create these types in the D-BUS GLib + bindings; however, there is nothing D-BUS specific about them. + In the future, we hope to include such "fundamental" types in GLib + itself. + + + + + D-BUS type signature + Description + GType + C typedef + Free function + Notes + + + + + ay + Array of bytes + DBUS_TYPE_G_BYTE_ARRAY + GArray * + g_array_free + + + + au + Array of uint + DBUS_TYPE_G_UINT_ARRAY + GArray * + g_array_free + + + + ai + Array of int + DBUS_TYPE_G_INT_ARRAY + GArray * + g_array_free + + + + ax + Array of int64 + DBUS_TYPE_G_INT64_ARRAY + GArray * + g_array_free + + + + at + Array of uint64 + DBUS_TYPE_G_UINT64_ARRAY + GArray * + g_array_free + + + + ad + Array of double + DBUS_TYPE_G_DOUBLE_ARRAY + GArray * + g_array_free + + + + ab + Array of boolean + DBUS_TYPE_G_BOOLEAN_ARRAY + GArray * + g_array_free + + + + + + + + D-BUS also includes a special type DBUS_TYPE_DICT_ENTRY which + is only valid in arrays. It's intended to be mapped to a "dictionary" + type by bindings. The obvious GLib mapping here is GHashTable. Again, + however, there is no builtin GType for a GHashTable. + Moreover, just like for arrays, we need a parameterized type so that + the bindings can communiate which types are contained in the hash table. + + + At present, only strings are supported. Work is in progress to + include more types. + + + + + D-BUS type signature + Description + GType + C typedef + Free function + Notes + + + + + a{ss} + Dictionary mapping strings to strings + DBUS_TYPE_G_STRING_STRING_HASHTABLE + GHashTable * + g_hash_table_destroy + + + + + + + + + Arbitrarily recursive type mappings + + Finally, it is possible users will want to write or invoke D-BUS + methods which have arbitrarily complex type signatures not + directly supported by these bindings. For this case, we have a + DBusGValue which acts as a kind of special + variant value which may be iterated over manually. The + GType associated is + DBUS_TYPE_G_VALUE. + + + TODO insert usage of DBUS_TYPE_G_VALUE here. + + + + + A sample program + Here is a D-BUS program using the GLib bindings. int main (int argc, char **argv) @@ -470,10 +744,8 @@ main (int argc, char **argv) DBusGConnection *connection; GError *error; DBusGProxy *proxy; - DBusGPendingCall *call; char **name_list; - int name_list_len; - int i; + char **name_list_ptr; g_type_init (); @@ -495,15 +767,10 @@ main (int argc, char **argv) DBUS_PATH_ORG_FREEDESKTOP_DBUS, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS); - /* Call ListNames method */ - - call = dbus_g_proxy_begin_call (proxy, "ListNames", DBUS_TYPE_INVALID); - + /* Call ListNames method, wait for reply */ error = NULL; - if (!dbus_g_proxy_end_call (proxy, call, &error, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, - &name_list, &name_list_len, - DBUS_TYPE_INVALID)) + if (!dbus_g_proxy_invoke (proxy, "ListNames", &error, G_TYPE_INVALID, + G_TYPE_STRV, &name_list, G_TYPE_INVALID)) { g_printerr ("Failed to complete ListNames call: %s\n", error->message); @@ -514,77 +781,348 @@ main (int argc, char **argv) /* Print the results */ g_print ("Names on the message bus:\n"); - i = 0; - while (i < name_list_len) + + for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++) { - g_assert (name_list[i] != NULL); - g_print (" %s\n", name_list[i]); - ++i; + g_print (" %s\n", *name_list_ptr); } - g_assert (name_list[i] == NULL); - g_strfreev (name_list); + g_object_unref (proxy); + return 0; } + + + Program initalization + + A connection to the bus is acquired using + dbus_g_bus_get. Next, a proxy + is created for the object "/org/freedesktop/DBus" with + interface org.freedesktop.DBus + on the service org.freedesktop.DBus. + This is a proxy for the message bus itself. + + + + Understanding method invocation + + You have a number of choices for method invocation. First, as + used above, dbus_g_proxy_invoke sends a + method call to the remote object, and blocks until reply is + recieved. The outgoing arguments are specified in the varargs + array, terminated with G_TYPE_INVALID. + Next, pointers to return values are specified, followed again + by G_TYPE_INVALID. + + + To invoke a method asynchronously, use + dbus_g_proxy_begin_call. This returns a + DBusGPendingCall object; you may then set a + notification function using + dbus_g_pending_call_set_notify. + + + + Connecting to object signals + + You may connect to signals using + dbus_g_proxy_add_signal and + dbus_g_proxy_connect_signal. At the + moment, dbus_g_proxy_add_signal requires + the D-BUS types of the remote object; this will likely be + changed later. + + + + More examples of method invocation + + Sending an integer and string, receiving an array of bytes + + + GArray *arr; + + error = NULL; + if (!dbus_g_proxy_invoke (proxy, "Foobar", &error, + G_TYPE_INT, 42, G_TYPE_STRING, "hello", + G_TYPE_INVALID, + DBUS_TYPE_G_UCHAR_ARRAY, &arr, G_TYPE_INVALID)) + { + g_printerr ("Failed to complete Foobar: %s\n", + error->message); + g_error_free (error); + exit (1); + } + g_assert (arr != NULL); + printf ("got back %u values", arr->len); + + + + + Sending a GHashTable + + + GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + guint32 ret; + + g_hash_table_insert (hash, "foo", "bar"); + g_hash_table_insert (hash, "baz", "whee"); - - - DBusGProxy represents a remote object. dbus_g_proxy_begin_call() sends - a method call to the remote object, and dbus_g_proxy_end_call() retrieves - any return values or exceptions resulting from the method call. - There are also DBusGProxy functions to connect and disconnect signals, - not shown in the code example. - - - - - - dbus_g_bus_get() assumes that the application will use GMainLoop. The - created connection will be associated with the main loop such that - messages will be sent and received when the main loop runs. However, in - the above code example the main loop never runs; D-BUS will not run the - loop implicitly. Instead, dbus_g_proxy_end_call() will block until the - method call has been sent and the reply received. A more complex GUI - application might run the main loop while waiting for the method call - reply. (DBusGPendingCall is currently missing the "notify me when the - call is complete" functionality found in DBusPendingCall, but it should be - added.) + error = NULL; + if (!dbus_g_proxy_invoke (proxy, "HashSize", &error, + DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID, + G_TYPE_UINT, &ret, G_TYPE_INVALID)) + { + g_printerr ("Failed to complete HashSize: %s\n", + error->message); + g_error_free (error); + exit (1); + } + g_assert (ret == 2); + g_hash_table_destroy (hash); + + + + + Receiving a boolean and a string + + + gboolean boolret; + char *strret; + + error = NULL; + if (!dbus_g_proxy_invoke (proxy, "GetStuff", &error, + G_TYPE_INVALID, + G_TYPE_BOOLEAN, &boolret, + G_TYPE_STRING, &strret, + G_TYPE_INVALID)) + { + g_printerr ("Failed to complete GetStuff: %s\n", + error->message); + g_error_free (error); + exit (1); + } + printf ("%s %s", boolret ? "TRUE" : "FALSE", strret); + g_free (strret); + + + + + Sending two arrays of strings + + + /* NULL terminate */ + char *strs_static[] = {"foo", "bar", "baz", NULL}; + /* Take pointer to array; cannot pass array directly */ + char **strs_static_p = strs_static; + char **strs_dynamic; - + strs_dynamic = g_new (char *, 4); + strs_dynamic[0] = g_strdup ("hello"); + strs_dynamic[1] = g_strdup ("world"); + strs_dynamic[2] = g_strdup ("!"); + /* NULL terminate */ + strs_dynamic[3] = NULL; + + error = NULL; + if (!dbus_g_proxy_invoke (proxy, "TwoStrArrays", &error, + G_TYPE_STRV, strs_static_p, + G_TYPE_STRV, strs_dynamic, + G_TYPE_INVALID, + G_TYPE_INVALID)) + { + g_printerr ("Failed to complete TwoStrArrays: %s\n", + error->message); + g_error_free (error); + exit (1); + } + g_strfreev (strs_dynamic); + + + + + Sending a boolean, receiving an array of strings + + + char **strs; + char **strs_p; + gboolean blah; - - - Future plans (see doc/TODO) are to use G_TYPE_STRING in place of - DBUS_TYPE_STRING and so forth. In fact the above code is slightly - incorrect at the moment, since it uses g_strfreev() to free a string array - that was not allocated with g_malloc(). dbus_free_string_array() should - really be used. However, once the GLib bindings are complete the returned - data from dbus_g_proxy_end_call() will be allocated with g_malloc(). + error = NULL; + blah = TRUE; + if (!dbus_g_proxy_invoke (proxy, "GetStrs", &error, + G_TYPE_BOOLEAN, blah, + G_TYPE_INVALID, + G_TYPE_STRV, &strs, + G_TYPE_INVALID)) + { + g_printerr ("Failed to complete GetStrs: %s\n", + error->message); + g_error_free (error); + exit (1); + } + for (strs_p = strs; *strs_p; strs_p++) + printf ("got string: \"%s\"", *strs_p); + g_strfreev (strs); + + + + + Sending a variant + + + GValue val = {0, }; - + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, "hello world"); + + error = NULL; + if (!dbus_g_proxy_invoke (proxy, "SendVariant", &error, + G_TYPE_VALUE, &val, G_TYPE_INVALID, + G_TYPE_INVALID)) + { + g_printerr ("Failed to complete SendVariant: %s\n", + error->message); + g_error_free (error); + exit (1); + } + g_assert (ret == 2); + g_value_unset (&val); + + + + + Receiving a variant + + + GValue val = {0, }; + error = NULL; + if (!dbus_g_proxy_invoke (proxy, "GetVariant", &error, G_TYPE_INVALID, + G_TYPE_VALUE, &val, G_TYPE_INVALID)) + { + g_printerr ("Failed to complete GetVariant: %s\n", + error->message); + g_error_free (error); + exit (1); + } + if (G_VALUE_TYPE (&val) == G_TYPE_STRING) + printf ("%s\n", g_value_get_string (&val)); + else if (G_VALUE_TYPE (&val) == G_TYPE_INT) + printf ("%d\n", g_value_get_int (&val)); + else + ... + g_value_unset (&val); + + + + GLib API: Implementing Objects - - - The GLib binding is defined in the header file - <dbus/dbus-glib.h>. To implement an object, it's also necessary - to use the dbus-glib-tool command line tool. - + At the moment, to expose a GObject via D-BUS, you must + write XML by hand which describes the methods exported + by the object. In the future, this manual step will + be obviated by the upcoming GLib introspection support. + + Here is a sample XML file which describes an object that exposes + one method, named ManyArgs. + +<?xml version="1.0" encoding="UTF-8" ?> + +<node name="/com/example/MyObject"> + <interface name="com.example.MyObject"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/> + <method name="ManyArgs"> + <!-- This is optional, and in this case is redunundant --> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/> + <arg type="u" name="x" direction="in" /> + <arg type="s" name="str" direction="in" /> + <arg type="d" name="trouble" direction="in" /> + <arg type="d" name="d_ret" direction="out" /> + <arg type="s" name="str_ret" direction="out" /> + </method> + </interface> +</node> + + - The GLib bindings are incomplete. Implementing an object is not yet - possible, see the TODO file and comments in the source code for details - on what work needs doing. + This XML is in the same format as the D-BUS introspection XML + format. Except we must include an "annotation" which give the C + symbols corresponding to the object implementation prefix + (my_object). In addition, if particular + methods symbol names deviate from C convention + (i.e. ManyArgs -> + many_args), you may specify an annotation + giving the C symbol. + + + Once you have written this XML, run dbus-binding-tool --mode=glib-server FILENAME > HEADER_NAME. to + generate a header file. For example: dbus-binding-tool --mode=glib-server my-objet.xml > my-object-glue.h. + + + Next, include the generated header in your program, and invoke + dbus_g_object_class_install_info, passing the + object class and "object info" included in the header. For + example: + + dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &com_foo_my_object_info); + + This should be done exactly once per object class. + + + To actually implement the method, just define a C function named e.g. + my_object_many_args in the same file as the info + header is included. At the moment, it is required that this function + conform to the following rules: + + + + The function must return a value of type gboolean; + TRUE on success, and FALSE + otherwise. + + + + + The first parameter is a pointer to an instance of the object. + + + + + Following the object instance pointer are the method + input values. + + + + + Following the input values are pointers to return values. + + + + + The final parameter must be a GError **. + If the function returns FALSE for an + error, the error parameter must be initalized with + g_set_error. + + + + + + Finally, you can export an object using dbus_g_connection_register_g_object. For example: + + dbus_g_connection_register_g_object (connection, + "/com/foo/MyObject", + obj); + - -- cgit