Thread overview
callback parameter order question
May 11, 2013
gedaiu
May 11, 2013
Andrej Mitrovic
May 11, 2013
gedaiu
May 11, 2013
Andrej Mitrovic
May 11, 2013
gedaiu
May 11, 2013
evilrat
May 11, 2013
gedaiu
May 11, 2013
Ali Çehreli
May 12, 2013
evilrat
May 11, 2013
Andrej Mitrovic
May 11, 2013
Hi,

I try to create a D interface to GNU Libmicrohttpd because i could not find any, and while i was implementing a demo webserver i've noticed that the     MHD_AccessHandlerCallback in D is triggered with the parameters in the reverse order.

This is in c:

struct MHD_Daemon *
MHD_start_daemon (unsigned int flags,
		  uint16_t port,
		  MHD_AcceptPolicyCallback apc, void *apc_cls,
		  MHD_AccessHandlerCallback dh, void *dh_cls,
		  ...);

typedef int
  (*MHD_AccessHandlerCallback) (void *cls,
                                struct MHD_Connection * connection,
                                const char *url,
                                const char *method,
                                const char *version,
                                const char *upload_data,
                                size_t *upload_data_size,
                                void **con_cls);



and to work in D I had to this:

alias int function(void **con_cls,
size_t *upload_data_size,
const char *upload_data,
const char *ver,
const char *method,
const char *url,
MHD_Connection* connection,
void* cls) MHD_AccessHandlerCallback;

extern (C) {
    .....
MHD_Daemon *MHD_start_daemon(uint flags, uint port, MHD_AcceptPolicyCallback apc, void *apc_cls, MHD_AccessHandlerCallback dh, void *dh_cls,...);

....
}
	
Can anyone help me to understand this?

Thanks,
Bogdan
May 11, 2013
On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
> alias int function(void **con_cls,
> size_t *upload_data_size,
> const char *upload_data,
> const char *ver,
> const char *method,
> const char *url,
> MHD_Connection* connection,
> void* cls) MHD_AccessHandlerCallback;

Add extern(C) to the alias:

alias extern(C) int function(void **con_cls, ...) MHD_AccessHandlerCallback;
May 11, 2013
On Saturday, 11 May 2013 at 09:39:42 UTC, Andrej Mitrovic wrote:
> On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
>> alias int function(void **con_cls,
>> size_t *upload_data_size,
>> const char *upload_data,
>> const char *ver,
>> const char *method,
>> const char *url,
>> MHD_Connection* connection,
>> void* cls) MHD_AccessHandlerCallback;
>
> Add extern(C) to the alias:
>
> alias extern(C) int function(void **con_cls, ...) MHD_AccessHandlerCallback;

if i do that, i get this error


src/import/server.d(128): Error: function gnu.microhttpd.MHD_start_daemon (uint flags, uint port, extern (C) int function(void* cls, const(sockaddr*) addr, uint addrlen) apc, void* apc_cls, extern (C) int function(void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** con_cls) dh, void* dh_cls, ...) is not callable using argument types (MHD_FLAG,int,typeof(null),typeof(null),int function(void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** ptr) @system,typeof(null),MHD_OPTION)
src/import/server.d(128): Error: cannot implicitly convert expression (ahc_echo) of type int function(void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** ptr) @system to extern (C) int function(void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** con_cls)
May 11, 2013
On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
> if i do that, i get this error

I don't know what "ahc_echo" is, but I imagine you'll have to make it
an extern(C) function.
May 11, 2013
On Saturday, 11 May 2013 at 10:04:54 UTC, Andrej Mitrovic wrote:
> On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
>> if i do that, i get this error
>
> I don't know what "ahc_echo" is, but I imagine you'll have to make it
> an extern(C) function.

Hi,


i have this code, and i don't think i can add extern(C) there

void start() {

auto ahc_echo = function(void* cls,
	MHD_Connection* connection,
	const char *url,
	const char *method,
	const char *ver,
	const char *upload_data,
	size_t *upload_data_size,
	void **ptr) {
	        ...
};

d = MHD_start_daemon(MHD_FLAG.MHD_USE_THREAD_PER_CONNECTION, 8080, null, null, ahc_echo, null, MHD_OPTION.MHD_OPTION_END);

}


and if i create a function like this:


extern(C) int ahc_echo(void* cls,
	MHD_Connection* connection,
	const char *url,
	const char *method,
	const char *ver,
	const char *upload_data,
	size_t *upload_data_size,
	void **ptr) {
....
};


i get this error:
Error: function cmsutils.CMServer.ahc_echo (void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** ptr) is not callable using argument types ()

