说明
为了代码看起来清爽一点,将上篇文章中的代码进行封装,抽象为一个类。
这篇的核心是
HWND hWnd = CreateWindow(WindowClass::GetInstance().get()->GetName(), // 创建的窗口类名
TEXT("First Window"), // 窗口名称
WS_OVERLAPPEDWINDOW, // 窗口类型
200, 200, // 窗口起始位置
400, 300, // 窗口宽高
NULL, // 父窗口句柄
NULL, // 菜单句柄
WindowClass::GetInstance()->GetHInstance(), // 要与该窗口关联的模块实例的句柄
this // 更 WM_CREATE 消息,通过 lparam 传入回调函数的数据
);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG>(pWnd)); // 将 this 指针保存在 GWLP_USERDATA
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG>(HandleMsgThunk)); // 将回调函数设置为 HandleMsgThunk
将 this 指针通过 CreateWindow 最后一个参数传入窗口的回调函数,然后将该指针保存到 GWLP_USERDATA 位置,实现将回调信息传到类的非静态成员函数中,方便后面的信息处理。
具体代码
#pragma once
#include <windows.h>
#include <string>
#include <mutex>
#include <memory>
class Window
{
public:
Window();
~Window();
Window(Window&) = delete;
Window& operator=(const Window&) = delete;
static LRESULT CALLBACK HandleMsgSetup(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK HandleMsgThunk(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LRESULT HandleMsg(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
public:
class WindowClass
{
typedef std::shared_ptr<WindowClass> Ptr;
public:
~WindowClass();
WindowClass(WindowClass&) = delete;
WindowClass& operator=(const WindowClass&) = delete;
static Ptr GetInstance();
const char* GetName();
const HINSTANCE GetHInstance();
private:
WindowClass();
private:
static Ptr m_instance;
static std::mutex m_mutex;
const HINSTANCE m_hInst;
const std::string m_className;
};
};
#include "window.h"
Window::WindowClass::Ptr Window::WindowClass::m_instance = nullptr;
std::mutex Window::WindowClass::m_mutex;
Window::WindowClass::~WindowClass()
{
}
Window::WindowClass::Ptr Window::WindowClass::GetInstance()
{
if (m_instance == nullptr)
{
std::lock_guard<std::mutex> autolock(m_mutex);
if (m_instance == nullptr)
{
m_instance = std::shared_ptr<WindowClass>(new WindowClass);
}
}
return m_instance;
}
const char* Window::WindowClass::GetName()
{
return m_className.c_str();
}
const HINSTANCE Window::WindowClass::GetHInstance()
{
return m_hInst;
}
Window::WindowClass::WindowClass()
:m_hInst(GetModuleHandle(NULL)),
m_className("0_51WindowClass")
{
WNDCLASS wc;
ZeroMemory(&wc, sizeof(wc));
wc.style = 0; // 窗口类型?
wc.lpfnWndProc = HandleMsgSetup; // 回调函数
wc.cbClsExtra = 0; // 类分配的额外字节数
wc.cbWndExtra = 0; // 窗口分配的额外字节数
wc.hInstance = m_hInst; // 包含类的窗口过程的实例的句柄 ?
wc.hIcon = LoadIcon(NULL, IDI_INFORMATION); // 窗口图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 光标形状
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 设置背景颜色
wc.lpszMenuName = TEXT("窗口 menu"); // 菜单名字
wc.lpszClassName = m_className.c_str(); // 窗口类名 创建窗口时设置该名字,来引用该属性
RegisterClass(&wc);
}
Window::Window()
{
HWND hWnd = CreateWindow(WindowClass::GetInstance().get()->GetName(), // 创建的窗口类名
TEXT("First Window"), // 窗口名称
WS_OVERLAPPEDWINDOW, // 窗口类型
200, 200, // 窗口起始位置
400, 300, // 窗口宽高
NULL, // 父窗口句柄
NULL, // 菜单句柄
WindowClass::GetInstance()->GetHInstance(), // 要与该窗口关联的模块实例的句柄
this // 更 WM_CREATE 消息,通过 lparam 传入回调函数的数据
);
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
}
LRESULT CALLBACK Window::HandleMsgSetup(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (msg == WM_CREATE)
{
const CREATESTRUCT* const pCreate = reinterpret_cast<CREATESTRUCT*>(lparam);
Window* const pWnd = static_cast<Window*>(pCreate->lpCreateParams);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG>(pWnd)); // 将 this 指针保存在 GWLP_USERDATA
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG>(HandleMsgThunk)); // 将回调函数设置为 HandleMsgThunk
return pWnd->HandleMsg(hwnd, msg, wparam, lparam);
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT CALLBACK Window::HandleMsgThunk(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
LONG param = GetWindowLongPtr(hwnd, GWLP_USERDATA);
Window* const pWnd = reinterpret_cast<Window*>(param);
return pWnd->HandleMsg(hwnd, msg, wparam, lparam);
}
LRESULT Window::HandleMsg(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
Window::~Window()
{
}