Reputation: 1
Hello I have recently decided to learn graphics programming through DirectX11 and for that I'm learning how to use the Windows API. I managed to create a window by following an online tutorial and later successfully created one by myself. However, the problem starts when I tried to make a framework to create the Window, I ran into a few errors but by studying the documentation and looking up examples most of them were solved, except for one involving the CreateWindow() function.
Whenever I try to get the handle for the window it returns nullptr, I tried getting the error code through GetLastError(), but all I get is 1400, which according to MSDN is "Invalid window handle". I don't know what I'm doing wrong and I haven't found any threads that solved the issue. It compiles successfully, but no window appears.
Window.hpp
#pragma once
#include "WindowsHeader.hpp"
class Window
{
public:
Window(int width, int height, const char* name);
~Window();
Window(const Window&) = delete;
Window& operator=(const Window&) = delete;
private:
class WindowClass
{
public:
static const char* GetName() noexcept;
static HINSTANCE GetInstance() noexcept;
private:
WindowClass() noexcept;
~WindowClass();
WindowClass(const WindowClass&) = delete;
WindowClass& operator=(const WindowClass&) = delete;
static constexpr const char* window_class_name{ "HardwareAccelerated3D" };
static WindowClass window_class;
HINSTANCE hinst;
};
static LRESULT CALLBACK HandleMsgSetup(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept;
static LRESULT CALLBACK HandleMsgInvoke(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept;
LRESULT HandleMsg(HWND, UINT msg, WPARAM wparam, LPARAM lparam) noexcept;
int width;
int height;
HWND hwnd;
};
Window.cpp
#include "Window.hpp"
#include <sstream>
//Window Class
Window::WindowClass Window::WindowClass::window_class;
Window::WindowClass::WindowClass() noexcept
: hinst(GetModuleHandle(NULL))
{
WNDCLASSEX window_class{ {0} };
window_class.cbSize = sizeof(window_class);
window_class.style = CS_OWNDC;
window_class.lpfnWndProc = &HandleMsgSetup;
window_class.cbClsExtra = NULL;
window_class.cbWndExtra = NULL;
window_class.hInstance = GetInstance();
window_class.hIcon = NULL;
window_class.hCursor = NULL;
window_class.hbrBackground = NULL;
window_class.lpszMenuName = NULL;
window_class.lpszClassName = GetName();
window_class.hIconSm = NULL;
RegisterClassEx(&window_class);
}
Window::WindowClass::~WindowClass()
{
UnregisterClass(GetName(), GetInstance());
}
const char* Window::WindowClass::GetName() noexcept
{
return window_class_name;
}
HINSTANCE Window::WindowClass::GetInstance() noexcept
{
return window_class.hinst;
}
//Window
Window::Window(int width, int height, const char* name)
: width(width), height(height)
{
RECT wndrec;
wndrec.left = 100;
wndrec.right = wndrec.left + width;
wndrec.top = 100;
wndrec.bottom = wndrec.top + height;
if (!AdjustWindowRect(&wndrec, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, false))
{
std::ostringstream oss;
oss << GetLastError();
OutputDebugString(oss.str().c_str());
}
hwnd = CreateWindow(WindowClass::GetName(), name, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, wndrec.right - wndrec.left, wndrec.bottom - wndrec.top, NULL,
NULL, WindowClass::GetInstance(), this);
if (!hwnd)
{
std::ostringstream oss;
oss << GetLastError();
OutputDebugString(oss.str().c_str());
}
ShowWindow(hwnd, SW_SHOWDEFAULT);
}
Window::~Window()
{
DestroyWindow(hwnd);
}
LRESULT WINAPI Window::HandleMsgSetup(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
if (msg == WM_NCCREATE)
{
const CREATESTRUCTW* const pcreate = reinterpret_cast<CREATESTRUCTW*>(lparam);
Window* const pwnd = static_cast<Window*>(pcreate->lpCreateParams);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pwnd));
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgInvoke));
return pwnd->HandleMsg(hwnd, msg, wparam, lparam);
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT WINAPI Window::HandleMsgInvoke(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
Window* const pwnd = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
return pwnd->HandleMsg(hwnd, msg, wparam, lparam);
}
LRESULT Window::HandleMsg(HWND, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
WinMain.cpp
#include "WindowsMessageMap.hpp"
#include "Window.hpp"
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
Window window(640, 480, "HardwareAccelerated3D");
MSG msg;
BOOL gresult;
while (gresult = GetMessage(&msg, NULL, NULL, NULL) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (gresult == -1)
return -1;
return msg.wParam;
}
WindowsHeader.hpp is just a few defines and Windows.h to avoid some windows macros, and WindowsMessageMap.hpp just prints windows messages to the debug console (I use it to see what messages are being called).
P.S.: this is my first post here, so feel free to point out any issues with the post itself, so that I can be more clear next time.
Thanks in advance! :-)
Upvotes: 0
Views: 316
Reputation: 3880
The hwnd
you used in the code is the same as it in Window.hpp
:
LRESULT Window::HandleMsg(HWND, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
The last line of Window.hpp:
HWND hwnd;
When you call HandleMsg
, hwnd
of Window.hpp
is not initialized:
You may use hwnd
in HandleMsgSetup
, just add the hwnd
param like the following code:
LRESULT Window::HandleMsg(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
And it works for me:
Upvotes: 2