C++ C++;WINAPI动态包装器类

C++ C++;WINAPI动态包装器类,c++,class,winapi,C++,Class,Winapi,首先,我想说,对于任何想说“我为什么要重新发明轮子”的人来说,我这样做是为了好玩,也是为了我目前正在从事的一个项目 从下面的代码中可以看出,我试图动态创建一个窗口和一个按钮,但我遇到的问题是在单击按钮时向该按钮添加一个函数 我知道在WM_COMMAND中进入窗口过程并在那里执行是非常简单的,但是这忽略了我在这里要完成的全部内容,所以我可以简单地调用btn。将(params)添加到某个窗口,并通过调用saybtn.单击(function)向该按钮添加某个函数;LRESULT\uU stdcall

首先,我想说,对于任何想说“我为什么要重新发明轮子”的人来说,我这样做是为了好玩,也是为了我目前正在从事的一个项目

从下面的代码中可以看出,我试图动态创建一个窗口和一个按钮,但我遇到的问题是在单击按钮时向该按钮添加一个函数

我知道在
WM_COMMAND
中进入窗口过程并在那里执行是非常简单的,但是这忽略了我在这里要完成的全部内容,所以我可以简单地调用
btn。将(params)
添加到某个窗口,并通过调用say
btn.单击(function)向该按钮添加某个函数;
我将如何做到这一点

#include <Windows.h>
#include <vector>
#include <thread>

using namespace std;

WNDCLASSEX defWndClass = { 0 };

class WinForm
{
private:
    HWND WindowHandle;
    std::thread Thread;
    std::vector<std::tuple<std::string, std::size_t, HWND>> ControlHandles;

public:
    ~WinForm();
    WinForm(std::string ClassName, std::string WindowName, bool Threaded = false, int Width = CW_USEDEFAULT,
        int Height = CW_USEDEFAULT, WNDPROC WindowProcedure = nullptr, WNDCLASSEX WndClass = defWndClass);
    bool AddButton(std::string ButtonName, POINT Location, int Width, int Height);
};

WinForm::~WinForm()
{
    if (Thread.joinable())
    {
        Thread.join();
    }
}

