I am learning Windows programming in C++. I created my first Windows, but there's one thing I don't really understand: WNDPROC in WNDCLASS. The structure was documented like this:
typedef struct tagWNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
Now in order to assign to lpfnWndProc, I must have a callback function WindowProc like this:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
And then I have to assign lfpnWndProc like this:
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
As I understand, WindowProc is a function. If I assign like this, it means I am assigning to a function pointer in WNDCLASS. But in the WNDCLASS definition, nothing indicates it is a function pointer. Further more, it looks like a data type to me rather than a function pointer.
Normally I would do get a function pointer like this to pass in as a parameter or used as a variable:
#include <stdio.h>
void my_int_func(int x)
{
printf("%d\n",x);
}
int main(void)
{
void (*foo) (int);
foo = &my_int_func;
foo(2);
(*foo)(2);
}
But the way I have to assign WindowProc just does not make sense to me. Can someone help me understand this?
WNDPROC is a function pointer type. The definition is:
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
Functions, sort of like arrays, automatically decay into pointers in certain contexts. The & in your example program is optional.
MSDN says,
lpfnWndProc
Type: WNDPROC
A pointer to the window procedure. You must use the CallWindowProc function to call the window procedure.
WinUser.h defines it as,
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
Related
So I saw this on a code snippet online:
typedef LRESULT(CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
What I want to know here is structure-wise.
What does this mean?
I read the msdocs documentation for typedefs but I still can't figure out what this does here, so I know it wants to give a synonym for LRESULT but what does the (CALLBACK* WNDPROC) do here, does it Mean name f_EndScene as a pointer to a CALLBACK which takes (HWND, UINT, WPARAM, LPARAM) parameters is a synonym for an LRESULT?
I really can't wrap my head around this.
Thanks in advance.
WNDPROC is the name of the typedef. I'll admit that knowing this is a bit of an art. The rule is basically that the name of a typedef/variable is actually the innermost thing in the declaration. Starting at the name, move right when you can and left when you must, respecting parentheses (the spiral rule). The declaration actually reads:
Declare the type alias WNDPROC to be pointer to CALLBACK function taking arguments HWND, UINT, WPARAM, and LPARAM returning LRESULT.
The spiral rule basically comes from nesting. Starting from the simplest typedef possible and repeatedly replacing the place where the actual typedef name goes with the "missing" bit of the tree:
typedef LRESULT WNDPROC; // WNDPROC = LRESULT
typedef LRESULT WNDPROC(...); // WNDPROC = function taking (...) returning LRESULT
typedef LRESULT (CALLBACK WNDPROC)(...); // WNDPROC = CALLBACK function taking (...) returning LRESULT
typedef LRESULT (CALLBACK *WNDPROC)(...); // WNDPROC = pointer to CALLBACK function taking (...) returning LRESULT
This typedef declares WNDPROC type, it is a pointer to a function type.
All it fits standard C and C++, except CALLBACK. CALLBACK is a macro that expands to __stdcall which is one of x86 calling conventions. (On x64 you can ignore __stdcall, there's (mostly) only one calling convetnion on x64)
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.
This question already has answers here:
Why callback functions needs to be static when declared in class
(6 answers)
Closed 10 years ago.
I'm trying to make a little class that displays console window in parent window. (you can imagine chat or debug info being displayed there)
Now, since diferent instanes do have different private variables (such as message array or parent window), I need to use non-static method as callback for the Windows events.
I have thought of ways, where I'd pass the actual class instance to static callback function and then called the proper method on it, but in winAPI, everything is done using TranslateMessage and DispatchMessage giving me no chance to use arguments of my own.
I found some code here: Class method as winAPI callback, but I don't understand it, and I think it is not exactly what I need. If it is, then please give me further explanation of code provided.
Error I get:
error: argument of type 'LRESULT (WindowConsole::)(HWND__, UINT, WPARAM, LPARAM)' does not match 'LRESULT (*)(HWND__, UINT,
WPARAM, LPARAM)'
I don't know what that star in brackets means, but this is what does not match.
And the code:
class WindowConsole {
char messages[255][255];
HWND mainWindow;
public:
int width;
int height;
inline HWND create(HWND parent);
inline bool update();
inline LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
};
HWND WindowConsole::create(HWND parent) {
HINSTANCE inst = GetModuleHandle (0);
WNDCLASSEX wincl;
/* The Window structure */
wincl.hInstance = inst;
wincl.lpszClassName = "ConsoleClass";
wincl.lpfnWndProc = this->WndProc; /* This function is called by windows */
/* more WNDCLASSEX crap...*/
mainWindow = CreateWindow (
/*PARAMS*/
);
ShowWindow(mainWindow,1);
return mainWindow;
}
bool WindowConsole::update() {
return true;
}
LRESULT CALLBACK WindowConsole::WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) /* handle the messages */
{
/*EVENT crap*/
}
return 0;
}
The usual is something on this order:
#include <windows.h>
class BaseWindow {
static LRESULT CALLBACK internal_WndProc(HWND hWnd, int msg, WORD wParam, LONG lParam) {
BaseWindow *c = (BaseWindow *)GetWindowLong(hWnd,GWLP_USERDATA);
if (c == NULL)
return DefWindowProc(hWnd, msg, wParam, lParam);
return c->WindowProc(hWnd, msg, wParam, lParam);
}
public:
virtual int WindowProc(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam) = 0;
BaseWindow(HINSTANCE instance) {
WNDCLASS window_class = {0};
HWND window;
HMENU my_menu;
window_class.lpfnWndProc = (WNDPROC)internal_WndProc;
/* fill in window_class here */
RegisterClass(&window_class);
window = CreateWindow(
"My Application", "Stupidity",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, my_menu, instance, NULL);
// save the address of the class as the Window's USERDATA.
SetWindowLong(window, GWLP_USERDATA, (long)this);
}
};
With this, you derive a class from BaseWindow. In your derived class, you provide a "WindowProc" that overrides the (pure virtual) one in BaseWindow. The trick here is fairly simple: since you can't pass a parameter directly, you store the address of the class in the window's GWLP_USERDATA, then in the window proc (try to) retrieve that and use it to call the derived class' virtual window proc.
As an aside, note that this is a sketch, not a finished work (so to speak). Though it should compile as-is, the result won't actually work unless you fill in a fair number of pieces that aren't here (e.g., the other fields of the WNDCLASS structure being only one of the most obvious).
The other question you linked to only applies partially.
The WindowProc method does need to be static. Then right after the call to CreateWindowEx call SetWindowLongPtr with GWLP_USERDATA as the second parameter and this as the third one. That associates the HWND with the class instance. Then in the static WindowProc method call GetWindowLongPtr (again with GWLP_USERDATA) to get the WindowConsole instance that received the UI event.
That's all explained in detail here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff381400(v=vs.85).aspx
I use a simple solution.
The winproc is a template function.
The message receiver is inside setwindowptr.
If the receiver has a function with the message name , for instance, onpaint , then the wm_paint is included at message switch.
http://www.thradams.com/codeblog/wndproc.htm
So I'm writing some wrapper classes for GUI programming in Win32. I'm starting with a Window class, and so far it contains a MainLoop method that is basically a clone of the standard Win32 WinMain function. That way, one can do something like this:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow) {
Window *win = new Window();
// Do all your widget creation and add it to the window object...
return win->MainLoop(hInst, hPrev, szCmdLine, nCmdShow);
}
Inside the window object's MainLoop method, it must create the new Win32 window by setting its lpfnWndProc member. This member, as any Win32 programmer knows, is a function pointer to a specifically defined WndProc function. The problem is, if I were to create a WndProc function, I would need access to that window object's members (so that it knew what to draw on the window, etc.). This leaves me two options (that I know of):
I can define WndProc at the top level, but that cuts off access to the object's members.
I can define it as a class method, but then it's not the exact function type that lpfnWndProc asks for, so I can't set it!
Can anyone help me unravel this catch-22?
You could also make it a static member function. :)
Anyways, a solution depends on if you need only one window or if you need multiple windows.
First a solution for single windows:
// in .h
class Window{
public:
static LRESULT WINAPI MessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT InternalMessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// ...
};
// in .cpp
#include "Window.h"
Window* global_window = 0;
Window::Window(/*...*/){
if(!global_window)
global_window = this;
else
// error or exception... or something else
}
LRESULT WINAPI Window::MessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
return global_window->InternalMessageProc(hWnd, msg, wParam, lParam);
}
Now if you want to allow multiple windows, use a std::map (or if your compiler supports std::unordered_map).
Edit: This solution comes with some subtle problems. As #Ben Voigt points out in his comment, you get a chicken and egg problem as the MessageProc is called inside of CreateWindow(Ex), but only after the CreateWindow(Ex) call you have the window handle. Here's a solution based on Ben's next comment (thanks!):
// Window.h stays the same
// in .cpp
#include "Window.h"
#include <map>
std::map<HWND, Window*> window_map;
Window* currently_created_window = 0;
Window::Window(){
currently_created_window = this;
window_handle = CreateWindow(/*...*/);
}
LRESULT WINAPI Window::MessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
// if the key 'hWnd' doesn't exist yet in the map
// a new key-value pair gets created and the value gets value-initialized
// which, in case of a pointer, is 0
if(window_map[hWnd] == 0){
// window doesn't exist yet in the map, add it
window_map[hWnd] = currently_created_window;
}
window_map[hWnd]->InternalMessageProc(hWnd, msg, wParam, lParam);
}
Be cautious though, as the above example isn't thread-safe. You need to mutex-lock the creation of the window:
Window::Window(/*...*/){
Lock lock_it(your_mutex);
currently_created_window = this;
window_handle = CreateWindow(/*...*/);
lock_it.release();
// rest of the initialization
}
The above should do for the thread-safety (I hope).
You need to create window map and when you create new window just add it to this global map. You can use simple linked list instead of course.
map<HWND, Window *> wndmap;
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
Window *pWnd = wndmap [hwnd];
....
}
WndProc cannot be an instance member function, because Windows will not pass any hidden this parameter. It can be namespace scope or a static member.
One simple solution is to use a map<HWND, Window*> to find the object, and then forward parameters to a method on the object.
Note that WndProc can maintain the map itself, since CreateWindow provides an opaque user parameter that shows up in WM_CREATE which is useful for carrying the Window *, and then you remove the entry in WM_DESTROY.
Define your WndProc as a static class member - this will then be compatible (for all compilers I'm aware of) with non-member function pointer, such as those used in Win32 programming.
But I have to say that this is a bit of a waste of time - there are a zillion Windows class libraries out there, and I don't think the world really needs another one.
Sounds you need to declare the function without defining it. That's what prototypes are for.
class Object;
void f(Object* o);
class Object {
public:
...
void some_method() {
... &f ...
}
void another_method() {
...
}
...
};
void f(Object* o) {
...
o->another_method();
...
}
The other way around might also be possible.
class Object {
public:
...
void some_method();
void another_method();
...
};
void f(Object* o) {
...
o->another_method();
...
}
void Object::some_method() {
... &f ...
}
void Object::another_method() {
...
}
I'm calling a Dialog that has it's resources and dlg-procedure in a DLL.
I'm not using a DEF file or LIB file. The function names are known, the function args are known, I'm using GetProcAddress to get a pointer to the functions I'm interested in.
'Why' I'm doing it this way is of no consequence, it's an experiment in 'learning'.
This works on _cdecl functions, but on the CALLBACK (_stdcall), I can't get a pointer to the actual dialog procedure (it returns 0).
Here's how I'm doing my pointers:
//////////////////// DLL TEST STUFF ////////////////////////////
#define DLLPATH "../../testdll/release/testdll.dll"
//typedef some function pointers
typedef HINSTANCE (__cdecl *INSTPROC )(void);
typedef int (__cdecl *VOIDPROC )(void);
typedef LRESULT (__stdcall *DLGROC )(HWND, UINT, WPARAM, LPARAM );
///////////////////////////////////////////////////////////////
As I said, any function that is NOT a callback returns a valid result, additionally, the dialog pops up as expected, no problems with DLL's HINSTANCE.
But without a pointer to it's dlgproc, no button messages have anywhere to go.
Here's some more test code:
//use DLL funcs without lib or def files
//this works
GetInst = (INSTPROC)GetProcAddress(Loadme,"getinst");
//this works
GetID = (VOIDPROC)GetProcAddress(Loadme,"getid");
//this doesn't work, rets 0
DlgProc = (DLGPROC) GetProcAddress(Loadme,"dllProc");
//test for result
dllid =(GetID)();
dllinst=(GetInst)();
//compare hinst OK
wsprintf(buf,"dllinst=%x Loadme=%x",dllinst, Loadme);
MessageBox(hwnd,buf,"",MB_OK);
//check resOurce ID OK
wsprintf(buf,"GetID returned: %d",dllid);
MessageBox(hwnd,buf,"",MB_OK);
//check dllProc addr NOGO, ret=0
wsprintf(buf,"dllProc=%x",DlgProc);
MessageBox(hwnd,buf,"",MB_OK);
// DLL instance, resource ID, parent, dlgproc
DialogBox(Loadme , MAKEINTRESOURCE(dllid), hwnd, DlgProc);
//dialog loads and shows, can't get dlgproc addr
FreeLibrary(Loadme);
///////////////// END DLL TEST STUFF ///////////////
On the DLL side of things, it looks like this:
__declspec(dllexport) LRESULT CALLBACK dllProc(
HWND hwnd,
UINT Message,
WPARAM wParam,
LPARAM lParam
)
{
hpwnd=hwnd;
switch (Message){
case WM_INITDIALOG:
MessageBox(hwnd,"At DlgProc...","",MB_OK);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam)){
case IDEND:
case IDCANEND:
EndDialog(hwnd,0);
return TRUE;
}
return TRUE;
}
return FALSE;
}
Which really doesn't matter at this point, since I can't get a pointer to the callback in the first place.
If anyone happens to know the fix for getting a pointer to the callback, I would very much appreciate your input.
Thanks for your patience.
You need to declare your dllProc inside an extern "C" block to prevent its name being decorated when exported, so that when you ask for a function called "dllProc" such a function is found (instead of "dllProc#blahmoocow" or whatever madness the C++ decoration produces. :-)).
Place this declaration before the dllProc definition:
extern "C"
{
__declspec(dllexport) LRESULT CALLBACK dllProc(
HWND hwnd, UINT Message, WPARAM wParam, PARAM lParam);
}
You can also then drop the __declspec(dllexport) from the dllProc definition.