Subj : Re: Callbacks in C++ or any other way To : borland.public.cpp.borlandcpp From : maeder Date : Wed Jun 09 2004 08:58 am "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; } .