WinForm::WinForm(std::string ClassName, std::string WindowName, bool Threaded, int Width, int Height, WNDPROC WindowProcedure, WNDCLASSEX WndClass)
    :WindowHandle(nullptr)
{
    if (WindowProcedure == nullptr)
    {
        WindowProcedure = [](HWND window, UINT msg, WPARAM wp, LPARAM lp)->LRESULT __stdcall
        {
            switch (msg)
            {
                /*
                case WM_PAINT:
                    break;
                    */

            case WM_DESTROY:
                PostQuitMessage(0);
                return 0;

            case WM_CREATE:
                break;

            default:
                return DefWindowProc(window, msg, wp, lp);
            }
            return 0;
        };
    }

    if (WndClass.cbSize == 0)
    {
        WndClass.cbSize = sizeof(WNDCLASSEX);
        WndClass.style = CS_DBLCLKS;
        WndClass.lpfnWndProc = WindowProcedure;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance = GetModuleHandle(nullptr);
        WndClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
        WndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
        WndClass.lpszMenuName = nullptr;
        WndClass.lpszClassName = ClassName.c_str();
        WndClass.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
    }

    if (RegisterClassEx(&WndClass))
    {
        if (Threaded)
        {
            // can't do that!
        }
        else
        {
            WindowHandle = CreateWindowEx(0, ClassName.c_str(), WindowName.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
            if (WindowHandle)
            {
                ShowWindow(WindowHandle, SW_SHOWDEFAULT);

                // don't put message loop here!
            }
        }
    }
}

bool WinForm::AddButton(std::string ButtonName, POINT Location, int Width, int Height)
{
    for (std::vector<std::tuple<std::string, std::size_t, HWND>>::iterator it = ControlHandles.begin(); it != ControlHandles.end(); ++it)
    {
        auto& tu = *it;
        auto& str = std::get<0>(tu);
        if (ButtonName.compare(str) == 0) {
            return false;
        }
    }

    std::size_t ID = 1;
    for (std::vector<std::tuple<std::string, std::size_t, HWND>>::iterator it = ControlHandles.begin(); it != ControlHandles.end(); ++it, ++ID)
    {
        if (std::get<1>(*it) != ID)
        {
            break;
        }
    }

    HWND ButtonHandle = CreateWindowEx(
        0, "button", ButtonName.c_str(), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, Location.x, Location.y, Width, Height,
        WindowHandle, (HMENU)ID, (HINSTANCE)GetWindowLong(WindowHandle, GWL_HINSTANCE), nullptr);
    ShowWindow(ButtonHandle, SW_SHOW);
    ControlHandles.push_back(std::make_tuple(ButtonName, ID, ButtonHandle));

    //SendMessage(WindowHandle, WM_CREATE, 0, 0);
    return true;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    WinForm Form("Class", "Title", false);
    POINT pt = { 50, 50 };
    Form.AddButton("NewButton", pt, 80, 50);

    MSG msg = { nullptr };
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

}
#包括
#包括
#包括
使用名称空间std;
WndClass x defWndClass={0};
类WinForm
{
私人:
窗柄;
标准:螺纹;
矢量控制手柄;
公众:
~WinForm();
WinForm(std::string类名称,std::string窗口名称,bool Threaded=false,int Width=CW\u USEDEFAULT,
int Height=CW_USEDEFAULT,WNDPROC WindowProcedure=nullptr,WNDCLASSEX WndClass=defWndClass);
bool AddButton(标准::字符串按钮名称、点位置、整数宽度、整数高度);
};
WinForm::~WinForm()
{
if(Thread.joinable())
{
Thread.join();
}
}
WinForm::WinForm(标准::字符串类名称,标准::字符串窗口名称,布尔线程,int-Width,int-Height,WNDPROC WindowProcedure,WNDCLASSEX WndClass)
:WindowHandle(nullptr)
{
if(WindowProcedure==nullptr)
{
WindowProcedure=[](HWND窗口,UINT消息,WPARAM wp,LPARAM lp)->LRESULT\uU stdcall
{
开关(msg)
{
/*
案例WM_油漆:
打破
*/
案例WM_销毁:
PostQuitMessage(0);
返回0;
案例WM_创建:
打破
违约:
返回DefWindowProc(窗口、消息、wp、lp);
}
返回0;
};
}
如果(WndClass.cbSize==0)
{
WndClass.cbSize=sizeof(WNDCLASSEX);
WndClass.style=CS_DBLCLKS;
WndClass.lpfnWndProc=WindowProcedure;
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hInstance=GetModuleHandle(nullptr);
WndClass.hIcon=LoadIcon(nullptr,IDI_应用程序);
WndClass.hCursor=加载光标(nullptr,IDC_箭头);
WndClass.hbrBackground=HBRUSH(颜色窗口+1);
WndClass.lpszMenuName=nullptr;
WndClass.lpszClassName=ClassName.c_str();
WndClass.hIconSm=加载图标(nullptr,IDI_应用程序);
}
if(注册类(&WndClass))
{
如果(螺纹)
{
//不能那样做!
}
其他的
{
WindowHandle=CreateWindowEx(0,ClassName.c_str(),WindowName.c_str(),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,宽度,高度,nullptr,nullptr,GetModuleHandle(nullptr),nullptr);
if(窗口句柄)
{
ShowWindow(WindowHandle,SW_SHOWDEFAULT);
//不要把信息循环放在这里!
}
}
}
}
bool WinForm::AddButton(标准::字符串按钮名称、点位置、整型宽度、整型高度)
{
对于(std::vector::iterator it=ControlHandles.begin();it!=ControlHandles.end();++it)
{
自动&tu=*it;
auto&str=std::get(tu);
if(ButtonName.compare(str)==0){
返回false;
}
}
std::size\u t ID=1;
对于(std::vector::iterator it=ControlHandles.begin();it!=ControlHandles.end();++it,++ID)
{
if(std::get(*it)!=ID)
{
打破
}
}
HWND ButtonHandle=CreateWindowEx(
0,“按钮”,按钮名.c_str(),WS|u CHILD | WS|u VISIBLE | BS|u按钮,位置.x,位置.y,宽度,高度,
WindowHandle,(humenu)ID,(HINSTANCE)GetWindowLong(WindowHandle,GWL_HINSTANCE),nullptr);
显示窗口(按钮手柄、开关显示);
ControlHandles.push_back(std::make_tuple(ButtonName、ID、ButtonHandle));
//SendMessage(WindowHandle,WM_CREATE,0,0);
返回true;
}
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
WinForm表格(“类别”、“标题”,假);
点pt={50,50};
表格.添加按钮(“新按钮”,pt,80,50);
MSG MSG={nullptr};
while(GetMessage(&msg,nullptr,0,0))
{
翻译信息(&msg);
发送消息(&msg);
}
}

