| 
 
 NAME
 SYNOPSIS
 typedef DCsigchar
   DCCallback *
   DCCallback *
   void
   void
   void
   void
   DCbool
   DCchar
   DCshort
   DCint
   DClong
   DClonglong
   DCuchar
   DCushort
   DCuint
   DCulong
   DCulonglong
   DCfloat
   DCdouble
   DCpointer
   DCpointer
   void
   DESCRIPTIONThe  
 
 NOTE: C++ non-trivial aggregates (check with the std::is_trivial type trait) do not use aggregate descriptions, so the respective pointers in the provided array must be NULL. See dyncall(3) for more information on C++ non-trivial aggregates. Use the pointer returned by
     
 
 
 Declaration of a dyncallback handler (following function pointer declaration in dyncall_callback.h): DCsigchar cbHandler(DCCallback* cb,
                    DCArgs*     args,
                    DCValue*    result,
                    void*       userdata);
cb is a pointer to the
    DCCallback object in use, args is to be used with the
     Retrieving aggregates by value from the generic
    handler's args argument can be done via
     To return a trivial aggregate by value, a
    helper function
     Retrieving or returning C++ non-trivial aggregates (check with the std::is_trivial type trait) is done differently, as dyncall cannot know how to do this copy and the C++ ABI handles those differently: When retrieving a C++ non-trivial aggregate via
     EXAMPLESNote: for simplicity, none of the examples below do any error checking. Also, none of them pass the callback object pointer as an argument to a function doing the respective callback (e.g. compar in qsort(3), etc.), but demonstrate calling it, directly, for clarity. Let's say, we want to create a callback object and call it. First, we need to define our callback handler - the following handler illustrates how to access the passed-in arguments, optional userdata, and how to return values: DCsigchar cbHandler(DCCallback* cb,
                    DCArgs*     args,
                    DCValue*    result,
                    void*       userdata)
{
  int* ud = (int*)userdata;
  int       arg1 = dcbArgInt     (args);
  float     arg2 = dcbArgFloat   (args);
  short     arg3 = dcbArgShort   (args);
  double    arg4 = dcbArgDouble  (args);
  long long arg5 = dcbArgLongLong(args);
  /* .. do something .. */
  result->s = 1244;
  return 's';
}
Note that the return value of the handler is a signature character, and not the actual return value, itself. Now, let's call it through a DCCallback object: DCCallback* cb;
short result = 0;
int userdata = 1337;
cb = dcbNewCallback("ifsdl)s", &cbHandler, &userdata);
/* call the callback object */
result = ((short(*)(int, float, short, double, long long))cb)
  (123, 23.f, 3, 1.82, 9909ll);
dcbFreeCallback(cb);
C/trivial aggregates by-valueOnto an example calling back a function which takes an aggregate
    by value (note that this is only available on platforms
    where macro  struct S { char x[3]; double y; };
int f(struct S, float);
the callback handler would look like: DCsigchar cbHandler(DCCallback* cb,
                    DCArgs*     args,
                    DCValue*    result,
                    void*       userdata)
{
  struct S arg1;
  float arg2;
  dcbArgAggr(args, (DCpointer)&arg1);
  arg2 = dcbArgFloat(args);
  /* ... */
  result->i = 1;
  return 'i';
}
and the callback object as well as the aggregate field/layout description are set up (and the former called back) as follows: struct S s = { { 56, -23, 0 }, -6.28 };
int result;
DCCallback* cb;
DCaggr *a = dcNewAggr(2, sizeof(struct S));
dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
dcCloseAggr(a);
/* an array of DCaggr* must be passed as last arg, with one
 * entry per 'A' signature character; we got only one, here
 */
cb = dcbNewCallback2("Af)v", &cbHandler, NULL, &a);
/* call the callback object */
result = ((int(*)(struct S, float))cb)(s, 42.f);
dcbFreeCallback(cb);
dcFreeAggr(a);
Let's extend the last example, so that the callback function also returns struct S by value. The struct definition, function declaration and handler definition would be: /* callback function decl */
struct S f(struct S, float);
struct S { char x[3]; double y; };
DCsigchar cbHandler(DCCallback* cb,
                    DCArgs*     args,
                    DCValue*    result,
                    void*       userdata)
{
  struct S arg1, r;
  float arg2;
  dcbArgAggr(args, (DCpointer)&arg1);
  arg2 = dcbArgFloat(args);
  /* ... */
  /* use helper to write aggregate return value to result */
  dcbReturnAggr(args, result, (DCpointer)&r);
  return 'A';
}
and the callback object as well as the aggregate field/layout descriptions are set up (and the former called back) as follows: struct S s = { { 33, 29, -1 }, 6.8 };
struct S result;
DCCallback* cb;
DCaggr *a = { dcNewAggr(2, sizeof(struct S)) };
dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
dcCloseAggr(a);
/* an array of DCaggr* must be passed as last arg, with one
 * entry per 'A' signature character
 */
cb = dcbNewCallback2("Af)A", &cbHandler, NULL, (DCaggr*[2]){a,a});
/* call the callback object */
result = ((struct S(*)(struct S, float))cb)(s, 42.f);
dcbFreeCallback(cb);
dcFreeAggr(a);
C++In our next example, let's look at setting up a DCCallback object to call back a simple C++ method (illustrating the need to specify the thiscall calling convention). If the class and method is declared as: class Klass {
public:
	virtual void Method(float, int);
};
the respective callback handler would be something along the lines of: DCsigchar cbHandler(DCCallback* cb,
                    DCArgs*     args,
                    DCValue*    result,
                    void*       userdata)
{
  Klass*    thisptr = (Klass*)dcbArgPointer(args);
  float     arg1 = dcbArgFloat(args);
  int       arg2 = dcbArgInt(args);
  /* ... */
  return 'v';
}
and the callback object would be used as follows: DCCallback* cb;
cb = dcbNewCallback("_*pfi)v", &cbHandler, NULL);
/* HACK: this is a hack just for this example to force the compiler
 * generating a thiscall, below (creates a fake vtable mimicking
 * Klass, setting all of its possible entries to our callback handler;
 */
DCpointer fakeClass[sizeof(Klass)/sizeof(DCpointer)];
for(int j=0; j<sizeof(Klass)/sizeof(DCpointer); ++j)
	fakeClass[j] = &cb;
/* (this)call the callback object */
((Klass*)&fakeClass)->Method(8, 23.f);
dcbFreeCallback(cb);
NOTE: In a real world scenario one would figure
    out the precise location of the vtable entry of
     CONFORMING TOThe dyncallback library needs at least a c99 compiler with additional support for anonymous structs/unions (which were introduced officially in c11). Given that those are generally supported by pretty much all major c99 conforming compilers (as default extension), it should build fine with a c99 toolchain. Strictly speaking, dyncall conforms to c11, though. SEE ALSOdyncall(3), dynload(3) and the dyncall manual (available in HTML and PDF format) for more information. AUTHORSDaniel Adler
    ⟨dadler@uni-goettingen.de⟩
   
 
  |