views:

83

answers:

4

Hi,

I want to use this function "EnumWindows(EnumWindowsProc, NULL);". The EnumWindowsProc is a Callback function:

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);

For this callback I want to use a member function of a class.

e.g:

Class MyClass
{
    BOOL CALLBACK My_EnumWindowsProc(HWND hwnd, LPARAM lParam);
    void          test();
};

So i want to bind the called Callback with my function !!!

I try this:

void MyClass::test()
{
    EnumWindowsProc ptrFunc = mem_fun(&MyClass::My_EnumWindowsProc);
    EnumWindows(ptrFunc, NULL);
}

It's doesn't work, "mem_fun" can take only one argument ! Is it possible to do that ? else do you know another solution ? (maybe a solution will be possible with Boost::bind)

A: 

look, non static methods of every class has one more hidden parameter (first one) this which is pointer to instance of class. so think that real signature is:

BOOL CALLBACK My_EnumWindowsProc(MyClass* this, HWND hwnd, LPARAM lParam);

is it clearer now? it means that you can't use it in this context

Andrey
I need a method to catch all information about all of my launched window in my desktop, that why I must do that !
Jaguar
didn't you read what i wrote? Methods have + 1 parameter, your call back must have 2
Andrey
@Andrey: Your response simply says he can't use a member function as a callback in this scenario. It doesn't show how to accomplish what needs to be accomplished.
John Dibling
@John Dibling: Thank you
Jaguar
+3  A: 

You need to create an Adapter, such as:

#include <windows.h>
#include <iostream>
#include <string>
using namespace std;

class MyCallback
{
public:
    MyCallback() : count_(0) {};
    static BOOL CALLBACK CallbackAdapter(HWND, LPARAM);
    BOOL Callback(HWND);
    unsigned count_;
};

BOOL MyCallback::Callback(HWND wnd)
{
    char title[1025] = {};
    GetWindowText(wnd, title, sizeof(title)-1);
    cout << wnd << "= '" << title << "'" << endl;
    ++count_;
    return TRUE;
}

BOOL MyCallback::CallbackAdapter(HWND wnd, LPARAM lp)
{
    MyCallback* that = reinterpret_cast<MyCallback*>(lp);
    return that->Callback(wnd);
}

int main()
{
    MyCallback cb;
    EnumWindows(&MyCallback::CallbackAdapter, reinterpret_cast<LPARAM>(&cb));
    cout << "Windows Found: " << cb.count_;
    return 0;
}
John Dibling
I try your code but it doesn't work, you have the same problem than me, the error is : 'EnumWindows' : cannot convert parameter 1 from 'BOOL (__cdecl *)(HWND,LPARAM)' to 'WNDENUMPROC'
Jaguar
@Jaguar: I fixed a problem with the declaration that prevented 32-bit compilers from grokking my code. Note the change to the declaration for `static BOOL CALLBACK CallbackAdapter(HWND, LPARAM);` and try again. (I added `CALLBACK`)
John Dibling
thank you John this method Work very good, but i want to try delete the reinterpret_cast with creating a new class with the static method and a static MyCallback* witch containt the "this" value ...
Jaguar
@Jaguar: Unfortunately you won't be able to eliminate the reinterpret_cast, because the callback must take an LPARAM. That's just how things like this work in the WINAPI
John Dibling
@Jaguar: You can replace the reinterpret_cast with a C-style cast like `(MyCallback*)lparam`, but it does the same thing as reinterpret_cast. reinterpret_cast is a little more expressive as to intent, so I'd stick with that.
John Dibling
@John Dibling: Yes the best in C++ is to use the c++ cast method ;)
Jaguar
A: 

Unfortunately EnumWindowsProc needs to be static to avoid adding the hidden "this" pointer and making it incompatible with the callback prototype. I've handled this in the past by saving the this pointer after creation of the window with this call:

SetWindowLong(handle,GWL_USERDATA,(DWORD)this);

and then inside the EnumWindowsProc (which is static) do something like this:

MyClass* thisClass = (MyClass*)GetWindowLong(hwnd,GWL_USERDATA);

and now you have the object pointer. You could use this to call a non-static function:

thisClass->ActualEnumWindowsProc(hwnd,lParam);
Cthutu
A: 

Nevermind my original answer: what you need to do is basically this:

struct InfoINeed {
 MyClass * mThis;
 ...
};

BOOL MyCallback(HWND hwnd, LPARAM lParam) {
 InfoINeed* info = (InfoINeed*)hwnd;
 // do your stuff, i.e. info->mThis->MyImplementationForCallback(lParam)
 // note that you won't need to pass hwnd further, it's a pointer to your own context
}

void MyClass::test()
{
    InfoINeed Info = {this, ...};
    EnumWindows(MyCallback, &Info);
}
Jan
thank you i will look !
Jaguar
@Jan: Yes i need to do that and the answer of John Dibling make that without error !
Jaguar