Subj : Re: Callbacks in C++ or any other way To : borland.public.cpp.borlandcpp From : MichaelK Date : Wed Jun 09 2004 06:35 am Interesting... But what in the case where the WIN 32 version of the Callback proc does not have that extra field for Application Data. Which is my case. How would the code below be modified to handle those types of callback functions. maeder@glue.ch (Thomas Maeder [TeamB]) wrote: >"MichaelK" writes: > >> Does anyone know how to do win32 callbacks in c++ >> >> The problem is it wont work with having a member function as a callback >> function (the calling convention seems to be messed up) > >I assume that you are writing about a *non-static* member function here. > >Yes, you are right, you can't register a non-static member function as a >callback with APIs that require a non-member function; typically, these are >C APIs that allow/require registering a callback. Converting the address of >the member function to the type of function pointer required by the >registration function will not work unless you apply brute force, and this is >for a reason. There is no way the non-static member function could be called >back anyway. > >You may get away with registering a *static* member function with some of >these APIs. However, it isn't the right thing to do, either, because the >C++ language has a different feature that was designed for exactly C and C++ >interoperability; extern "C". If you want to register a callback with a >Windows API, you must not declare it extern "C", though, but use the >CALLBACK macro in its declaration (cf. below). > > >The reason that non-static member functions won't work is that when they >are called, the object which they are applied on is passed as a hidden >additional argument (the this pointer). No C code will know anything about >C++ classes and member functions, let alone how to pass the this pointer. > > >This doesn't mean that you can't use these C APIs from C++ classes, though. > > >Take for example the Windows API function EnumFonts() >(http://msdn.microsoft.com/library/en-us/gdi/fontext_2ynn.asp): it is passed >the address of a callback function as third argument: > >int EnumFonts( > HDC hdc, // handle to DC > LPCTSTR lpFaceName, // font typeface name > FONTENUMPROC lpFontFunc, // callback function > LPARAM lParam // application-supplied data >); > >The callback has to have a prototype like > >int CALLBACK EnumFontsProc( > CONST LOGFONT *lplf, // logical-font data > CONST TEXTMETRIC *lptm, // physical-font data > DWORD dwType, // font type > LPARAM lpData // application-defined data >); > > >The lpData passed to the callback is equal to lParam passed to EnumFonts. >This is what you can use to get the this pointer through; most C APIs have >a paramter that can be (ab)used like that. > > >To use the EnumFonts API from a C++ class, we might thus write the following >(DISCLAIMER, UNCOMPILED - but you'll get the idea): > >class FontLister >{ > public: > void run(HDC dc); > > int callback(LOGFONT const &, TEXTMETRIC const &, DWORD type); >}; > >namespace >{ > int CALLBACK FontListerCallBack( > CONST LOGFONT *lplf, // logical-font data > CONST TEXTMETRIC *lptm, // physical-font data > DWORD dwType, // font type > LPARAM lpData // application-defined data > ); >} > >void FontLister::run(HDC dc) >{ > int const result(EnumFonts(dc, > 0, > &FontListerCallBack, > reinterpret_cast(this))); >} > >namespace >{ > int CALLBACK FontListerCallBack( > CONST LOGFONT *lplf, // logical-font data > CONST TEXTMETRIC *lptm, // physical-font data > DWORD dwType, // font type > LPARAM lpData // application-defined data > ) > { > // retrieve the this pointer > FontLister * const lister(reinterpret_cast(lpData)); > > // make sure that everything is safe and well > assert(lister!=0); > assert(lplf!=0); > assert(lptm!=0); > > // forward to non-static member function > return lister->callback(*lplf,*lptm,dwType); > } >} > >int FontLister::callback(LOGFONT const &lf, > TEXTMETRIC const &, > DWORD type) >{ > std::cout << lf.lfFaceName << '\n'; > > return 0; >} .