Use object method as WinApi WndProc callback [duplicate] - c++

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

Related

Do CustomDialogProc have to be static. WinAPI

I've been looking at creating a custom control with WinApi for my application, and I have made a class which contains the CustomDialogProc and CreateWindowEx and RegisterClass() functions.
I can set a breakpoint inside the CustomDialogProc and it hits, so the class is registered correctly.
However, I have to declare the CustomDialogProc function as static int he header of my class
static LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam);
If I don't set it to static, I get the error
Error C3867 'CustomControl::CustomDialogProc': non-standard syntax; use '&' to create a pointer to member
IS this necessary, this requires all my controls created within this control to be static as well. What if I want multiple instances of this control?
How can I get around this? The main MsgProc doesn't seem to be a static function. Neither is the UpDownDialogProc in the first link shown below
Below is my code for CustomControl.h in case anyone needs it.
Put together from code found at:
https://msdn.microsoft.com/en-us/library/windows/desktop/hh298353(v=vs.85).aspx
https://www.codeproject.com/Articles/485767/True-Windows-control-subclassing
Thanks,
#pragma once
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
class CustomControl
{
public:
CustomControl();
~CustomControl();
LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//DO STUFF HERE
break;
}
}
bool CreateControl(HWND hwnd, HINSTANCE* m_hApp_instance)
{
g_hInst = m_hApp_instance;
RegisterSubClass(*g_hInst, WC_LISTBOX, TEXT("CustomControl"), CustomDialogProc);
HWND hwndCustom = CreateWindow(TEXT("CustomControl"), NULL, WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hwnd, (HMENU)100, *g_hInst, NULL);
return true;
}
private:
HINSTANCE* g_hInst;
WNDPROC RegisterSubClass(HINSTANCE hInstance, LPCTSTR ParentClass, LPCTSTR ChildClassName, WNDPROC ChildProc) {
WNDCLASSEX twoWayStruct;
WNDPROC parentWndProc;
if (GetClassInfoEx(NULL, ParentClass, &twoWayStruct)) {
parentWndProc = twoWayStruct.lpfnWndProc; // save the original message handler
twoWayStruct.cbSize = sizeof(WNDCLASSEX); // does not always get filled properly
twoWayStruct.hInstance = hInstance;
twoWayStruct.lpszClassName = ChildClassName;
twoWayStruct.lpfnWndProc = ChildProc;
/* Register the window class, and if it fails return 0 */
if (RegisterClassEx(&twoWayStruct))
return parentWndProc; // returns the parent class WndProc pointer;
// subclass MUST call it instead of DefWindowProc();
// if you do not save it, this function is wasted
}
return 0;
}
};
The most common way is to use SetWindowLongPtr to store a pointer to the object associated with the window handle.
HWND hWnd = CreateWindow(...);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) this);
And then in your dialog proc, get that pointer and call into your class:
// this static method is registered with your window class
static LRESULT CALLBACK CustomDialogProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
auto pThis = (CustomControl*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pThis != NULL)
return pThis->CustomDialogProcInstance(hWnd, uMsg, wParam, lParam);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// this instance method is called by the static method
LRESULT CustomDialogProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
}
Make sure you manage your window and class life cycle appropriately to prevent the window proc from calling a deleted object instance. In many cases, this is as simple as ensuring DestroyWindow is called if your class is destructed.
The Windows API is C language based. It knows nothing about C++, non-static member functions, objects, etc.
So yes, all of your functions that will communicate with the Windows API directly must be static class member functions, or non-class / global / "free" functions.
That doesn't preclude you from writing a C++ wrapper for a C API. That's what libraries such as Microsoft's MFC or the old Borland OWL libraries accomplish. Other independent groups have also written wrappers for the Windows API.
Note that these differing libraries accomplish the goal of hooking a C based API to C++ in different ways. One is to use the SetWindowLongPtr method mentioned in the answer given by #MichaelGunter. Another method is to use maps to associate window handles and static Window procedures.
I would suggest before you try this on your own (creating a wrapper), you investigate how others have done this already, and choose the best approach that fits. Another suggestion is that before you even create a wrapper, you should know the C based API on much more than a cursory level. You need advanced to expert knowledge of any C API you plan to create a C++ wrapper for if you want the wrapper to work relatively flawless under different scenarios.

Subclassing an edit control from a user defined class/pointer-to-member-function

