I'm getting a weird error trying to EnumWindows to a function inside a class. Here's my code
EnumWindows(&ConsoleDetector::EnumWindowsProc, NULL);
BOOL CALLBACK ConsoleDetector::EnumWindowsProc(HWND wnd, LPARAM lParam)
{
char className[200];
GetClassName(wnd, className, 200);
if (strcmp(className, "ConsoleWindowClass"))
m_result.push_back(wnd);
return TRUE;
}
Here's the error im getting:
ConsoleDetector.cpp:30: error: cannot convert 'BOOL (ConsoleDetector::*)(HWND__*, LPARAM)' to 'BOOL (*)(HWND__*, LPARAM)' for argument '1' to 'BOOL EnumWindows(BOOL (*)(HWND__*, LPARAM), LPARAM)'
Using MingW.
Thanks for help.
You are passing an instance method. You need to pass a plain function rather than a method bound to an instance.
It has to be declared like this:
BOOL CALLBACK EnumWindowsProc(HWND wnd, LPARAM lParam)
Pass the instance of the ConsoleDetector to the lParam parameter of EnumWindows and it will in turn be passed to your callback.
Like this:
BOOL CALLBACK EnumWindowsProc(HWND wnd, LPARAM lParam)
{
ConsoleDetector cd = static_cast<ConsoleDetector*>(lParam);
//do stuff with cd and wnd
}
ConsoleDetector *cd = ...
EnumWindows(EnumWindowsProc, static_cast<LPARAM>(cd));
You can't use the windows callback function with class member functions in c++. Only static class functions or non class functions are allowed.
How should the EnumWindows function kown the instance of a class? You can only supply a function pointer, not an instance pointer to EnumWindows
Related
This question already has answers here:
Win32 WndProc as class member
(3 answers)
Closed 9 years ago.
I'm trying to create a class that includes the WndProc, but I'm getting an error :
Error 2 error C2440: '=' : cannot convert from 'LRESULT (__stdcall Client::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
I searched the web for it, and seen that you need to make the WndProc static, but then, it compiles and everything is great, though if I want to change something, it doesnt let me :
Error 3 error C2352: 'Client::CreateMen' : illegal call of non-static member function
(CreateMen is a function in the class that creates the menu, using HMENU and such).
this is my function title:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
What can I do? I'm really confused...
Thanks!
A non-static class method has a hidden this parameter. That is what prevents the method from being used as a WndProc (or any other API callback). You must declare the class method as static to remove that this parameter. But as you already noticed, you cannot access non-static members from a static method. You need a pointer to the object in order to access them.
In the specific case of a WndProc callback, you can store the object pointer in the HWND itself (using either SetWindowLongPtr(GWLP_USERDATA) or SetProp()), then your static method can retrieve that object pointer from the hWnd parameter (using GetWindowLongPtr(GWLP_USERDATA) or GetProp()) and access non-static members using that object pointer as needed.
For example:
private:
HWND m_Wnd;
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK Client::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Client *pThis;
if (msg == WM_NCCREATE)
{
pThis = static_cast<Client*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
SetLastError(0);
if (!SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis)))
{
if (GetLastError() != 0)
return FALSE;
}
}
else
{
pThis = reinterpret_cast<Client*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
if (pThis)
{
// use pThis->member as needed...
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
m_Wnd = CreateWindowEx(..., this);
Unfortunately you cannot use a class function as a wndproc because as the compiler tries to tell you the calling convention differs, even though the two functions have the same signature, a class function expects the this pointer to be passed to it. On 64 bit builds it will expect it to be in the RCX/ECX registry while on 32 bit builds it will expect the this pointer to be the last argument pushed on the stack. The window code won't do that when calling your WndProc essentially turning this into a function call on a garbage pointer.
What you can do is make a static method that does something like the following:
LRESULT Client::CreateMen(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
// The OS makes sure GWLP_USERDATA is always 0 before being initialized by the application
Client* client = (Client*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(msg == WM_INIT)
{
client = new Client();
SetWindowLongPtr(hwnd, GWLP_USERDATA, client);
}
if(msg == WM_DESTROY)
{
client = (Client*)GetWindowLongPtr(hwnd, GWLP_USERDATA, client);
SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
delete client;
client = NULL;
}
if(client)
{
// Do stuff with the client instance
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
I haven't tested this, so it might have some bugs, but let me know if you have any problems with it and I'll refine it if need be.
This question already has answers here:
Win32 WndProc as class member
(3 answers)
Closed 9 years ago.
I'm trying to create a class that includes the WndProc, but I'm getting an error :
Error 2 error C2440: '=' : cannot convert from 'LRESULT (__stdcall Client::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
I searched the web for it, and seen that you need to make the WndProc static, but then, it compiles and everything is great, though if I want to change something, it doesnt let me :
Error 3 error C2352: 'Client::CreateMen' : illegal call of non-static member function
(CreateMen is a function in the class that creates the menu, using HMENU and such).
this is my function title:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
What can I do? I'm really confused...
Thanks!
A non-static class method has a hidden this parameter. That is what prevents the method from being used as a WndProc (or any other API callback). You must declare the class method as static to remove that this parameter. But as you already noticed, you cannot access non-static members from a static method. You need a pointer to the object in order to access them.
In the specific case of a WndProc callback, you can store the object pointer in the HWND itself (using either SetWindowLongPtr(GWLP_USERDATA) or SetProp()), then your static method can retrieve that object pointer from the hWnd parameter (using GetWindowLongPtr(GWLP_USERDATA) or GetProp()) and access non-static members using that object pointer as needed.
For example:
private:
HWND m_Wnd;
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK Client::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Client *pThis;
if (msg == WM_NCCREATE)
{
pThis = static_cast<Client*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
SetLastError(0);
if (!SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis)))
{
if (GetLastError() != 0)
return FALSE;
}
}
else
{
pThis = reinterpret_cast<Client*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
if (pThis)
{
// use pThis->member as needed...
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
m_Wnd = CreateWindowEx(..., this);
Unfortunately you cannot use a class function as a wndproc because as the compiler tries to tell you the calling convention differs, even though the two functions have the same signature, a class function expects the this pointer to be passed to it. On 64 bit builds it will expect it to be in the RCX/ECX registry while on 32 bit builds it will expect the this pointer to be the last argument pushed on the stack. The window code won't do that when calling your WndProc essentially turning this into a function call on a garbage pointer.
What you can do is make a static method that does something like the following:
LRESULT Client::CreateMen(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
// The OS makes sure GWLP_USERDATA is always 0 before being initialized by the application
Client* client = (Client*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(msg == WM_INIT)
{
client = new Client();
SetWindowLongPtr(hwnd, GWLP_USERDATA, client);
}
if(msg == WM_DESTROY)
{
client = (Client*)GetWindowLongPtr(hwnd, GWLP_USERDATA, client);
SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
delete client;
client = NULL;
}
if(client)
{
// Do stuff with the client instance
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
I haven't tested this, so it might have some bugs, but let me know if you have any problems with it and I'll refine it if need be.
This question already has answers here:
how to pass a non static-member function as a callback?
(8 answers)
Closed 9 years ago.
Can I use member function as first argument to EnumWindows? I don't see any workaround in this case even with boost::bind.
Given this normal callback function:
BOOL CALLBACK EnumWindowsProc(HWND wnd, LPARAM lParam);
You can invoke EnumWindows using lParam to pass it a pointer to your class:
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(this));
In EnumWindowsProc you can simply call member function (casting lParam to your class type). Like this:
BOOL CALLBACK EnumWindowsProc(HWND wnd, LPARAM lParam)
{
return reinterpret_cast<MyClass*>(lParam)->EnumWindows(wnd);
}
If you don't want to make your class method public you can:
Pack a struct to contain both class instance and pointer to member.
Use a library for delegates.
Use boost std:bind (in this case it'll work well because you do it on your own class member, it has not to be __stdcall).
Whatever you will use you can find more details in this post here on SO.
EnumWindows takes a callback that looks like this
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam);
You cannot use either a member function or a lambda that has a capture. You do this instead.
typedef std::function<bool(HWND hwnd)> func_type;
BOOL CALLBACK MyEnumProc(HWND hwnd, LPARAM lparam)
{
auto& func = *reinterpret_cast<func_type*>(lparam);
if(func(hwnd))return TRUE;
else return FALSE;
}
You would use it like this
auto f = std::make_shared<func_type>(std::bind(&mymemberfunction,this));
EnumWindows(MyEnumProc,reinterpret_cast<LPARAM>(f.get()));
//Make sure to keep the shared_ptr around until you are done enumerating
The title is pretty descriptive. I have stored a non-static pointer to a member function in a vector of a structure that store member function pointers in my class, and I need a static function in the class to call that function.
I have access to the class instance in my static function, but I still can't seem to call the member function through the pointer b/c of an error message error C2597: illegal reference to non-static member
The syntax I have now is (object->*(vector[a].function)) (parameter). Simplified code below:
class Base
{
private:
struct FunctionRelation
{
UINT message;
LRESULT (Base::*function) (HWND, WPARAM, LPARAM);
};
static LRESULT CALLBACK WndProc (HWND window, UINT msg, WPARAM wparam, LPARAM lparam);
std::vector<FunctionRelation> func_rel;
}
The pointer to Base is stored in the USERDATA of the window passed to the WndProc function, and thus I have access to the class instance. In WndProc I have:
Base *user_data = reinterpret_cast<Base *>(GetWindowLongPtr (window, GWLP_USERDATA));
//Loop through our function relations and call those functions. Else, just return DefWindowProc.
if (user_data != NULL) //If it is not directly after we created a window.
for (int a = 0;a < static_cast<int>(user_data->func_rel.size ());a++)
if (user_data->func_rel[a].message == msg)
return (user_data->*(func_rel[a].function)) (window, wparam, lparam);
return DefWindowProc (window, msg, wparam, lparam);
I have tried the (object)->*(function) (parameter) syntax
Try the (object->*function)(parameter) syntax instead if object is a pointer, or (object.*function)(parameter) if it's an object or reference.
UPDATE: now you've posted the error message and some representative code, we can see that the problem is that you're trying to access the class member func_rel from a static member function. You'll need to access that via the class pointer:
(user_data->*(user_data->func_rel[a].function)) (window, wparam, lparam);
^^^^^^^^^^^
I have a class:
class SomeClass
{
public:
void Init ();
private:
LRESULT CALLBACK WndProc (HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam);
};
Also, in another file I have a function:
void MakeWindow (WNDPROC wnd_proc, DWORD style, HICON lg_icon, ...);
The first parameter is supposed to take a LRESULT CALLBACK function as input. Somewhere I also have a definition for the Init function:
void SomeClass::Init ()
{
MakeWindow (this->WndProc, WM_POPUP, NULL, ...);
}
This gives me error C3867 in VS2012 when I try to pass this->WndProc to WNDPROC wnd_proc. Is there any way I can pass the LRESULT CALLBACK WndProc function to MakeWindow?
The problem is that your WndProc method is an instance method and so does not match WNDPROC. Because it is an instance method it receives an extra, implict, this parameter.
You need to declare it as a static method in order for it to be compatible with WNDPROC.