www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing a delegate to a C function.

reply =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= writes:
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.
Feb 06 2006
parent reply "Charles" <noone nowhere.com> writes:
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.

Feb 09 2006
parent =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= writes:
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.
Feb 10 2006