I think I've fallen in the same trap as many before me where I try to impose a nice OO methodology on win32 API programming. No MFC, no AFX, I'm not even using VC++, I'm using C::B with gcc.
I think what I'm trying to do is impossible, but since MFC exists (although I'm not using it) there must be some way.
I've created a class to contain several window controls. It implements handlers for WM_CREATE and WM_COMMAND, and keeps track of all the associated data around my small group of controls (ID codes and HWNDs).
It works great for buttons, static controls, even light GDI methods, but it all breaks down when I try to subclass an edit control.
Really, I just want to capture the "enter" key, but as anybody who's been down that road before will attest, when an edit control has focus, the parent window doesn't receive WM_KEYDOWN or WM_COMMAND, we are left to implement our own proc. Super lame.
OK, so subclassing an edit control is fine, if the editProc is global or static. I know that is because SetWindowLongPtr needs a function address, and that concept is nebulous for a member function.
So the object of my class is declared as "static" inside the parent WndProc. But the function is not "static" because then I wouldn't have access to non-static data members (completely defeating the purpose of this exercise). I'm hoping that because the objest is itself static, I should be able to properly define the address of one of its member functions.
Readers that have tried this before will either have given up and used MFC or something else, or perhaps have found a clever work-around.
I'll let this sample code do the rest of the talking: (simplified - will not compile as such)
/**** myprogram.c ****/
#include "MyControlGroup.h"
int winMain(){ // etc... }
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// object is static becuse it only needs to be initialized once
static MyControlGroup myControl;
if (msg == WM_CREATE)
myControl.onWMCreate(hWnd);
else if (msg == WM_COMMAND)
myControl.onWMCommand( wParam, lParam );
else if (msg == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProcW(l_hWnd, l_msg, l_wParam, l_lParam);
}
The header file for my class:
/**** MyControlGroup.h ****/
class MyControlGroup
{
private:
HWND m_hWndParent;
HWND m_hWndEditBox;
int m_editBoxID;
public:
MyControlGroup();
void onWMCreate(HWND);
void onWMCommand(WPARAM, LPARAM);
// want to find a way to pass the address of this function to SetWindowLongPtr
LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
...and the implementation:
/**** MyControlGroup.cpp ****/
static int staticID = 1;
MyControlGroup::MyControlGroup()
{
m_editBoxID = staticID++;
}
void MyControlGroup::onWMCreate(HWND hWnd)
{
// My control group has buttons, static controls, and other stuff which are created here with CreateWindowW. It also has an edit control:
m_hWndEditBox = CreateWindowW(L"EDIT", L"initial text", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 150, 20, hWnd, (HMENU)m_editBoxID, NULL, NULL);
/*
To subclass the edit control, I need a pointer to my customized proc. That means I
need a pointer-to-member-function, but SetWindowLongPtr needs a pointer to global or
static function (__stdcall or CALLBACK, but not __thiscall).
*/
// I'd like to do something like this, adapted from a great write-up at
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
LERSULT (MyControlGroup::*myEditProcPtr)(HWND, UINT, WPARAM, LPARAM);
myEditProcPtr = &MyControlGroup::myEditProc;
// Up to now it compiles ok, but then when I try to pass it to SetWindowLongPtr, I get
// an "invalid cast" error. Any ideas?
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProcPtr);
}
void MyControlGroup::onWMCommand(WPARAM wParam, LPARAM lParam){ /* process parent window messages. Editboxes don't generate WM_COMMAND or WM_KEYDOWN in the parent :''( */}
LRESULT MyControlGroup::myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// process messages like IDOK, WM_KEYDOWN and so on in the edit control
}
Even once I get this done, I'll still need to figure out a way to pass the address of the parent WndProc to myEditProc for the return value, but until I get past this there is no point in worrying about that.
Thanks in advance for reading!
myEditProc needs to be a static function.
Once you've done that you can pass the address of the function directly without going through the intermediate variable:
static LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
...
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProc);
To access your class data from the static function, you can save it in the userdata field of the edit control, e.g.:
// before sub-classing the control
SetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA, (LPARAM)this);
// in the sub-class procedure
MyControlGroup* pThis = (MyControlGroup*)GetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA);
But as #K-ballo suggested, SetWindowSubclass is definitely the way to do this unless you want compatibility with pre-XP. It handles the sub-classing procedure for you automatically, lets you associate a userdata pointer (e.g. this) that is automatically passed to the sub-class procedure, and safely handles removing the sub-class at the end.

attaching WNDPROC function from child class

