1

I am attempting to write a class to handle the creation of a button and it's messages internally. I wish to keep all of the code contained within the class itself. This may be simple or impossible as I am relatively new to Winapi and C++, having used vb.net much more extensively. I was unable to find an example that accomplished this seeming simple conversion. I did find examples suggesting i use an alternate API, or use SetWindowLongPtr, I am told that SetWindowSubclass is the better option. My attempted code is below:

#pragma once
#include <iostream>
#include <Windows.h>
#include <Commctrl.h>

using namespace std;

    class button {
    public:
        bool initialize();
        buttton(int x, int y, int length, int width, LPCWSTR text, HWND parent, HINSTANCE hInstance);  // This is the constructor

    private:
        LPCWSTR text = L"Button";
        int height = 25;
        int width = 100;
        int x = 0;
        int y = 0;
        HWND parent;
        HWND thisHandle;
        HINSTANCE thisInstance;
        bool initialized = false;
        LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

    };


    button::button(int x, int y, int height, int width, LPCWSTR text, HWND parent, HINSTANCE hInstance) {
        this->x = x;
        this->y = y;
        this->height = height;
        this->width = width;
        this->text = text;
        this->parent = parent;
        thisInstance = hInstance;
    }
        bool button::initialize()
    {
        thisHandle = CreateWindowW(
            L"BUTTON",  // Predefined class; Unicode assumed 
            text,      // Button text 
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS | BS_NOTIFY,  // Styles 
            x,         // x position 
            y,         // y position 
            width,        // Button width
            height,        // Button height
            parent,     // Parent window
            NULL,       // No ID.
            thisInstance,
            NULL);      // Pointer not needed.
        if (!thisHandle)
        {
            return false;
        }
        initialized = true;
        //Problem Code****
        SetWindowSubclass(thisHandle, mySubClassProc, 1, 0);
        //****  
        return true;
    }

    LRESULT CALLBACK button::mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {

        //Code handling messages here.
    }
}

This throws the error :

argument of type "LRESULT (__stdcall button::*)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)" is incompatible with parameter of type "SUBCLASSPROC"

I am hoping that someone can explain a simple solution, or suggest an alternative in Winapi, as i wish to learn native windows and C++ and not rely on additional libraries.

James Hays
  • 13
  • 4
  • 1
    You still have a *lot* to learn about the differences between C and C++, subclassing is also not nearly enough to do this properly. Do avoid re-inventing this wheel, there are many excellent C++ wrappers for the winapi. Pick from, say, MFC, Qt, wxwidgets. If you don't want to use them then at least look at what they do. – Hans Passant Nov 26 '16 at 22:00
  • 1
    Declare your subclass procedure as `static`... – AlwaysLearningNewStuff Nov 26 '16 at 22:21
  • 2
    @Hans Passant: I do have a lot to learn. This particular code isn't intended to be used in a finished product but instead was attempting to explore possibilities. While "Re-inventing the wheel" seems pointless, I don't think that using the mentioned wrappers will give me a better understanding of the inner workings of Winapi. If subclassing isn't enough to do this properly can you suggest what I should be studying to accomplish something like this in native Winapi? Additionally, I will look into the suggested wrappers. – James Hays Nov 28 '16 at 03:39

1 Answers1

5

You are trying to use a non-static class method as the subclass callback. That will not work, because a non-static class method has a hidden this parameter that the API will not be able to pass.

To do what you are attempting, you must remove the this parameter (you can use the dwRefData parameter of SetWindowSubclass() instead), by either:

  1. using a static class method:

    class button {
    public:
        bool initialize();
        ...
    
    private:
        ...
    
        static LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
    
    };
    
    bool button::initialize()
    {
        ...
        SetWindowSubclass(thisHandle, mySubClassProc, 1, (DWORD_PTR) this);
        return true;
    }
    
    LRESULT CALLBACK button::mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        button *pThis = (button*) dwRefData;
    
        //Code handling messages here.
    }
    
  2. using a non-member function:

    class button {
    public:
        bool initialize();
        ...
    };
    
    LRESULT CALLBACK myButtonSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        button *pBtn = (button*) dwRefData;
        //Code handling messages here.
    }
    
    bool button::initialize()
    {
        ...
        SetWindowSubclass(thisHandle, myButtonSubClassProc, 1, (DWORD_PTR) this);
        return true;
    }
    
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770