Error: expected 8 function arguments, not 0
May 11, 2013
On Saturday, 11 May 2013 at 10:44:01 UTC, gedaiu wrote:
> On Saturday, 11 May 2013 at 10:04:54 UTC, Andrej Mitrovic wrote:
>> On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
>>> if i do that, i get this error
>>
>> I don't know what "ahc_echo" is, but I imagine you'll have to make it
>> an extern(C) function.
>
> Hi,
>
>
> i have this code, and i don't think i can add extern(C) there
>
> void start() {
>
> auto ahc_echo = function(void* cls,
> 	MHD_Connection* connection,
> 	const char *url,
> 	const char *method,
> 	const char *ver,
> 	const char *upload_data,
> 	size_t *upload_data_size,
> 	void **ptr) {
> 	        ...
> };
>
> d = MHD_start_daemon(MHD_FLAG.MHD_USE_THREAD_PER_CONNECTION, 8080, null, null, ahc_echo, null, MHD_OPTION.MHD_OPTION_END);
>
> }
>
>
> and if i create a function like this:
>
>
> extern(C) int ahc_echo(void* cls,
> 	MHD_Connection* connection,
> 	const char *url,
> 	const char *method,
> 	const char *ver,
> 	const char *upload_data,
> 	size_t *upload_data_size,
> 	void **ptr) {
> ....
> };
>
>
> i get this error:
> Error: function cmsutils.CMServer.ahc_echo (void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** ptr) is not callable using argument types ()
>
> Error: expected 8 function arguments, not 0

looks like you are trying to pass func as parameter in this func, but you forgot to take its address

d = MHD_start_daemon(MHD_FLAG.MHD_USE_THREAD_PER_CONNECTION, 8080, null, null, &ahc_echo, // <-- here
null, MHD_OPTION.MHD_OPTION_END);
May 11, 2013
On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
> i have this code, and i don't think i can add extern(C) there

That's a problem with the parser. Instead of auto use the actual function type:

alias extern(C) int function(void **con_cls,
    size_t *upload_data_size,
    const char *upload_data,
    const char *ver,
    const char *method,
    const char *url,
    MHD_Connection* connection,
    void* cls) MHD_AccessHandlerCallback;

...

MHD_AccessHandlerCallback ahc_echo = function(void* cls,
        MHD_Connection* connection,
        const char *url,
        const char *method,
        const char *ver,
        const char *upload_data,
        size_t *upload_data_size,
        void **ptr) {
                ...
};
May 11, 2013
On Saturday, 11 May 2013 at 11:28:10 UTC, evilrat wrote:
> On Saturday, 11 May 2013 at 10:44:01 UTC, gedaiu wrote:
>> On Saturday, 11 May 2013 at 10:04:54 UTC, Andrej Mitrovic wrote:
>>> On 5/11/13, gedaiu <szabobogdan@yahoo.com> wrote:
>>>> if i do that, i get this error
>>>
>>> I don't know what "ahc_echo" is, but I imagine you'll have to make it
>>> an extern(C) function.
>>
>> Hi,
>>
>>
>> i have this code, and i don't think i can add extern(C) there
>>
>> void start() {
>>
>> auto ahc_echo = function(void* cls,
>> 	MHD_Connection* connection,
>> 	const char *url,
>> 	const char *method,
>> 	const char *ver,
>> 	const char *upload_data,
>> 	size_t *upload_data_size,
>> 	void **ptr) {
>> 	        ...
>> };
>>
>> d = MHD_start_daemon(MHD_FLAG.MHD_USE_THREAD_PER_CONNECTION, 8080, null, null, ahc_echo, null, MHD_OPTION.MHD_OPTION_END);
>>
>> }
>>
>>
>> and if i create a function like this:
>>
>>
>> extern(C) int ahc_echo(void* cls,
>> 	MHD_Connection* connection,
>> 	const char *url,
>> 	const char *method,
>> 	const char *ver,
>> 	const char *upload_data,
>> 	size_t *upload_data_size,
>> 	void **ptr) {
>> ....
>> };
>>
>>
>> i get this error:
>> Error: function cmsutils.CMServer.ahc_echo (void* cls, MHD_Connection* connection, const(char*) url, const(char*) method, const(char*) ver, const(char*) upload_data, ulong* upload_data_size, void** ptr) is not callable using argument types ()
>>
>> Error: expected 8 function arguments, not 0
>
> looks like you are trying to pass func as parameter in this func, but you forgot to take its address
>
> d = MHD_start_daemon(MHD_FLAG.MHD_USE_THREAD_PER_CONNECTION, 8080, null, null, &ahc_echo, // <-- here
> null, MHD_OPTION.MHD_OPTION_END);

yeah... what a shameful mistake.. i vave a new tricky question... how i can provide a class method instead a simple function as callback?
May 11, 2013
On 05/11/2013 10:34 AM, gedaiu wrote:

> how i can provide a class method instead a simple function as
> callback?

Can you describe a little bit more? Where will the object that the member function will be called on come from? Do you want to use always the same object that you already have up front, or do you want to create a new object when the member function needs to be called?

In any case, you will have to use a delegate.

Ali

May 12, 2013
On Saturday, 11 May 2013 at 17:34:53 UTC, gedaiu wrote:
>
> yeah... what a shameful mistake.. i vave a new tricky question... how i can provide a class method instead a simple function as callback?

with D code use delegates as Ali commented, it's simple. with C code use static method and pass instance pointer as callback target, something like this

---------------

// C function
alias extern(C) function(void*) callbackfunc;
extern(C) setCallback(callbackfunc cb, void* userptr);


class Handler {
 static extern(C) callback(void* instance) {
  if ( auto self = cast(Handler) instance )
    self.onCallback();
 }

 void onCallback() {
  // ...
  // your code here
  // ...
 }
}


void setCAPI_callback(Handler hnd) {
 setCallback(Handler.callback, hnd); // don't remember if needed to cast hnd to void
}

however this would require C API which has userptr argument in callbacks(hopefully most libs i've seen has this)