Posted by: Airtower | 2010-06-25

Returning a string array from a D-Bus method call

I am writing a D-Bus service using dbus-glib, and I want one of my methods to return a variable number of strings. Sounds easy enough, right? Arrays of strings are listed in the D-Bus tutorial with the type signatureas“. I was still unsure of the right C data type for the method signature, and surprisingly I could not find a single example where this was actually used as a return value. The only hint I had was the following information from the tutorial:

  • Type signature: as
  • GType: G_TYPE_STRV
  • C typedef: char **
  • Free function: g_strfreev

What is a G_TYPE_STRV? The documentation describes it as a “NULL-terminated array of strings.” This means that it is an array of gchar *, and the last pointer in the array has to be NULL, so that you can easily recognize the end of the array. Such an array is technically a gchar **, which matches the type definition cited above. Therefore, my handler function will take a gchar **return_string_array as a parameter and set that pointer to point at the returned array.

The difficulties started when I tried to actually fill the array. An empty array

*return_string_array = NULL;

worked, but I suffered a lot of segfaults trying to put useful data into it. This is the solution I found (GStrv is just a typedef for the kind of string array described above):

/* Inside the message handler function that gets
 * "gchar **return_string_array" as a parameter */
GStrv s = g_new(char *, 3);
s[0] = g_strdup("Hi!");
s[1] = g_strdup("This is a test.");
s[2] = NULL;
*return_string_array = (gchar *) s;

Step-by-step description

  1. Allocate memory for the required number of pointers (number of strings plus one for the NULL pointer).
  2. Fill the strings (g_strdup is a nice little function to put strings on the heap), don’t forget the NULL at the end.
  3. Have the return pointer point at the data you placed on the heap.

The last line of code is not very intuitive (at least for me), but it makes sense: For each outgoing argument the function gets a pointer to a memory area it is supposed to fill with the returned data. The reason for this is that D-Bus method calls can return multiple values, while C functions can not. So the C function returns a gboolean which is TRUE in case of success and FALSE in case of error. The return data is passed by writing to memory provided by the caller. In this case, the returned data is an array of pointers to strings, so the provided memory is a pointer which must point at the first element of the array (which is another pointer). Quite a bit of pointer confusion, but it works. 🙂

Advertisements

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: