Subclass a button within a custom class using SetW

2019-09-12 16:12发布

This question already has an answer here:

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.

1条回答
爷的心禁止访问
2楼-- · 2019-09-12 17:05

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;
    }
    
查看更多
登录 后发表回答