Thread overview
Passing a delegate to a C function.
Feb 09, 2006
Charles
February 07, 2006
Hi.

I'm writing a binding to a C library. One of its functions has the following signature:

write_to_stream(surface_t* surface,
                write_func_t write_func,
                void* closure);

... and write_func is:

alias status_t function(void* closure,
                        ubyte* data,
                        uint length) write_func_t;

This seemed to map perfectly to a D delegate. So I started looking in the reference for a way to obtain the stack frame and the function pointer of a non-static delegate but couldn't find it.

Then attempted to implement the trick, that was posted in the digitalmars.D newsgroup long time ago, of creating a union with the delegate and member functions for the stack and function pointer:

union WriteClosure
{
	/*extern(C)*/ status_t delegate (ubyte* data, uint length) dg;
	struct
	{
		// It's this the correct order?
		void* closure;
		write_func_t write_func;
	}
}

void writeToPng(OutputStream ostream)
{
	WriteClosure wc;
	wc.dg = /*extern(C)*/ delegate status_t (ubyte* data,
		uint length)
	{
		try
		{
			ostream.writeExact(data, length);
			return status_t.STATUS_SUCCESS;
		}
		catch (WriteException e)
		{
			ex = e;
			return status_t.STATUS_WRITE_ERROR;
		}
	};
	write_to_stream(m_surface_t, wc.write_func, wc.closure);
}

but it throws an AccessViolation when I call the "write_to_stream" function. I think it's probably missing the extern(C) but it doesn't compile with it. This is the code that calls the function.

Any pointers on how to implement this?

Thanks.
February 09, 2006
It seems like a lot of hacking just to be able to use delegate's  with C , does wrapping the callback not work for you , ala:

// call write to stream with a C callback that just calls our delegate


// our d delegate
 alias int function (void *closure,
        ubyte* data,
        uint length) writeFuncDelegate;

writeFuncDelegate writeCallback; // = whatever

//our c callback
extern ( C ) write_func_callback ( void* closure, ubyte* d, uint length )
{

        writeCallback(closure,d,length);

}

// then call write to stream with your C callback, write_func_callback

write_to_stream( mySurface, &write_func_callback, myClosure );

?



"Julio César Carrascal Urquijo" <jcesar@phreaker.net> wrote in message news:ds93t9$16b4$1@digitaldaemon.com...
> Hi.
>
> I'm writing a binding to a C library. One of its functions has the following signature:
>
> write_to_stream(surface_t* surface,
>                  write_func_t write_func,
>                  void* closure);
>
> ... and write_func is:
>
> alias status_t function(void* closure,
>                          ubyte* data,
>                          uint length) write_func_t;
>
> This seemed to map perfectly to a D delegate. So I started looking in the reference for a way to obtain the stack frame and the function pointer of a non-static delegate but couldn't find it.
>
> Then attempted to implement the trick, that was posted in the digitalmars.D newsgroup long time ago, of creating a union with the delegate and member functions for the stack and function pointer:
>
> union WriteClosure
> {
> /*extern(C)*/ status_t delegate (ubyte* data, uint length) dg;
> struct
> {
> // It's this the correct order?
> void* closure;
> write_func_t write_func;
> }
> }
>
> void writeToPng(OutputStream ostream)
> {
> WriteClosure wc;
> wc.dg = /*extern(C)*/ delegate status_t (ubyte* data,
> uint length)
> {
> try
> {
> ostream.writeExact(data, length);
> return status_t.STATUS_SUCCESS;
> }
> catch (WriteException e)
> {
> ex = e;
> return status_t.STATUS_WRITE_ERROR;
> }
> };
> write_to_stream(m_surface_t, wc.write_func, wc.closure);
> }
>
> but it throws an AccessViolation when I call the "write_to_stream" function. I think it's probably missing the extern(C) but it doesn't compile with it. This is the code that calls the function.
>
> Any pointers on how to implement this?
>
> Thanks.


February 11, 2006
Charles wrote:
> It seems like a lot of hacking just to be able to use delegate's  with C ,
> does wrapping the callback not work for you , ala:
> 
> // call write to stream with a C callback that just calls our delegate
> 
> 
> // our d delegate
>  alias int function (void *closure,
>         ubyte* data,
>         uint length) writeFuncDelegate;
> 
> writeFuncDelegate writeCallback; // = whatever
> 
> //our c callback
> extern ( C ) write_func_callback ( void* closure, ubyte* d, uint length )
> {
> 
>         writeCallback(closure,d,length);
> 
> }
> 
> // then call write to stream with your C callback, write_func_callback
> 
> write_to_stream( mySurface, &write_func_callback, myClosure );
> 
> ?
> 

Don't worry, got it working after talking with Walter in d.D.

I don't think this would compile, though:

>         writeCallback(closure,d,length);

The closure is be passed implicitly by the compiler in D code, but of course I needed the C code to pass it as the first parameter so I could modify some variables from the calling function.

The problem was that D doesn't allow extern declarations for anonymous delegates but once I tried a named delegate everything worked out.

Thanks.