单击按钮时,按钮的父窗口将通过
WM_命令
接收通知。如果父窗口不处理该消息,它将转到
DefWindowProc()
,并被忽略。因此,父窗口需要处理
WM_命令
。单击通知代码时,只需在按钮列表中查找提供的按钮,如果找到,则调用相应的功能(如果已分配)

#include <Windows.h>
#include <vector>
#include <thread>
#include <algorithm>
#include <functional>

class WinForm
{
public:
    using ControlActionFunc = std::function<void(const std::string &)>;

    WinForm(std::string ClassName, std::string WindowName, bool Threaded = false, int Width = CW_USEDEFAULT, int Height = CW_USEDEFAULT);

    ~WinForm();

    bool AddButton(const std::string &ButtonName, POINT Location, int Width, int Height, ControlActionFunc OnClick);

private:
    HWND WindowHandle;
    std::thread Thread;

    using ControlInfo = std::tuple<std::string, std::size_t, HWND, ControlActionFunc>;
    using ControlInfoVector = std::vector<ControlInfo>;
    ControlInfoVector Controls;

    static LRESULT __stdcall StaticWindowProcedure(HWND window, UINT msg, WPARAM wp, LPARAM lp);

protected:
    virtual LRESULT WindowProcedure(UINT msg, WPARAM wp, LPARAM lp);
};

class MainAppWinForm : public WInForm
{
public:
    using WinForm::WinForm;

protected:
    LRESULT WindowProcedure(UINT msg, WPARAM wp, LPARAM lp) override;
};

WinForm::WinForm(std::string ClassName, std::string WindowName, bool Threaded, int Width, int Height)
    : WindowHandle(nullptr)
{
    HINSTANCE hInstance = GetModuleHandle(nullptr);
    WNDCLASSEX WndClass = {};

    bool isRegistered = GetClassInfoEx(hInstance, ClassName.c_str(), &WndClass);
    if ((!isRegistered) || (WndClass.lpfnWndProc != &WinForm::StaticWindowProcedure))
    {
        if (isRegistered)
            UnregisterClass(ClassName.c_str(), hInstance);

        WndClass.cbSize = sizeof(WNDCLASSEX);
        WndClass.style = CS_DBLCLKS;
        WndClass.lpfnWndProc = &WinForm::StaticWindowProcedure;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra = sizeof(WinForm*);
        WndClass.hInstance = hInstance;
        WndClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
        WndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
        WndClass.lpszMenuName = nullptr;
        WndClass.lpszClassName = ClassName.c_str();
        WndClass.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);

        if (!RegisterClassEx(&WndClass))
            return;
    }

    if (Threaded)
    {
        // can't do that!
        return;
    }

    WindowHandle = CreateWindowEx(0, ClassName.c_str(), WindowName.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, nullptr, nullptr, hInstance, this);
    if (!WindowHandle)
        return;

    ShowWindow(WindowHandle, SW_SHOWDEFAULT);

    // don't put message loop here!
}

WinForm::~WinForm()
{
    if (Thread.joinable())
    {
        Thread.join();
    }
}

LRESULT __stdcall WinForm::StaticWindowProcedure(HWND window, UINT msg, WPARAM wp, LPARAM lp)
{
    WinForm *This;
    if (msg == WM_NCCREATE)
    {
        This = static_cast<WinForm*>(reinterpret_cast<CREATESTRUCT*>(lp)->lpCreateParams);
        This->WindowHandle = window;
        SetWindowLongPtr(window, 0, reinterpret_cast<LONG_PTR>(This));
    }
    else
        This = reinterpret_cast<WinForm*>(GetWindowLongPtr(window, 0));

    if (This)
        return This->WindowProcedure(msg, wp, lp);

    return DefWindowProc(window, msg, wp, lp);
}

