Skip to content

Instantly share code, notes, and snippets.

@VioletGiraffe
Forked from cos-public/main.cpp
Last active May 2, 2023 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VioletGiraffe/24256ea2973296d3a055437fc891403d to your computer and use it in GitHub Desktop.
Save VioletGiraffe/24256ea2973296d3a055437fc891403d to your computer and use it in GitHub Desktop.
classic win32 app with raii style window
#include <Windows.h>
#include <assert.h>
#include <cstdint>
#include <memory>
class main_window;
template <class WndT, class ParamsTuple>
LRESULT CALLBACK main_window_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_CREATE) {
::OutputDebugStringW(L"WM_CREATE\n");
auto cp = reinterpret_cast<LPCREATESTRUCTW>(lParam);
auto* args_tuple = reinterpret_cast<ParamsTuple*>(cp->lpCreateParams); /// last parameter passed to ::CreateWindow()
WndT* wnd = std::apply([&wnd, hWnd](auto&&... args) {
return new WndT(hWnd, std::forward<decltype(args)>(args)...);
}, std::move(*args_tuple));;
::SetLastError(0);
::SetWindowLongPtrW(hWnd, 0, reinterpret_cast<LONG_PTR>(wnd));
assert(::GetLastError() == 0);
}
if (message == WM_DESTROY) {
::OutputDebugStringW(L"WM_DESTROY\n");
auto* wnd = reinterpret_cast<WndT*>(::GetWindowLongPtrW(hWnd, 0));
assert(wnd != nullptr);
delete wnd;
}
/// DefWindowProcW calls DestroyWindow(), which sends WM_DESTROY by default
return ::DefWindowProcW(hWnd, message, wParam, lParam);
}
class main_window {
public:
using ParamsTuple = std::tuple<std::unique_ptr<int>&&, float, double&>;
friend LRESULT CALLBACK main_window_proc<main_window, ParamsTuple>(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
protected:
~main_window() {
::OutputDebugStringW(L"main_window::~main_window()\n");
::PostQuitMessage(EXIT_SUCCESS);
}
main_window(HWND hWnd, std::unique_ptr<int> p1, const float& p2, double& p3) {
p3 = 1.1111;
::OutputDebugStringW(L"main_window::main_window()\n");
}
main_window(const main_window&) = delete;
main_window(main_window&&) = delete;
LRESULT wnd_proc(UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_PAINT) {
::OutputDebugStringW(L"WM_PAINT\n");
}
}
};
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) try {
static const WNDCLASSEXW wnd_class {
.cbSize = sizeof(WNDCLASSEXW),
.style = CS_HREDRAW | CS_VREDRAW,
.lpfnWndProc = &main_window_proc<main_window, main_window::ParamsTuple>,
.cbClsExtra = 0,
.cbWndExtra = sizeof(std::uintptr_t),
.hInstance = ::GetModuleHandle(NULL),
.hIcon = NULL,
.hCursor = ::LoadCursorW(NULL, IDC_ARROW),
.hbrBackground = NULL,
.lpszMenuName = NULL,
.lpszClassName = L"main_window",
.hIconSm = NULL
};
static_assert(sizeof(main_window*) == sizeof(LONG_PTR));
const ATOM cls = ::RegisterClassExW(&wnd_class);
/// pass these parameters to main_window_proc
auto p1 = std::make_unique<int>(42);
float p2 = 3.14f;
double p3 = 2.71828;
main_window::ParamsTuple args_tuple{ std::move(p1), p2, p3 };
HWND hWnd = ::CreateWindowEx(0, MAKEINTRESOURCEW(cls), L"Main Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, &args_tuple);
MSG msg;
BOOL bRet;
while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
catch (...) {
return -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment