www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unable to pass a D function member to a C callback

reply Luh <null null.null> writes:
Hello,

When trying to pass a D function to the C callback, the compiler 
says:

'Error: cannot implicitly convert expression &this.onProcessCb of 
type extern (C) bool delegate(const(short*) a, ulong b, void* c) 
to extern (C) bool function(const(short*), ulong, void*'

because my function is member of a class (compiles when the 
function is out of the class).

Is there any way to say to solve this ?
The wiki isn't very clear about the C callbacks:
https://dlang.org/spec/interfaceToC.html#callbacks

C code:
----
typedef bool (*onProcessCallback)(const short*, size_t, void*);
----


D Code:
-----
class Game
{
	onProcessCallback m_onProcessCb;
	
	this()
	{
		m_onProcessCb = &onProcessCb; // Error here
	}
	
	void onProcess()
	{
		// ...
	}

	extern(C) bool onProcessCb(const short* a, size_t b, void* c)
	{
		onProcess();
		return true;
	}
}

private extern(C)
{
	// Should call onProcess() when executed by the C lib
	alias onProcessCallback = bool function(const short*, size_t, 
void*);
}
-----
Nov 02 2019
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 2 November 2019 at 17:49:09 UTC, Luh wrote:
 Hello,

 When trying to pass a D function to the C callback, the 
 compiler says:

 'Error: cannot implicitly convert expression &this.onProcessCb 
 of type extern (C) bool delegate(const(short*) a, ulong b, 
 void* c) to extern (C) bool function(const(short*), ulong, 
 void*'

 because my function is member of a class (compiles when the 
 function is out of the class).

 Is there any way to say to solve this ?
 The wiki isn't very clear about the C callbacks:
 https://dlang.org/spec/interfaceToC.html#callbacks

 C code:
 ----
 typedef bool (*onProcessCallback)(const short*, size_t, void*);
 ----


 D Code:
 -----
 class Game
 {
 	onProcessCallback m_onProcessCb;
 	
 	this()
 	{
 		m_onProcessCb = &onProcessCb; // Error here
 	}
 	
 	void onProcess()
 	{
 		// ...
 	}

 	extern(C) bool onProcessCb(const short* a, size_t b, void* c)
 	{
 		onProcess();
 		return true;
 	}
 }

 private extern(C)
 {
 	// Should call onProcess() when executed by the C lib
 	alias onProcessCallback = bool function(const short*, size_t, 
 void*);
 }
 -----
you are missing a static in your member function's signature. The callback is not providing a this pointer.
Nov 02 2019
parent reply Luh <null null.null> writes:
On Saturday, 2 November 2019 at 18:31:28 UTC, Stefan Koch wrote:
 On Saturday, 2 November 2019 at 17:49:09 UTC, Luh wrote:
 Hello,

 When trying to pass a D function to the C callback, the 
 compiler says:

 'Error: cannot implicitly convert expression &this.onProcessCb 
 of type extern (C) bool delegate(const(short*) a, ulong b, 
 void* c) to extern (C) bool function(const(short*), ulong, 
 void*'

 because my function is member of a class (compiles when the 
 function is out of the class).

 Is there any way to say to solve this ?
 The wiki isn't very clear about the C callbacks:
 https://dlang.org/spec/interfaceToC.html#callbacks

 C code:
 ----
 typedef bool (*onProcessCallback)(const short*, size_t, void*);
 ----


 D Code:
 -----
 class Game
 {
 	onProcessCallback m_onProcessCb;
 	
 	this()
 	{
 		m_onProcessCb = &onProcessCb; // Error here
 	}
 	
 	void onProcess()
 	{
 		// ...
 	}

 	extern(C) bool onProcessCb(const short* a, size_t b, void* c)
 	{
 		onProcess();
 		return true;
 	}
 }

 private extern(C)
 {
 	// Should call onProcess() when executed by the C lib
 	alias onProcessCallback = bool function(const short*, size_t, 
 void*);
 }
 -----
you are missing a static in your member function's signature. The callback is not providing a this pointer.
My problem is, that the onProcess function should not be static because it uses a variable inside the class. like: ----- class Game { private short[] m_a; void onProcess(short[] a) { m_a ~= a; // ... } extern(C) bool onProcessCb(const short* a, size_t b, void* c) { onProcess(); return true; } } ----- So I think I just can't. :(
Nov 02 2019
parent reply Dennis <dkorpel gmail.com> writes:
On Saturday, 2 November 2019 at 19:42:54 UTC, Luh wrote:
 So I think I just can't. :(
Is that `void* c` in the callback a context pointer by any chance? That's a common thing in C callbacks precisely for purposes like this. You can cast your class to a void* when you register the callback and in the callback function cast it back to a class and call process on that. I don't know what C library you're working with so can't give you specifics.
Nov 02 2019
parent reply Luh <null null.null> writes:
On Saturday, 2 November 2019 at 19:55:58 UTC, Dennis wrote:
 On Saturday, 2 November 2019 at 19:42:54 UTC, Luh wrote:
 So I think I just can't. :(
Is that `void* c` in the callback a context pointer by any chance? That's a common thing in C callbacks precisely for purposes like this. You can cast your class to a void* when you register the callback and in the callback function cast it back to a class and call process on that. I don't know what C library you're working with so can't give you specifics.
Yup that's it ! Many thanks !
Nov 02 2019
parent Dennis <dkorpel gmail.com> writes:
On Saturday, 2 November 2019 at 20:42:29 UTC, Luh wrote:
 Yup that's it !
 Many thanks !
One word of warning: ensure the C library does not have the only reference to your Game class instance, or the garbage collector might deallocate it since it does not scan threads created by C libraries. See: https://dlang.org/spec/garbage.html#gc_foreign_obj
Nov 02 2019
prev sibling parent Alex <sascha.orlov gmail.com> writes:
On Saturday, 2 November 2019 at 17:49:09 UTC, Luh wrote:
 Hello,

 When trying to pass a D function to the C callback, the 
 compiler says:

 'Error: cannot implicitly convert expression &this.onProcessCb 
 of type extern (C) bool delegate(const(short*) a, ulong b, 
 void* c) to extern (C) bool function(const(short*), ulong, 
 void*'

 because my function is member of a class (compiles when the 
 function is out of the class).

 Is there any way to say to solve this ?
 The wiki isn't very clear about the C callbacks:
 https://dlang.org/spec/interfaceToC.html#callbacks

 C code:
 ----
 typedef bool (*onProcessCallback)(const short*, size_t, void*);
 ----


 D Code:
 -----
 class Game
 {
 	onProcessCallback m_onProcessCb;
 	
 	this()
 	{
 		m_onProcessCb = &onProcessCb; // Error here
 	}
 	
 	void onProcess()
 	{
 		// ...
 	}

 	extern(C) bool onProcessCb(const short* a, size_t b, void* c)
 	{
 		onProcess();
 		return true;
 	}
 }

 private extern(C)
 {
 	// Should call onProcess() when executed by the C lib
 	alias onProcessCallback = bool function(const short*, size_t, 
 void*);
 }
 -----
This is because onProcessCb is a member of an object. Therefore, it carries also the information about the context, which includes e.g. all members of the class. Due to this onProcessCb is a delegate, which is something different from a function, cf. https://dlang.org/spec/function.html#closures So, there is a type mismatch.
Nov 02 2019