Search code examples
dffi

Calling extern C function called with void*


I have a C library which takes opaque pointers in the header.

Here's my C header

typedef void* dbaxRange_p;
typedef void* dbaxFunction_p;

extern "C" {
    // ... lots of other methods...
    EXPORT dbaxRange_p range_d(const double value);
    EXPORT void add_param(dbaxFunction_p func, dbaxRange_p arg);
    EXPORT dbaxFunction_p dbax_function(const char* name, const int num_params);
    // Call method taking void*
    EXPORT dbaxRange_p call(dbaxFunction_p func);
}

Here's my D interface CDbax.d:

extern (C):
alias void *dbaxFunction_p;
alias void *dbaxRange_p;

extern (C) {
dbaxRange_p  range_d(double value);
void  add_param(dbaxFunction_p func, dbaxRange_p arg);
dbaxFunction_p  dbax_function(const char *name, int num_params);
dbaxRange_p  call(dbaxFunction_p func);
}

And here's my call to the function

class Dbax {
     // ...
    dbaxFunction_p func_;
    this(string name) {
       func_ = dbax_function(std.string.toStringz(name),0);
    }
    Dbax add(double val) {
        auto rng = range_d(val);
        add_param(func_,rng);
        return this;
    }
    dbaxRange_p call() {
        return call(cast(dbaxFunction_p) this.func_);
    }
}

main.d

import CDbax;
void test()
{
    auto res = new CDbax.Dbax("GetVersionNumber").add(0.24).call();
}

But I get this error:-

CDbax.d(113): Error: function CDbax.Dbax.call () is not callable using argument types (void*)

Update Answer is that there's a namespace clash. It picked up my C FFI call rather than the Dbax class call() function. I'll ask a follow up SO question as to why


Solution

  • This is simply a case of it trying to call the method call instead of the global function. (BTW are you sure the C function is called call and that isn't a macro? It is kinda rare for a C function to have such a naked name.)

    Anyway, when you're inside a class, it always looks to the class first for members and D does not overload across units unless you specifically ask it to by alias innerName = full.outer.name; The explanation for why is here: http://dlang.org/hijack.html basically it is so adding a global function later doesn't break the class by introducing a new, confusing overload. The class' author should be able to focus on just the class' source without worrying about a new global written by another programmer in a module far, far away making her code more confusing.

    The easiest way to solve this in your case is to use a full name, or at least the global scope operator in your call:

        return call(cast(dbaxFunction_p) this.func_); // before
    
        return .call(cast(dbaxFunction_p) this.func_); // after
    

    The leading dot means "look it up in the top-level namespace". (BTW, similarly, you can explicitly use this.call when you want it to look only at this.)

    When these things come up, you can also prepend the module name to disambiguate if you prefer to be even more explicit:

      foo.bar.call(); // looks in foo.bar