Simple question.

According to wikipedia a "callback" is "a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time."

So does that mean that something like this.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

Actually goes to a separate DLL or the OS and fills in for the variables hwnd and uMsg? Therefore being asynchronous or do I have this all wrong?
(I didn't include lParam and wParam since I believe I've read that they're not used out side of the 16 bit Windows days.)

Here's why I see it this way.

I've got a bit of code from the MSND site that I'm trying to understand fully.
In order to save post space i'll add my thought process in the code as extra comments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
//This is going to be used to name the window class
    const wchar_t CLASS_NAME[]  = L"Sample Window Class";
    // Declare a winclass object.
    WNDCLASS wc = { };
// Call the WindowProc function and assign its return values to lpfnWndProc
    wc.lpfnWndProc   = WindowProc;
//Assign wc.hInstance the hInstance the program received from the OS.
    wc.hInstance     = hInstance;
//Assign the class name
    wc.lpszClassName = CLASS_NAME;
Register the class using the address of wc
    RegisterClass(&wc);//  


PS: As I read more online searches about my question I think that my mind is in the right place with CALLBACK being a asynchronous call to the OS for the assignment of the parameters of the function next to it. But I'd still like some confirmation on the subject.

Please and thanks in advance.

Where I got the code from.
http://msdn.microsoft.com/en-us/library/windows/desktop/ff381409(v=vs.85).aspx
Last edited on
In this case (Windows API), your code goes in a callback function that you register with the Windows at creation. Windows then calls your function when a message needs to be handled.
Factors wrote:
I didn't include lParam and wParam since I believe I've read that they're not used out side of the 16 bit Windows days



This is absolutely wrong. Many windows messages makes use of wParam and lParam, does not matter if this is x86, x64 or IA64 architecture.
This is absolutely wrong. Many windows messages makes use of wParam and lParam, does not matter if this is x86, x64 or IA64 architecture.

Ok thank you for clearing that up.

In this case (Windows API), your code goes in a callback function that you register with the Windows at creation. Windows then calls your function when a message needs to be handled.

I'm not quite sure I understand what you mean. What do you mean by callback function that I register?
The Windows Api functions you are examining here are essentially what OOP looks like in C. It not C++ but OOP based on C. In C there are no 'classes'. However, there is the struct. And a struct can be thought of as a simple and awkward kind of 'class'. Note that, like the C++ class, it can contain member functions; however, it doesn't look quite like a member function of a C++ class. That is what the WNDCLASSEX::lpfnWndProc() member function of the WNDCLASSEX struct is. The CALLBACK macro simply resolves to __stdcall in 32 bit Windows, and nothing in 64 bit windows, because 64 bit windows does't implement some of the calling conventions of 32 bit Windows.

So to create a window using the C based Api you first 'Register' a class by filling in the members of the WNDCLASSEX struct, and then calling RegisterClassEx(). The two most important fields of the WNDCLASSEX struct are the szClassName member, which is a pointer to a null terminated char array, and the address of the function which Windows will call into when the operating system detects any activity that the window needs to know about.

As an aside, function pointers are a critically important topic in C based OOP as implemented in the C Api. You don't have member functions like in C++; what you have are function pointer calls in many cases. That is how Windows the operating system notifies an instantiation of a Window Class of pertinent data, i.e., through the function pointer address you passed into Windows by Registering a Window Class with RegisterClassEx(), and that .lpfnWndProc is the address of the 'CALLBACK' Windows will call.

Added Later:

I might further point out that there is a one to many relationship between a class registered with RegisterClassEx() and instantiated window objects. The implications of this are that you'll only have one CALLBACK Window Procedure for as many instantiations of the Window Class that you make; think of the cookie cutter - cookie analogy. Each call into the Window Procedure will be accompanied by the HWND to which the call applies.
Last edited on
http://cplusplus.com/forum/windows/90529/#msg486698

Oh wow, thanks that helps a hell of a lot. I wondered why microsoft didn't use classes in what I've seen so far, but now it makes more sense.

So WNDCLASSEX::lpfnWndProc is a function pointer and CALLBACK is a macro.
Thank you.
Yes, from WinDef.h

1
2
#define CALLBACK    __stdcall
#define WINAPI      __stdcall 


For 64 bit Windows CALLBACK is defined as nothing, so the text is simply removed from the
front of the Window Procedure name in use. This is at base a hardware/processor type issue.

Note further than the Window Procedure must conform exactly to a specified function signature,
as its called through its address (which you supplied in the WNDCLASSEX struct) by Windows -
not through any textural name. You can name it however you want in your code. In large, complex
applications I write I'll have a seperate Window Procedure for each Window Class I register, and
I'll usually have a seperate Window_Procedure_Name.cpp and Window_Procedure_Name.h file for each.
However, programs usually only need one 'Message Pump' (except in unusual circumstances); usually
located at the bottom of WinMain().

Just for kix, here's a simple Windows program that will work fine with a 32 bit compile (not
with 64 bit) where I've simply removed the CALLBACK, LRESULT, WINAPI macros entirely ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//Main.cpp
#include <windows.h>
#include <tchar.h>
#define IDR_MAIN_MENU  2000
#define IDM_FILE_OPEN  2100
#define IDM_FILE_EXIT  2105


long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
    case WM_CREATE:
     {
         HMENU hMenu, hSubMenu;
         hMenu = CreateMenu();
         hSubMenu = CreatePopupMenu();
         AppendMenu(hSubMenu,  MF_STRING,            IDM_FILE_OPEN,       "&Open");
         AppendMenu(hSubMenu,  MF_STRING,            IDM_FILE_EXIT,       "E&xit");
         AppendMenu(hMenu,     MF_STRING | MF_POPUP, (UINT)hSubMenu,      "&File");
         SetMenu(hwnd, hMenu);
         return 0;
     }
    case WM_DESTROY:
     {
         PostQuitMessage(0);
         return 0;
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("Mnu05");
 WNDCLASS wc;
 MSG messages;
 HWND hWnd;

 wc.style         = 0,                         wc.lpfnWndProc   = fnWndProc;
 wc.lpszClassName = szClassName,               wc.cbClsExtra    = 0;
 wc.cbWndExtra    = 0,                         wc.hInstance     = hIns,
 wc.hIcon         = NULL,                      wc.hCursor       = LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW,   wc.lpszMenuName  = NULL;
 RegisterClass(&wc);
 hWnd=CreateWindow(szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,200,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


I'm not saying you should do this; only trying to make the point that there's nothing 'magical'
or overly hard to comprehend going on here.
Topic archived. No new replies allowed.