I have a problem with attaching a windows procedure to a window.
I have a baseclass called BaseWindow, that uses GWPL_USERDATA to call a virtual function called HandleMessage() of the child classes.
However, if i try to change the window procedure without creating a custom Window Class, it gives a type error from the child procedure to long.
Here's the code:
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BaseWindow *pThis = NULL;
if (uMsg == WM_NCCREATE)
{
CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
pThis = (BaseWindow*)pCreate->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
pThis->m_hwnd = hwnd;
}
else
{
pThis = (BaseWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (pThis)
{
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{return 0;};
PlayList Class : BaseWindow
SetWindowLong(m_hwnd, GWL_WNDPROC,(long) HandleMessage); //Error
LRESULT PlayList::HandleMessage(UINT message,WPARAM wParam,LPARAM lParam) //Need to attach this window procedure
{}
It works if the child procedure is static, however I use non static members in that procedure.
I want to subclass a common control, while using this base class (because a lot of code is redundant), is it possible?
Here's the whole code for the base class: http://pastebin.com/ME8ks7XK
The compiler doesn't like your declaration for HandleMessage, it isn't static. It's missing CALLBACK too, not good.
Not sure why you are trying to do this, the whole point of your WindowProc() function is to get the message forwarded to a virtual HandleMessage() method. At best you'd use WindowProc in your SetWindowLong() call instead of HandleMesssage. Or just specify it directly in the CreateWindowEx() call.
From MSDN:
An application subclasses an instance of a window by using the SetWindowLong function. The application passes the GWL_WNDPROC flag, the handle to the window to subclass, and the address of the subclass procedure to SetWindowLong. The subclass procedure can reside in either the application's executable or a DLL.
So, you should write this:
SetWindowLong(m_hwnd, GWL_WNDPROC,(long) & HandleMessage);
But this doesn't compile again! the reason: all non-static member functions have hidden this parameter (pointer to owner class). So, you HandleMessage doesn't fit the WindowProc declaration.

sending lparam as a pointer to class, and use it in WndProc()

i have this abstract code :
i want to use lParam (last parameter) in CreateWindowEx() to save a pointer to a class thats declared in the begining of main - SaveArr. then, i want to use it in the function WndProc.
in the begining i did a global array, and then i could use it anywhere, but its not so "clever" as far as c++ concern, so im trying to upgrade it a bit.
class Samples
{
int arr[ITERATIONS+1];
int index;
...
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
Samples * SaveArr;
...
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
ClsName,
WindowCaption,
WS_OVERLAPPEDWINDOW,
INITIAL_WIN_LOCAT_X,
INITIAL_WIN_LOCAT_Y,
WIN_WIDTH,
WIN_HIGHT,
NULL,
NULL,
hInstance,
NULL); //here i want to pass SaveArr, so that i can use it in the WndProc(...) function
...
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
... //here i would like to use lParam as the class pointer, meaning using the
SaveArr declared in the main function.
}
}
Adding caller information to the window:
m_window = CreateWindow(..., this);
Similar for the extended CreateWindowEx.
Obtaining a pointer to the caller:
template< typename CallerT >
[[nodiscard]]
CallerT* WindowCaller(HWND window, UINT message, LPARAM lParam) noexcept
{
if (message == WM_NCCREATE) [[unlikely]]
{
const auto caller = reinterpret_cast< CallerT* >(
reinterpret_cast< CREATESTRUCT* >(lParam)->lpCreateParams);
// Change the user data of the window for subsequent messages.
::SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast< LONG_PTR >(caller));
return caller;
}
else
{
// Retrieve the user data of the window.
return reinterpret_cast< CallerT* >(
::GetWindowLongPtr(window, GWLP_USERDATA));
}
}
This method needs to be called in your message callback.
Best way would be
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
Samples *savearr = (Samples*)GetWindowLong(hWnd,GWL_USERDATA)
switch(Msg)
{
case WM_CREATE:
SetWindowLong(hWnd, GWL_USERDATA, (LONG)lParam);
break;
}
}
The next time the WndProc is called the value would be in savearr, and can be used.
From the reference:
lpParam [in, optional]
Type: LPVOID
Pointer to a value to be passed to the window through the
CREATESTRUCT structure (lpCreateParams member) pointed to by the
lParam param of the WM_CREATE message. This message is sent to the
created window by this function before it returns.
If an application calls CreateWindow to create a MDI client
window, lpParam should point to a CLIENTCREATESTRUCT structure. If an
MDI client window calls CreateWindow to create an MDI child window,
lpParam should point to a MDICREATESTRUCT structure. lpParam may be
NULL if no additional data is needed.
You're expecting the lParam to be always passed to WndProc, but it is only passed with WM_CREATE.
Note, that even then it's not passed directly, but rather through a structure which is the actual lParam for WM_CREATE.
Your only chance to read the lParam is during WM_CREATE. If you want to keep using the value later then you must store it somewhere. Maybe as a static of the WndProc or otherwise assign it to something else which is going to be scoped.
Why all the insistence on using that last, lpParam value set to X, then catching it on WM_CREATE (through all that indirect struct stuff, no less!) and then setting GWL_USERDATA?!
Why not cut to the chase and do this:
HWND H=CreateWindow(.....)
SetWindowLong(H,GWL_USERDATA,X)
In other words, just put X there directly, yourself, right after the window creation statement.
In my tests it works, and so long as you test the window handle against some list of known handles, you can prevent some errant message picked up by your program, and prevent inappropriate use of something else's userdata.

Is it possible to give a top-level function access to an object's members in C++?

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() {
...
}