tags:

views:

83

answers:

4

I want to create my own class to handle creating windows and the window procedure but I have noticed that the window procedure has to be static! I'm now wondering whether its possible to make the window procedure object oriented? I have read some tutorials on object oriented windows, but they always make the procedure static -.- whats the use in that? :/

Any links or info on how to get around this problem would be appreciated,

thanks

+1  A: 

If you are looking for object oriented Win32 API then you should look to MFC and/or WTL.

Brian R. Bondy
Overkill solutions for many purposes. MFC may be *relatively* thin, but it's still a large API in its own right, and switching from one API to another is a lot of work. It's also completely unnecessary if all you want to do is use a few C++ classes of your own while coding for Win32. My own old "object framework" for Win32 was probably about 2 or 3 sides of code - little more than a base class, some initialisation and a main GetMessage/etc loop.
Steve314
Matter of opinion
Brian R. Bondy
MFC is a nasty framework, but it's well supported and relatively well known in the Win32 world.
seand
A: 

You can use the window handle passed to the WindowProc to grab an object you've created for that particular window and delegate the event handling to that object.

e.g.

IMyWindowInterface* pWnd = getMyWindowObject(hWnd);
pWnd->ProcessMessage(uMsg, wParam, lParam);
Will A
Sounds good, i noticed that the only unique thing in the procedure is the handle, but wasn't sure how to find my window through it. like in your example, the getMyWindowObject(hwnd), would that function consist of iterating through my open windows to see if the handle matches? because if so, if i was handling a WM_MOUSEMOVE or WM_TIMER, wouldn't that be tedious on the processor?
Your best bet it to use some form of hashtable to hash from HWND to pointers-to-your-window-object - that was the lookups are quick. Unless you've a pretty large number of windows open, I would expect a loop through all (HWND,object*) pairs would be quick enough tho'.
Will A
+5  A: 

You can get around that by making the static WndProc delegate everything to the members:

// Forward declarations
class MyWindowClass;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

std::map<HWND, MyWindowClass *> windowMap;

// Your class
class MyWindowClass  {
private:
  HWND m_handle;

  // The member WndProc
  LRESULT MyWndProc(UINT message, WPARAM wParam, LPARAM lParam) { /* ... */ }

public:
  MyWindowClass()
  {
    /* TODO: Create the window here and assign its handle to m_handle */
    /* Pass &WndProc as the pointer to the Window procedure */

    // Register the window
    windowMap[m_handle] = this;
  }
};

// The delegating WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  std::map<HWND, MyWindowClass *>::iterator it = windowMap.find(hWnd);
  if (it != windowMap.end())
    return it->second->MyWndProc(message, wParam, lParam);
  return 0;
}
dark_charlie
+1, but you might also want to check for WM_DESTROY there and remove the handle from the map.
SoapBox
nice example, looks cool. I will try to implement it in my own, nice use of std::map to find the matching handle
@SoapBox It is incomplete in many ways, thanks for noting this one though.
dark_charlie
@dark_charlie: +1 for having a dictionary of HWND to MyWindowClass. I've seen methods before where people store pointers inside win32 structures, cast it, and dereference it directly. That's an extremely easy way to make your program vulnerable to hacks.
Merlyn Morgan-Graham
+2  A: 

The general technique of allowing a window instance to be represented by as class instance is to make use of the SetWindowLongPtr and GetWindowLongPtr to associate your class instance pointer with the window handle. Below is some sample code to get you started. It may not compile without a few tweaks. It's only meant to be a reference.

Personally, I've stopped rolling my own window classes back a few years ago when I discovered ATL's CWindow and CWindowImpl template class. They take care of doing all this mundane coding for you so can focus on just writing methods that handle window messages. See the example code I wrote up here.

Hope this helps.

class CYourWindowClass
{
private:
    HWND m_hwnd;

public:
    LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
            case WM_CREATE: return OnCreate(wParam, lParam);
            case wM_PAINT: return OnPaint(wParam, lParam);
            case WM_DESTROY:
            {
                SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL);
                m_hwnd = NULL;
                return 0;
            }
        }
        return DefWindowProc(m_hwnd, uMsg, wParam, lParam);

    }

    CYourWindowClass()
    {
        m_hwnd = NULL;
    }

    ~CYourWindowClass()
    {
        ASSERT(m_hwnd == NULL && "You forgot to destroy your window!");
        if (m_hwnd)
        {
            SetWindowLong(m_hwnd, GWLP_USERDATA, 0);
        }
    }

    bool Create(...) // add whatever parameters you want
    {
        HWND hwnd = CreateWindow("Your Window Class Name", "Your Window title", dwStyle, x, y, width, height, NULL, hMenu, g_hInstance, (LPARAM)this);
        if (hwnd == NULL)
            return false;

        ASSERT(m_hwnd == hwnd);
        return true;
    }


    static LRESULT __stdcall StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        CYourWindowClass* pWindow = (CYourWindowClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

        if (uMsg == WM_CREATE)
        {
            pWindow = ((CREATESTRUCT*)lParam)->lpCreateParams;
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (void*)pWindow);
            m_hWnd = hwnd;
        }

        if (pWindow != NULL)
        {
            return pWindow->WndProc(uMsg, wParam, lParam);
        }

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


};
selbie
Always wondered what the lpParam was for on the CreateWindowEx function, but i support this could be the way that makes it vulnerable, as somebody could use GetWindowLong to get your user data :P