LRESULT WinForm::WindowProcedure(UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg)
    {
        /*
        case WM_PAINT:
            break;
        */

        case WM_COMMAND:
        {
            if (lp != 0)
            {
                if (HIWORD(wp) == BN_CLICKED)
                {
                    HWND ControlWindow = reinterpret_cast<HWND>(lp);

                    auto it = std::find_if(Controls.begin(), Controls.end(),
                        [](ControlInfo &info){ return (std::get<2>(info) == ControlWindow); }
                    );

                    if (it != Controls.end())
                    {
                        auto &tu = *it;
                        auto actionFunc = std::get<3>(tu);
                        if (actionFunc) actionFunc(std::get<0>(tu));
                        return 0;
                    }
                }
            }
            break;
        }

        case WM_CREATE:
            break;
    }

    return DefWindowProc(WindowHandle, msg, wp, lp);
}

bool WinForm::AddButton(const std::string &ButtonName, POINT Location, int Width, int Height, ControlActionFunc OnClick)
{
    auto it = std::find_if(Controls.begin(), Controls.end(),
        [&](ControlInfo &info){ return (std::get<0>(info).compare(ButtonName) == 0); }
    );

    if (it != Controls.end()) {
        return false;
    }

    std::size_t ID = 1;
    auto matchesID = [&](ControlInfo &info){ return (std::get<1>(tu) == ID); };
    while (std::find_if(Controls.begin(), Controls.end(), matchesID) != Controls.end()) {
        ++ID;
    }

    HWND ButtonHandle = CreateWindowEx(
        0, "button", ButtonName.c_str(), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, Location.x, Location.y, Width, Height,
        WindowHandle, (HMENU)ID, (HINSTANCE)GetWindowLong(WindowHandle, GWL_HINSTANCE), nullptr);
    if (!ButtonHandle)
        return false;

    Controls.push_back(std::make_tuple(ButtonName, ID, ButtonHandle, std::move(OnClick)));
    return true;
}

LRESULT MainAppWinForm::WindowProcedure(UINT msg, WPARAM wp, LPARAM lp)
{
    if (msg == WM_DESTROY)
    {
        PostQuitMessage(0);
        return 0;
    }
    return WinForm::WindowProcedure(msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    MainAppWinForm Form("Class", "Title", false);

    POINT pt = { 50, 50 };
    Form.AddButton("NewButton", pt, 80, 50,
        [](const std::string &ButtonName){ MessageBox(NULL, ButtonName.c_str(), "button clicked", MB_OK); }
    );

    MSG msg = { nullptr };
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
#包括
#包括
#包括
#包括


单击按钮时,按钮的父窗口将通过
WM_命令
接收通知。如果父窗口不处理该消息,它将转到
DefWindowProc()
,并被忽略。因此,父窗口需要处理
WM_命令
。单击通知代码时,只需在按钮列表中查找提供的按钮,如果找到,则调用相应的功能(如果已分配)

#include <Windows.h>
#include <vector>
#include <thread>
#include <algorithm>
#include <functional>

class WinForm
{
public:
    using ControlActionFunc = std::function<void(const std::string &)>;

    WinForm(std::string ClassName, std::string WindowName, bool Threaded = false, int Width = CW_USEDEFAULT, int Height = CW_USEDEFAULT);

    ~WinForm();

    bool AddButton(const std::string &ButtonName, POINT Location, int Width, int Height, ControlActionFunc OnClick);

private:
    HWND WindowHandle;
    std::thread Thread;

    using ControlInfo = std::tuple<std::string, std::size_t, HWND, ControlActionFunc>;
    using ControlInfoVector = std::vector<ControlInfo>;
    ControlInfoVector Controls;

    static LRESULT __stdcall StaticWindowProcedure(HWND window, UINT msg, WPARAM wp, LPARAM lp);

protected:
    virtual LRESULT WindowProcedure(UINT msg, WPARAM wp, LPARAM lp);
};

class MainAppWinForm : public WInForm
{
public:
    using WinForm::WinForm;

protected:
    LRESULT WindowProcedure(UINT msg, WPARAM wp, LPARAM lp) override;
};

WinForm::WinForm(std::string ClassName, std::string WindowName, bool Threaded, int Width, int Height)
    : WindowHandle(nullptr)
{
    HINSTANCE hInstance = GetModuleHandle(nullptr);
    WNDCLASSEX WndClass = {};

    bool isRegistered = GetClassInfoEx(hInstance, ClassName.c_str(), &WndClass);
    if ((!isRegistered) || (WndClass.lpfnWndProc != &WinForm::StaticWindowProcedure))
    {
        if (isRegistered)
            UnregisterClass(ClassName.c_str(), hInstance);

        WndClass.cbSize = sizeof(WNDCLASSEX);
        WndClass.style = CS_DBLCLKS;
        WndClass.lpfnWndProc = &WinForm::StaticWindowProcedure;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra = sizeof(WinForm*);
        WndClass.hInstance = hInstance;
        WndClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
        WndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
        WndClass.lpszMenuName = nullptr;
        WndClass.lpszClassName = ClassName.c_str();
        WndClass.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);

        if (!RegisterClassEx(&WndClass))
            return;
    }

    if (Threaded)
    {
        // can't do that!
        return;
    }

    WindowHandle = CreateWindowEx(0, ClassName.c_str(), WindowName.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, nullptr, nullptr, hInstance, this);
    if (!WindowHandle)
        return;

    ShowWindow(WindowHandle, SW_SHOWDEFAULT);

    // don't put message loop here!
}

WinForm::~WinForm()
{
    if (Thread.joinable())
    {
        Thread.join();
    }
}

LRESULT __stdcall WinForm::StaticWindowProcedure(HWND window, UINT msg, WPARAM wp, LPARAM lp)
{
    WinForm *This;
    if (msg == WM_NCCREATE)
    {
        This = static_cast<WinForm*>(reinterpret_cast<CREATESTRUCT*>(lp)->lpCreateParams);
        This->WindowHandle = window;
        SetWindowLongPtr(window, 0, reinterpret_cast<LONG_PTR>(This));
    }
    else
        This = reinterpret_cast<WinForm*>(GetWindowLongPtr(window, 0));

    if (This)
        return This->WindowProcedure(msg, wp, lp);

    return DefWindowProc(window, msg, wp, lp);
}

LRESULT WinForm::WindowProcedure(UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg)
    {
        /*
        case WM_PAINT:
            break;
        */

        case WM_COMMAND:
        {
            if (lp != 0)
            {
                if (HIWORD(wp) == BN_CLICKED)
                {
                    HWND ControlWindow = reinterpret_cast<HWND>(lp);

                    auto it = std::find_if(Controls.begin(), Controls.end(),
                        [](ControlInfo &info){ return (std::get<2>(info) == ControlWindow); }
                    );

                    if (it != Controls.end())
                    {
                        auto &tu = *it;
                        auto actionFunc = std::get<3>(tu);
                        if (actionFunc) actionFunc(std::get<0>(tu));
                        return 0;
                    }
                }
            }
            break;
        }

        case WM_CREATE:
            break;
    }

    return DefWindowProc(WindowHandle, msg, wp, lp);
}

