digitalmars.D - Passing member function pointer to external C functions.
- Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= (39/39) Jan 28 2005 I'm trying to register member function of one of my class as expat handl...
- Kris (4/43) Jan 28 2005 I think you can do that by making the class members static ...
- Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= (9/10) Jan 29 2005 Well, right but this way I lose information stored in "this" and I don't
- pragma (21/54) Jan 28 2005 I understand what you're trying to do, as I thought the same thing mysel...
- Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= (13/20) Jan 29 2005 This is nice hack, but I was thinking about something more portable, sta...
- pragma (14/25) Jan 29 2005 As long as you use "extern(C)" in all the places illustrated, D will com...
- Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= (11/17) Jan 29 2005 I've found my personal solution. Because every class instance that need ...
- Andrew Fedoniouk (29/29) Jan 29 2005 Hi, Dawid,
- Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= (6/9) Jan 30 2005 Brilinat! I didn't know that user that is working like this. Thank you. ...
- Andrew Fedoniouk (5/8) Jan 30 2005 I didn't get the exact meaning of this phrase. Is it something good (Coś...
- Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= (12/20) Jan 31 2005 Oh, sorry - my English is far from being perfect. I meant: That is right
- h3r3tic (4/9) Jan 31 2005 No teraz to na pewno kolesie zrozumieją, bueheheheh :>
- Russ Lewis (32/71) Jan 29 2005 You need to create an extern(C) wrapper for the class function, and
I'm trying to register member function of one of my class as expat handler. Of course expat functions are taking pointer to a function and are declared in extern(C) scope. I understand that member functions are in fact normal functions invisibly taking "this" argument and so is this possible to do such thing in D? If answer is "yes": how and "WOW I love this language"; if answer is "no": what would be the best workaround. For clarifying this is what I'm trying to do: extern(C){ void XML_SetElementHandler(XML_Parser p, XML_StartElementHandler start, XML_EndElementHandler end); typedef void function(void *userData, XML_Char *name, XML_Char **atts) XML_StartElementHandler; typedef void function(void *userData, XML_Char *name) XML_EndElementHandler; } class Foo{ this(){ _parser = XML_ParserCreate(null); XML_SetElementHandler(_parser, cast(XML_StartElementHandler)&this.startHandle, cast(XML_EndElementHandler)&this.endHandle); } extern(C){ void startHandle(void *userData,XML_Char *name,XML_Char **atts){ printf("started: %sn",name); } void endHandle(void *userData,XML_Char *name){ printf("ended: %sn",name); } } I get: e2ir: cannot cast from void delegate(void*userData,char*name,char**atts) to void(C *)(void*userData,char*name,char**atts) e2ir: cannot cast from void delegate(void*userData,char*name) to void(C * (void*userData,char*name) Regards, -- Dawid Ciężarkiewicz | arael jid: arael fov.pl
Jan 28 2005
I think you can do that by making the class members static ... - Kris In article <cteolm$12va$1 digitaldaemon.com>, Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= says...I'm trying to register member function of one of my class as expat handler. Of course expat functions are taking pointer to a function and are declared in extern(C) scope. I understand that member functions are in fact normal functions invisibly taking "this" argument and so is this possible to do such thing in D? If answer is "yes": how and "WOW I love this language"; if answer is "no": what would be the best workaround. For clarifying this is what I'm trying to do: extern(C){ void XML_SetElementHandler(XML_Parser p, XML_StartElementHandler start, XML_EndElementHandler end); typedef void function(void *userData, XML_Char *name, XML_Char **atts) XML_StartElementHandler; typedef void function(void *userData, XML_Char *name) XML_EndElementHandler; } class Foo{ this(){ _parser = XML_ParserCreate(null); XML_SetElementHandler(_parser, cast(XML_StartElementHandler)&this.startHandle, cast(XML_EndElementHandler)&this.endHandle); } extern(C){ void startHandle(void *userData,XML_Char *name,XML_Char **atts){ printf("started: %sn",name); } void endHandle(void *userData,XML_Char *name){ printf("ended: %sn",name); } } I get: e2ir: cannot cast from void delegate(void*userData,char*name,char**atts) to void(C *)(void*userData,char*name,char**atts) e2ir: cannot cast from void delegate(void*userData,char*name) to void(C * (void*userData,char*name) Regards, -- Dawid Ciężarkiewicz | arael jid: arael fov.pl
Jan 28 2005
Kris wrote:I think you can do that by making the class members static ...Well, right but this way I lose information stored in "this" and I don't know on which object I work. I was trying to write multithreaded server application that communicates with xml. Each connection has to be separately parsed. I need tons of parser - each knowing almost nothing about other. -- Dawid Ciężarkiewicz | arael jid: arael fov.pl
Jan 29 2005
These are the culprit lines from your post:cast(XML_StartElementHandler)&this.startHandle, cast(XML_EndElementHandler)&this.endHandle);I understand what you're trying to do, as I thought the same thing myself: since D passes 'this' as the first argument to a method, why not pass along my class's methods to Expat since they happen to match the same spec. This would work amazingly well in C++ but D doesn't like it (obviously). There's a lot more going on in those lines than meets the eye: 1) D converts "&this.startHandle" into a *delegate*, which contains a reference to 'this' as well as the address of "startHandle". 2) D does not provide a means for casting a delegate into a function, so the cast to XML_StartElementHandler fails miserably. A more complete explaination of the underpinnings of delegates is here: http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Function Now what you're asking for is a hack to crack the function pointer out of a delegate. I don't advocate this in the slightest, since it's probing around a grey area that may or may not be changed in the D ABI.import std.stdio; struct DelegateStruct { void *ptr; void *func; }; class Test{ extern(C) int myMethod(int a){ writefln("A is %d",a); return a+1; } } extern(C) typedef int delegate(int) TestDelegate; extern(C) typedef int function(void*,int) TestFunctionHandle; int testFunction(void* thisPtr,TestFunctionHandle handle,int a){ return handle(thisPtr,a); } void main(){ Test t = new Test(); writefln("calling directly"); writefln("result is: %d",t.myMethod(42)); TestDelegate del = &t.myMethod; DelegateStruct ds = *cast(DelegateStruct*)cast(void**)&del; TestFunctionHandle handle = cast(TestFunctionHandle)ds.func; writefln("calling indirectly"); writefln("result is: %d",testFunction(cast(void*)t,handle,42)); }I'm sure there's probably a way to use a template and/or mixin to make this much more clean. The secret here is the liberal use of "extern(C)". The default D linkage likes to throw the last argument around as EAX, which happens to be "this" for object.method calls (at least for DMD, I don't know what GDC is up to). - EricAnderton at yahoo
Jan 28 2005
pragma wrote:I'm sure there's probably a way to use a template and/or mixin to make this much more clean. The secret here is the liberal use of "extern(C)". The default D linkage likes to throw the last argument around as EAX, which happens to be "this" for object.method calls (at least for DMD, I don't know what GDC is up to).This is nice hack, but I was thinking about something more portable, stable etc. As I understand whole hack is set on fact that EAX isn't changed and stores "this" pointer, right? Can I really depend on this in multithreaded environment using external C callback? I mean - I will register such function as handler, then many things will happen (EAX will definitely change) and then expat will call my handler and I don't think it will set EAX to something usable. If I understand this will end with random "this" and segfault. I'm not sure if I understood you so sorry if I'm jabbering. -- Dawid Ciężarkiewicz | arael jid: arael fov.pl
Jan 29 2005
In article <ctfqta$287m$1 digitaldaemon.com>, Dawid =?ISO-8859-2?Q?Ci=EA=BFarkiewicz?= says...pragma wrote:As long as you use "extern(C)" in all the places illustrated, D will compile those methods/functions as 'stdcall' which is the C standard (no EAX mojo). If you try removing "extern(C)", so the compiler uses the D linkage instead, it segfaults all over the place. A hack is a hack. I don't advocate using it unless it gives you a sound advantage that can't be met otherwise. If it passes muster with testing on all your target platforms, then techically its sound code. I for one never code with a hack unless it achives a requirement, like better performance or a reduced memory footprint; and even then its a last resort. Plus I document the heck out of it (flagging it with "//HACK:") to warn other developers of what, why and how. - EricAnderton at yahooI'm sure there's probably a way to use a template and/or mixin to make this much more clean. The secret here is the liberal use of "extern(C)". The default D linkage likes to throw the last argument around as EAX, which happens to be "this" for object.method calls (at least for DMD, I don't know what GDC is up to).This is nice hack, but I was thinking about something more portable, stable etc. As I understand whole hack is set on fact that EAX isn't changed and stores "this" pointer, right?
Jan 29 2005
Dawid Ciężarkiewicz wrote:I'm trying to register member function of one of my class as expat handler. Of course expat functions are taking pointer to a function and are declared in extern(C) scope. I understand that member functions are in fact normal functions invisibly taking "this" argument and so is this possible to do such thing in D? If answer is "yes": how and "WOW I love this language"; if answer is "no": what would be the best workaround.I've found my personal solution. Because every class instance that need his own parser is new thread I register static member function as handler that use "getThis()" to run good instance of member function. Like this: static void StartHandler(void *userData,XML_Char *name,XML_Char **atts){ (cast(ConnectionHandler)getThis()).startHandle(userData,name,atts); } -- Dawid Ciężarkiewicz | arael jid: arael fov.pl
Jan 29 2005
Hi, Dawid, Why not to use something simple as below? (It's just a scetch, never compiled it) class MyHandler { void startHandler(XML_Char *name,XML_Char **atts) { printf("started: %sn",name); } void endHandler(XML_Char *name) { printf("ended: %sn",name); } extern(C) static void _startHandler(void *userData,XML_Char *name,XML_Char **atts) { (cast(MyHandler)(userData)).startHandler(name,atts); } extern(C) static void _endHandler(void *userData,XML_Char *name) { (cast(MyHandler)(userData)).endHandler(name); } void setup(XML_Parser p) { XML_SetUserData(p, cast(void*) this); XML_SetElementHandler(p,_startHandle,_endHandle); } } You can wrap it into template if you want to use it in multiple places.
Jan 29 2005
Andrew Fedoniouk wrote:Hi, Dawid, Why not to use something simple as below?Brilinat! I didn't know that user that is working like this. Thank you. This is very good answer to my problem. -- Dawid Ciężarkiewicz | arael jid: arael fov.pl
Jan 30 2005
Brilinat! I didn't know that user that is working like this. Thank you. This is very good answer to my problem.I didn't get the exact meaning of this phrase. Is it something good (Coś dobry) ? :) (just curious) Andrew Fedoniouk. http://terrainformatica.com
Jan 30 2005
Andrew Fedoniouk wrote:Oh, sorry - my English is far from being perfect. I meant: That is right solution that satisfies me. And from where did you get "coś dobry". It sounds funny - should be "coś dobrego". I niebardzo to było dobre, bo się pomyliłem. Za to Twoje rozwiązanie było poprawne. Szkoda tylko, że nawet pochwalić Cię nie potrafiłem. ;) Well, my language is beautiful. :) Regards, -- Dawid Ciężarkiewicz | arael jid: arael fov.plBrilinat! I didn't know that user that is working like this. Thank you. This is very good answer to my problem.I didn't get the exact meaning of this phrase. Is it something good (Coś dobry) ? :) (just curious)
Jan 31 2005
Dawid Ciężarkiewicz wrote:And from where did you get "coś dobry". It sounds funny - should be "coś dobrego"./me agrees it's funnyI niebardzo to było dobre, bo się pomyliłem. Za to Twoje rozwiązanie było poprawne. Szkoda tylko, że nawet pochwalić Cię nie potrafiłem. ;)No teraz to na pewno kolesie zrozumieją, bueheheheh :>Well, my language is beautiful. :)I wouldn't quite agree :> I've been forced to speak it, sb help me
Jan 31 2005
Dawid Ciężarkiewicz wrote:I'm trying to register member function of one of my class as expat handler. Of course expat functions are taking pointer to a function and are declared in extern(C) scope. I understand that member functions are in fact normal functions invisibly taking "this" argument and so is this possible to do such thing in D? If answer is "yes": how and "WOW I love this language"; if answer is "no": what would be the best workaround. For clarifying this is what I'm trying to do: extern(C){ void XML_SetElementHandler(XML_Parser p, XML_StartElementHandler start, XML_EndElementHandler end); typedef void function(void *userData, XML_Char *name, XML_Char **atts) XML_StartElementHandler; typedef void function(void *userData, XML_Char *name) XML_EndElementHandler; } class Foo{ this(){ _parser = XML_ParserCreate(null); XML_SetElementHandler(_parser, cast(XML_StartElementHandler)&this.startHandle, cast(XML_EndElementHandler)&this.endHandle); } extern(C){ void startHandle(void *userData,XML_Char *name,XML_Char **atts){ printf("started: %sn",name); } void endHandle(void *userData,XML_Char *name){ printf("ended: %sn",name); } }You need to create an extern(C) wrapper for the class function, and store the 'this' pointer in a struct, which you use as the userdata. Here's the bare bones of an example, with some nice translation of C strings to D strings thrown in, to boot: // override this class for your own uses... class ExpatParser { void startHandler(XML_char[] name,XML_Char[][] attrs) { return; } void endHandler (XML_char[] name) { return; } this() { _parser = XML_ParserCreate(null); ExpatParserUserData *ptr = new ExpatParserUserData[1]; ptr.ref = this; XML_SetUserData(_parser, cast(void*)ptr); XML_SetElementHandler(_parser, &startHandler_c, &endHandler_c); }; }; struct ExpatParserUserData { ExpatParser ref; }; extern(C) void startHandler_c(void *userdata_void, XML_Char *name_c, XML_Char **attrs_c) { ExpatParserUserData *userdata = cast(ExpatParserUserData*)userdata_void; XML_Char[] name = name_c[0..strlen(name_c)]; XML_Char[][] attrs; for( ; *attrs_c != null; attrs_c++) attrs ~= (*attrs_c)[0..strlen(*attrs_c)]; userdata.ref.startHandler(name,attrs); } you can write your own endHandler_c() the same way...
Jan 29 2005