2

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)

Jaguar
  • 339
  • 2
  • 3
  • 9

5 Answers5

3

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
  • 99,718
  • 31
  • 186
  • 324
  • 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 Mar 04 '10 at 19:01
  • @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 Mar 04 '10 at 19:05
  • 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 Mar 04 '10 at 19:34
  • @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 Mar 04 '10 at 20:34
  • @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 Mar 04 '10 at 20:35
  • @John Dibling: Yes the best in C++ is to use the c++ cast method ;) – Jaguar Mar 05 '10 at 09:58
0

guys the Adapter worked great for me, here is a sample of my code, which I was using with a EnumChildWindow to preform an AutoSave.

Header file:

public:

    BOOL AutosaveTimerChildProc( HWND hwnd );
    static BOOL CALLBACK CallbackAdapter(HWND wnd, LPARAM lp);
...

C++ file:

BOOL CMainFrame::InitInstance()
{
    SetTimer(0, 5 * 60 * 1000,NULL);
    return TRUE;
}

void CMainFrame::OnTimer(UINT nIDEvent)
{
    ::EnumChildWindows(m_hWnd,&CMainFrame::CallbackAdapter,NULL);
}

BOOL CMainFrame::AutosaveTimerChildProc(HWND hwnd)
{
    if(DYNAMIC_DOWNCAST(CVISIONView,CWnd::FromHandle(hwnd)) != NULL)
    {
        ::PostMessage(hwnd,WM_MYVIEW_AUTOSAVETIMER,0,0);
    }

    return TRUE;
}

BOOL CMainFrame::CallbackAdapter(HWND wnd, LPARAM lp)
{
    CMainFrame* that = reinterpret_cast<CMainFrame*>(lp);
    return that->AutosaveTimerChildProc(wnd);
}
Ryan
  • 1
0

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
  • 8,713
  • 7
  • 33
  • 49
0

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
  • 1,807
  • 13
  • 26
-1

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
  • 59,039
  • 12
  • 119
  • 163
  • I need a method to catch all information about all of my launched window in my desktop, that why I must do that ! – Jaguar Mar 04 '10 at 19:03
  • didn't you read what i wrote? Methods have + 1 parameter, your call back must have 2 – Andrey Mar 04 '10 at 19:18
  • 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 Mar 04 '10 at 20:33