bool WinForm::AddButton(const std::string &ButtonName, POINT Location, int Width, int Height, ControlActionFunc OnClick)
{
    auto it = std::find_if(Controls.begin(), Controls.end(),
        [&](ControlInfo &info){ return (std::get<0>(info).compare(ButtonName) == 0); }
    );

    if (it != Controls.end()) {
        return false;
    }

    std::size_t ID = 1;
    auto matchesID = [&](ControlInfo &info){ return (std::get<1>(tu) == ID); };
    while (std::find_if(Controls.begin(), Controls.end(), matchesID) != Controls.end()) {
        ++ID;
    }

    HWND ButtonHandle = CreateWindowEx(
        0, "button", ButtonName.c_str(), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, Location.x, Location.y, Width, Height,
        WindowHandle, (HMENU)ID, (HINSTANCE)GetWindowLong(WindowHandle, GWL_HINSTANCE), nullptr);
    if (!ButtonHandle)
        return false;

    Controls.push_back(std::make_tuple(ButtonName, ID, ButtonHandle, std::move(OnClick)));
    return true;
}

LRESULT MainAppWinForm::WindowProcedure(UINT msg, WPARAM wp, LPARAM lp)
{
    if (msg == WM_DESTROY)
    {
        PostQuitMessage(0);
        return 0;
    }
    return WinForm::WindowProcedure(msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    MainAppWinForm Form("Class", "Title", false);

    POINT pt = { 50, 50 };
    Form.AddButton("NewButton", pt, 80, 50,
        [](const std::string &ButtonName){ MessageBox(NULL, ButtonName.c_str(), "button clicked", MB_OK); }
    );

    MSG msg = { nullptr };
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
#包括
#包括
#包括
#包括


一种方法是让窗口程序查阅从按钮到功能的映射。添加按钮时,将一个条目添加到