I have this class:
WNDCLASSEX ActionButton::m_wndClass = CreateWndClass();
ActionButton::ActionButton() :
m_function(NULL), m_parameters(NULL), m_window()
{}
ActionButton::~ActionButton()
{
DestroyWindow(m_window);
}
bool ActionButton::DestroyButton()
{
return DestroyWindow(m_window);
}
bool ActionButton::Create(HWND parent, int x, int y, int heigth, int width)
{
HWND m_window = CreateWindowEx(0, L"Action button", NULL, WS_CHILD | WS_VISIBLE,
x, y, width, heigth, parent, NULL, NULL, NULL);
if (m_window == NULL)
return false;
SetWindowLongPtr(m_window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
return true;
}
void ActionButton::SetFuncionLeftButtonDown(CallbackFunction f)
{
m_function = f;
}
void ActionButton::SetParametersLeftButtonDown(void* param)
{
m_parameters = param;
}
WNDCLASSEX ActionButton::CreateWndClass()
{
WNDCLASSEX m_wndClass = {0};
if (m_wndClass.cbSize == 0)
{
m_wndClass.cbSize = sizeof(WNDCLASSEX);
m_wndClass.style = CS_NOCLOSE;
m_wndClass.lpfnWndProc = WndProc;
m_wndClass.cbClsExtra = 0;
m_wndClass.cbWndExtra = 0;
m_wndClass.hInstance = GetModuleHandle(NULL);
m_wndClass.hIcon = NULL;
m_wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wndClass.hbrBackground = HBRUSH(COLOR_BACKGROUND);
m_wndClass.lpszMenuName = NULL;
m_wndClass.lpszClassName = L"Action button";
m_wndClass.hIconSm = NULL;
}
RegisterClassEx(&m_wndClass);
return m_wndClass;
}
LRESULT __stdcall ActionButton::WndProc (HWND window, UINT msg, WPARAM wp, LPARAM lp)
{
ActionButton* classInfo = reinterpret_cast<ActionButton *>(GetWindowLongPtr(window, GWLP_USERDATA));
switch(msg)
{
case WM_LBUTTONDOWN:
{
(classInfo->m_function)(classInfo->m_parameters, classInfo);
classInfo->DestroyButton();
break;
}
case WM_DESTROY:
{
break;
}
default:
return DefWindowProc(window, msg, wp, lp);
}
return 0;
}
I have found problem, that it do not destroy window, what is more I check with debugger that m_window in destructor and Destroy() methods is NULL.
My code of using this class:
void Function(void* input, ActionButton*)
{
std::cout << "Works :)\n";
}
//....
ActionButton button;
button.Create(Form.Get(), 150,150, 50,50);
button.SetFuncionLeftButtonDown(Function);
HWND m_window
That declares a local variable which hides the class member variable. Your compiler should be warning you about this. Pay attention to the warnings.
Related
I'm making a library with raw Win32 API. My problem is, when I make an object of my child window classes, I get an error that says:
Access violation reading location 0xFFFFFFFFFFFFFFFF
I have tried many solutions, but they didn't work for me.
Also, I know that I can't access my class members in the HandleMessage() function inside the Text class (one of the child classes) because they're filled with some random garbage. How can I fix this issue?
Here's the Text.h file:
class IText
{
protected:
virtual void onPaint(Event) = 0;
virtual void onClick(Event) = 0;
};
class Text : public Component, IText, IEventListener
{
public:
Text();
Text(const std::string& text, const Style& style, const handleWindow_t& parent);
operator const std::string () const;
public:
const std::wstring& getComponentClassName() const;
const handleWindow_t& getHandleWindow() const;
public:
void onPaint(Event e) override;
void onClick(Event e) override;
public:
void addEventListener(const std::string& eventType, const std::function<void(Event)>& callbackFn) override;
public:
static LRESULT CALLBACK HandleMsgSetup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Text* self = nullptr;
if (uMsg == WM_NCCREATE)
{
LPCREATESTRUCT pCreate = reinterpret_cast<LPCREATESTRUCT>(lParam);
self = static_cast<Text*>(pCreate->lpCreateParams);
self->m_Hwnd = hWnd;
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
}
else
{
self = reinterpret_cast<Text*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
}
if (self)
{
return self->HandleMessage(uMsg, wParam, lParam);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Event e;
e.code = uMsg;
e.spec = wParam;
e.data = lParam;
e.component = m_Hwnd;
e.target = this;
switch (uMsg)
{
case WM_PAINT:
{
onPaint(e);
}
return 0;
case WM_LBUTTONDOWN:
{
onClick(e);
}
return 0;
}
return DefWindowProc(m_Hwnd, uMsg, wParam, lParam);
}
public:
handleWindow_t m_Hwnd;
private:
Style m_Style;
handleWindow_t m_Parent;
std::wstring m_Text, m_ClassName = make_ClassName(L"Text");
};
Here's the Text.cpp file:
Text::Text() : m_Style({0}), m_Text(L""), m_Parent(nullptr)
{
}
Text::Text(const std::string& text, const Style& style, const handleWindow_t& parent) : m_Text(to_wstring(text)), m_Style(style), m_Parent(parent)
{
WNDCLASS wc = { 0 };
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = HandleMsgSetup;
wc.hInstance = GetModuleHandle(nullptr);
wc.lpszClassName = m_ClassName.c_str();
if (!RegisterClass(&wc))
DWORD ret = GetLastError();
if (!(m_Hwnd = CreateWindowEx(
0,
m_ClassName.c_str(),
L"",
WS_CHILD | WS_VISIBLE,
m_Style.marginX, m_Style.marginY, m_Style.width, m_Style.height,
parent,
nullptr,
GetModuleHandle(nullptr), this
)))
printf("%s", "error\n");
}
Text::operator const std::string () const
{
return to_string(m_Text);
}
const std::wstring& Text::getComponentClassName() const
{
return m_ClassName;
}
const handleWindow_t& Text::getHandleWindow() const
{
return m_Hwnd;
}
void Text::onPaint(Event e)
{
PAINTSTRUCT ps;
handleDeviceContext_t hdc = BeginPaint(m_Hwnd, &ps);
FillRect(hdc, &ps.rcPaint, Brush(m_Style.backgroundColor));
HFONT font = CreateFontA(20, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET,
0, 0, 0,
0, "Sans Serif" // Or Segoe UI
);
SelectObject(hdc, font);
SetTextColor(hdc, m_Style.color);
if (m_Style.backgroundColor == transparent)
SetBkMode(hdc, TRANSPARENT);
else
SetBkColor(hdc, m_Style.backgroundColor);
DrawText(hdc, m_Text.c_str(), -1, &ps.rcPaint, DT_NOCLIP);
EndPaint(m_Hwnd, &ps);
}
void Text::addEventListener(const std::string& eventType, const std::function<void(Event)>& callbackFn)
{
if (eventType == "click")
m_ClickCallback = callbackFn;
}
void Text::onClick(Event e)
{
m_ClickCallback(e);
}
And here's the main.cpp:
void init(handleWindow_t window)
{
Style txtStyle = { 0 };
txtStyle.width = 100;
txtStyle.height = 22;
txtStyle.color = RGB(0, 100, 255);
txtStyle.backgroundColor = 0;
Text text("text", txtStyle, window);
text.addEventListener("click", [](Event e)
{
std::cout << "Clicked\n";
});
}
int main()
{
Style appStyle = { 0 };
appStyle.width = 800;
appStyle.height = 600;
appStyle.marginX = 100;
appStyle.marginY = 100;
appStyle.backgroundColor = 0xffffff;
Window window("Sandbox", appStyle);
window.show();
init(window);
while (window.running())
{
}
return 0;
}
The reason why I was getting that error was the that Text object was destructed when init function scope ends and the solution for that is to make pointer to that object so the Text object is not destroyed when the init function returns.
Here's the code
void init(handleWindow_t window)
{
Style txtStyle = { 0 };
txtStyle.width = 100;
txtStyle.height = 22;
txtStyle.color = RGB(0, 100, 255);
txtStyle.backgroundColor = 0;
Text* text = new Text("text", txtStyle, window);
text->addEventListener("click", [](Event e)
{
std::cout << "Clicked\n";
});
}
CreateWindow.h
#pragma once
#include <Windows.h>
#include <iostream>
#include <stdint.h>
#include <cmath>
#include <vector>
#include <sstream>
using namespace std;
struct returncursorposdemcical
{
float x, y;
};
struct CustomImage
{
vector<vector<unsigned>> CImage;
int long height, width;
};
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
class window
{
public:
window();
window(const window&) = delete;
window& operator = (const window&) = delete;
~window();
bool windowpro();
void stretchbit();
void backgroundcolor(int R, int G, int B);
private:
};
CreateWindow.cpp
#include "../Header/CreateWindow.h"
WNDCLASS WindowClass = {};
HWND CreateMyWindow;
HDC mydc;
int BitmapWidth;
int BitmapHeight;
RECT ClientRect;
int ClientWidth;
int ClientHeight;
long int buffer_sizes;
void* buffer_memory;
BITMAPINFO buffer_bitmap;
HINSTANCE myhinstance;
window::window()
{
WindowClass.lpszClassName = "Game_Engine";
WindowClass.lpfnWndProc = WindowProc;
WindowClass.hInstance = myhinstance;
WindowClass.hCursor = LoadCursor(0, IDC_CROSS);
RegisterClass(&WindowClass);
CreateMyWindow = CreateWindowEx(0, "Game_Engine", "Program",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, GetModuleHandle(nullptr), 0);
mydc = GetDC(CreateMyWindow);
ShowWindow(CreateMyWindow, SW_SHOWMAXIMIZED);
}
window::~window()
{
std::cout << "destroy";
ReleaseDC(CreateMyWindow, mydc);
UnregisterClass("Game_Engine", myhinstance);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_MOUSEMOVE:
{
}
case WM_MOUSELEAVE:
{
}
case WM_SIZE:
{
GetClientRect(CreateMyWindow, &ClientRect);
ClientWidth = ClientRect.right - ClientRect.left;
ClientHeight = ClientRect.bottom - ClientRect.top;
BitmapWidth = ClientWidth;
BitmapHeight = ClientHeight;
buffer_sizes = BitmapWidth * BitmapHeight * sizeof(unsigned int);
if (buffer_memory) {
VirtualFree(buffer_memory, 0, MEM_RELEASE);
}
buffer_memory = VirtualAlloc(0, buffer_sizes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
buffer_bitmap.bmiHeader.biSize = sizeof(buffer_bitmap.bmiHeader);
buffer_bitmap.bmiHeader.biWidth = BitmapWidth;
buffer_bitmap.bmiHeader.biHeight = -BitmapHeight;
buffer_bitmap.bmiHeader.biPlanes = 1;
buffer_bitmap.bmiHeader.biBitCount = 24;
buffer_bitmap.bmiHeader.biCompression = BI_RGB;
}
return 0;
case WM_PAINT:
{
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
bool window::windowpro()
{
MSG msg = { };
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) {
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}
void window::backgroundcolor(int R, int G, int B)
{
unsigned int* pixel = (unsigned int*)buffer_memory;
for (int y = 0; y < BitmapHeight; y++) {
for (int x = 0; x < BitmapWidth; x++)
{
*pixel++ = (R << 16) + (G << 8) + B;
}
}
}
void window::stretchbit()
{
StretchDIBits(mydc, 0, 0, BitmapWidth, BitmapHeight, 0, 0, ClientWidth, ClientHeight, buffer_memory,&buffer_bitmap,DIB_RGB_COLORS,SRCCOPY);
}
Source.cpp
#include "../WindowStartup/Header/CreateWindow.h"
int main()
{
window mywindow;
bool running = true;
while (running == true)
{
mywindow.backgroundcolor(225, 225, 225);
mywindow.stretchbit();
if (!mywindow.windowpro())
{
running = false;
}
}
return 0;
}
I tried to double buffer it, but it didn't work, I tried using bitblit, but it's the same result. Also, when the window resizing, it's not fully painted. And when the window it's not at the full size, it does not look strippy, so my speculation is that either my program is writing the data to bitmap to slow for the refresh rate, or the bitmap it's copying to screen to slow. Sorry for my bad English, English it's not my first language, and I am new to program.
I fixed, all you have to do is change biBitcounts to 32, I don't know why that works, might be some to do with ARGB, although I am only using RGB which is 24bits or 3 bytes, if someone could explain this why I need to change biBitcounts to 32, that would be nice. Also thanks for all the people in the comment that are trying to help me.
This question already has an answer here:
Win32 API - RegisterClassEx errors
(1 answer)
Closed 2 years ago.
Hi I am an Beginner learning DirectX 11 Api I have seen tutorial on Youtube and implemented this Wrapper for Windows But the Window is lot Loading The only debug string I get is just the Register Class Failed string in the INIT_WINDOw method . Nothing else Pops up . PLease help me with this .
DX_Wrapper.cpp
#include "Headers/Dx_Wrapper.h"
//Global One For Defining __stdcall for WindowProc
namespace
{
Wrapper* g_wrapper = nullptr;
}
//Main WINDOW Message processing Window Procedure
LRESULT CALLBACK WINDOWPROC(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (g_wrapper) return g_wrapper->MessageProcedure(hwnd, msg, wparam, lparam);
else return DefWindowProc(hwnd, msg, wparam, lparam);
}
//Constructor For the Instance
Wrapper::Wrapper(HINSTANCE hinstance)
{
m_hinstance = hinstance;
m_hwnd = NULL;
m_winheight = 600;
m_winwidth = 800;
m_wintitle = L"DirectX";
m_winstyles = WS_OVERLAPPEDWINDOW;
g_wrapper = this;
}
Wrapper::~Wrapper()
{
}
//Window Loop Manager Attached to the WINDOWPROC function
int32_t Wrapper::Run()
{
MSG message = { 0 };
while (WM_QUIT != message.message)
{
//Message Check If Quit
if (PeekMessage(&message, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
//If Not Quit
else
{
UPDATE_FRM(5.5f);
}
}
return static_cast<int>(message.wParam);
}
bool Wrapper::Init()
{
if (!INIT_WINDOW() == true)
{
return false;
}
return true;
}
LRESULT Wrapper::MessageProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
void Wrapper::UPDATE_FRM(float delta_time)
{
}
void Wrapper::RENDER_FRM(float delta_time)
{
}
//Registering Classical Windows Class Function
bool Wrapper::INIT_WINDOW()
{
//THE CLASS REGISTERING STUFF
WNDCLASSEX win_class;
win_class.cbClsExtra = 0;
win_class.hInstance = m_hinstance;
win_class.cbWndExtra = 0;
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.cbSize = sizeof(WNDCLASSEX);
win_class.lpfnWndProc = WINDOWPROC;
win_class.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
win_class.lpszMenuName = NULL;
win_class.lpszClassName = L"dx_main_class";
win_class.hCursor = 0;
RegisterClassEx(&win_class);
if (!RegisterClassEx(&win_class))
{
OutputDebugString(L"Registering Class Failed");
return false;
}
RECT r = {0,0,m_winwidth,m_winheight};
AdjustWindowRect(&r, m_winstyles, FALSE);
uint_fast16_t f_width = r.right - r.left;
uint_fast16_t f_height = r.bottom - r.top;
uint_fast16_t f_width_final = uint_fast16_t(GetSystemMetrics(SM_CXSCREEN) / 2 - f_width / 2);
uint_fast16_t f_height_final = uint_fast16_t(GetSystemMetrics(SM_CYSCREEN) / 2 - f_height / 2);
m_hwnd = CreateWindow(L"dx_main_class", m_wintitle, m_winstyles, f_width_final, f_height_final, f_width, f_height, NULL, NULL, m_hinstance, NULL);
if (!m_hwnd)
{
OutputDebugString(L"Window Could Not be Created ");
return false;
}
ShowWindow(m_hwnd, SW_SHOW);
return true;
}
DX_Wrapper.h
#include <Windows.h>
#include <stdint.h>
#include <string>
#define WIN32_LEAN_AND_MEAN
class Wrapper
{
public:
Wrapper(HINSTANCE hinstance);
virtual ~Wrapper();
int32_t Run();
virtual bool Init();
virtual LRESULT MessageProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
virtual void UPDATE_FRM(float delta_time) = 0;
virtual void RENDER_FRM(float delta_time) = 0;
protected:
HWND m_hwnd = nullptr;
HINSTANCE m_hinstance = nullptr;
uint_fast16_t m_winwidth = 0;
uint_fast16_t m_winheight = 0;
LPCWSTR m_wintitle = L"";
DWORD m_winstyles = 0;
protected:
bool INIT_WINDOW();
};
This is the Main Application CPP file
#include "Headers/Dx_Wrapper.h"
class Application : public Wrapper
{
public:
Application(HINSTANCE hinstance);
bool Init() override;
void UPDATE_FRM(float delta_time) override;
void RENDER_FRM(float delta_time) override;
};
Application::Application(HINSTANCE hinstance) : Wrapper(hinstance)
{
}
bool Application::Init()
{
return Wrapper::Init();
}
void Application::UPDATE_FRM(float delta_time)
{
}
void Application::RENDER_FRM(float delta_time)
{
}
int32_t WINAPI WinMain(__in HINSTANCE hinstance, __in_opt HINSTANCE hprevinstance, __in LPSTR cmdline, __in int cmdshow)
{
Application m_app(hinstance);
if (!m_app.Init()) return 1;
return m_app.Run();
}
My Problem is The OutputDebugString Just shows The Registering class failed string from the INIT_WINDOW function . I have no clue why it is wrong . The Window is not running .
First you called twice RegisterClassEx function, so you need to delete the first call:
//RegisterClassEx(&win_class);
if (!RegisterClassEx(&win_class))
{
OutputDebugString(L"Registering Class Failed");
return false;
}
Then you need to set each member of WNDCLASSEX.
So you can refer to the following code:
WNDCLASSEX win_class;
win_class.cbSize = sizeof(WNDCLASSEX);
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.lpfnWndProc = WINDOWPROC;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = 0;
win_class.hInstance = m_hinstance;
win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
win_class.hCursor = 0;
win_class.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
win_class.lpszMenuName = NULL;
win_class.lpszClassName = L"dx_main_class";
win_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
In my project i have created a simple Button class:
button.hpp:
class Button : public Control {
std::string text;
int id;
std::function<void(void)>&& callback{};
static inline const char* sClassName = "Button";
static LRESULT CALLBACK ButtonSubclassProc(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR);
public:
Button(HWND parent, POINT position, SIZE size, int id, const std::string& text) noexcept;
virtual ~Button() noexcept;
inline void SetCallback(std::function<void(void)>&& callback) noexcept { this->callback = callback; }
NODISCARD inline int GetId() const noexcept { return id; }
private:
NODISCARD bool CreateControl(HWND) noexcept override;
void DestroyControl() noexcept override;
void Invoke() const noexcept;
};
button.cpp:
#include "button.hpp"
Button::Button(HWND parent, POINT position, SIZE size, int id, const std::string& text) noexcept
: Control(position, size), id(id), text(text) {
isCreated = CreateControl(parent);
SetWindowSubclass(hwnd, &Button::ButtonSubclassProc, id, reinterpret_cast<DWORD_PTR>(this));
}
Button::~Button() noexcept {
RemoveWindowSubclass(hwnd, &Button::ButtonSubclassProc, id);
DestroyControl();
}
NODISCARD bool Button::CreateControl(HWND parent) noexcept {
hwnd = CreateWindow(sClassName, text.c_str(), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, position.x, position.y, size.cx, size.cy, parent, reinterpret_cast<HMENU>(id), reinterpret_cast<HINSTANCE>(GetWindowLong(parent, GWL_HINSTANCE)), NULL);
return hwnd != NULL;
}
void Button::DestroyControl() noexcept {
Control::DestroyControl();
}
void Button::Invoke() const noexcept {
if (callback) {
callback();
}
}
LRESULT CALLBACK Button::ButtonSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR refData) {
auto button = reinterpret_cast<Button*>(refData);
if (uMsg == WM_COMMAND) {
MessageBox(0, std::to_string(id).c_str(), 0, 0);
button->Invoke();
return TRUE;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
that's how i pass message from main window procedure:
case WM_COMMAND: {
return SendMessage(reinterpret_cast<HWND>(lParam), WM_COMMAND, wParam, lParam);
}
And it works fine when only one button is created, but when i try to create more, it does not matter which button i would push, i always get callback of the last created button.
I suppose this happens because of SetWindowSubclass call in counstructor and passing it this pointer, but i do not know what should i do. Read about GetWindowSubclass but i dont clearly understand how to use it.
Buttons are created in main window class:
mainwnd.hpp
class MainWindow : public NonCopyable, public NonMovable {
HINSTANCE handle;
HWND hwnd;
int width;
int height;
bool isRegistered{ false };
bool isCreated{ false };
IRenderer* renderer;
Button* buttonStart;
Button* buttonStop;
static inline const char* sClassName = "MAIN_WINDOW_CLASS";
static LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
public:
explicit MainWindow(HINSTANCE handle, int width, int height) noexcept;
~MainWindow() noexcept;
NODISCARD inline bool IsRegistered() const noexcept { return isRegistered; }
NODISCARD inline bool IsCreated() const noexcept { return isCreated; }
NODISCARD bool CheckControls() const noexcept;
NODISCARD inline int Width() const noexcept { return width; }
NODISCARD inline int Height() const noexcept { return height; }
void Update() noexcept;
private:
NODISCARD bool RegisterMainClass() const noexcept;
NODISCARD bool CreateMainWindow() noexcept;
void UnregisterMainClass() noexcept;
void DestroyMainWindow() noexcept;
void CreateControls() noexcept;
void DestroyControls() noexcept;
void OnButtonStartPushed();
void OnButtonStopPushed();
};
mainwnd.cpp
#include "main_window.hpp"
MainWindow::MainWindow(HINSTANCE handle, int width, int height) noexcept
: width(width), height(height), handle(handle) {
isRegistered = RegisterMainClass();
isCreated = CreateMainWindow();
CreateControls();
}
MainWindow::~MainWindow() noexcept {
DestroyControls();
DestroyMainWindow();
UnregisterMainClass();
}
bool MainWindow::RegisterMainClass() const noexcept {
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASSA));
if (!GetClassInfo(handle, sClassName, &wc)) {
wc.style = 0;
wc.hInstance = handle;
wc.lpszClassName = sClassName;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LONG_PTR);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.lpszMenuName = NULL;
}
return RegisterClass(&wc) != 0;
}
bool MainWindow::CreateMainWindow() noexcept {
if (IsRegistered()) {
hwnd = CreateWindow(sClassName, NULL, WS_VISIBLE | WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, handle, this);
}
return hwnd != NULL;
}
void MainWindow::UnregisterMainClass() noexcept {
UnregisterClass(sClassName, handle);
isRegistered = false;
}
void MainWindow::DestroyMainWindow() noexcept {
if (hwnd) {
DestroyWindow(hwnd);
hwnd = NULL;
}
isCreated = false;
}
void MainWindow::CreateControls() noexcept {
this->renderer = new Canvas(hwnd, { 10,10 }, { 200,200 });
buttonStart = new Button(hwnd, { 300,50 }, { 100,40 }, 145, "Start");
buttonStart->SetCallback(std::bind(&MainWindow::OnButtonStartPushed, this));
buttonStop = new Button(hwnd, { 300,150 }, { 100,40 }, 168, "Stop");
buttonStop->SetCallback(std::bind(&MainWindow::OnButtonStopPushed, this));
}
void MainWindow::DestroyControls() noexcept {
delete renderer;
delete buttonStart;
delete buttonStop;
}
bool MainWindow::CheckControls() const noexcept {
return renderer != 0;
}
void MainWindow::Update() noexcept {
renderer->Redraw();
}
void MainWindow::OnButtonStartPushed() {
MessageBox(0, "Start", 0, 0);
}
void MainWindow::OnButtonStopPushed() {
MessageBox(0, "Stop", 0, 0);
}
LRESULT CALLBACK MainWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_NCCREATE) {
MainWindow* window = reinterpret_cast<MainWindow*>(lParam);
SetWindowLongPtr(hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(window));
return TRUE;
}
auto window = reinterpret_cast<MainWindow*>(GetWindowLongPtr(hwnd, GWL_USERDATA));
if (window == nullptr) {
return FALSE;
}
switch (uMsg) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
case WM_COMMAND: {
return SendMessage(reinterpret_cast<HWND>(lParam), WM_COMMAND, wParam, lParam);
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return TRUE;
}
Message Loop:
MSG message;
memset(&message, 0, sizeof(MSG));
while (true) {
if (PeekMessage(&message, 0, 0, 0, PM_REMOVE) != 0) {
if (message.message == WM_QUIT) {
break;
}
TranslateMessage(&message);
DispatchMessage(&message);
} else {
mainWindow.Update();
}
}
For the most part this is borrowed code from RasterTeks DX11 tutorial that I am modified lightly or my own use and taste. I am getting a read access violation while using the below InputClass to set keystates.
#include "InputClass.h"
InputClass::InputClass() { }
InputClass::InputClass(const InputClass& other) { }
InputClass::~InputClass() { }
void InputClass::Initialize() {
// Initialize all the keys to being released and not pressed.
for (int i = 0; i<256; i++) {
keystate[i] = false;
}
return;
}
void InputClass::KeyDown(unsigned int input) {
// If a key is pressed then save that state in the key array.
keystate[input] = true;
return;
}
void InputClass::KeyUp(unsigned int input) {
// If a key is released then clear that state in the key array.
keystate[input] = false;
return;
}
bool InputClass::IsKeyDown(unsigned int input) {
// Return what state the key is in (pressed/not pressed).
return keystate[input];
}
Below is my main callback loop, the one registered with the WindowClass:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
// this message is read when the window is closed
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
// Check if the window is being closed.
case WM_CLOSE: {
PostQuitMessage(0);
return 0;
}
default: { return ApplicationHandle->MessageHandler(hWnd, message, wParam, lParam); }
}
}
Finally, below is the secondary message handler that is a part of my SystemClass:
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_KEYDOWN: { input->KeyDown((unsigned int)wparam); }
case WM_KEYUP: { input->KeyUp((unsigned int)wparam); }
default: { return DefWindowProc(hwnd, message, wparam, lparam); }
}
}
The exception is fired off when the code gets to my switch/case/default list in the secondary message handler. If I comment these lines out the program happily runs but of course, no input.
Any help or clues would be invaluable. Thank you so much for your time.
Try following modification of your code:
void InputClass::KeyDown(unsigned int input) {
if (input < 0 || input > 255)
return;
// If a key is pressed then save that state in the key array.
keystate[input] = true;
return;
}
void InputClass::KeyUp(unsigned int input) {
if (input < 0 || input > 255)
return;
// If a key is released then clear that state in the key array.
keystate[input] = false;
return;
}
(since you haven't any problems in constructor of InputClass, it is not a problem of private status of array)
I tried it with no luck. I will leave the code in just in case of error, but it called an access violation in the same place.
I will include missing information below.
//inputclass.h
class InputClass
{
public:
InputClass();
InputClass(const InputClass&);
~InputClass();
void Initialize();
void KeyDown(unsigned int);
void KeyUp(unsigned int);
bool IsKeyDown(unsigned int);
//private:
bool keystate[256];
};
//systemclass.h
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <windowsx.h>
#include "InputClass.h"
class SystemClass {
public:
SystemClass();
~SystemClass();
void Startup();
bool InitializeWindows(HWND);
void ShutDown();
void Run();
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
int GetWindowPosX();
int GetWindowPosY();
int GetWindowWidth();
int GetWindowHeight();
private:
HWND hWnd;
InputClass* input;
int posX, posY, windowWidth, windowHeight;
};
static SystemClass* ApplicationHandle = 0;
//main.cpp
#include "systemclass.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviousInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
SystemClass* system;
system = new SystemClass;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"Engine";
RegisterClassEx(&wc);
system->Startup();
if(!(system->InitializeWindows(CreateWindowEx(NULL,
L"Engine",
L"Engine",
WS_POPUP | WS_VISIBLE,
system->GetWindowPosX(),
system->GetWindowPosY(),
system->GetWindowWidth(),
system->GetWindowHeight(),
NULL,
NULL,
hInstance,
NULL)))) return 0;
system->Run();
system->ShutDown();
UnregisterClass(L"Engine", hInstance);
delete system;
system = 0;
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
// this message is read when the window is closed
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
// Check if the window is being closed.
case WM_CLOSE: {
PostQuitMessage(0);
return 0;
}
default: { return ApplicationHandle->MessageHandler(hWnd, message, wParam, lParam); }
}
}
//systemclass.cpp
#include "SystemClass.h"
SystemClass::SystemClass() { }
SystemClass::~SystemClass() { }
void SystemClass::Startup() {
ApplicationHandle = this;
windowWidth = GetSystemMetrics(SM_CXSCREEN);
windowHeight = GetSystemMetrics(SM_CYSCREEN);
input = new InputClass;
input->Initialize();
int fc = MessageBox(NULL, L"Engine", L"Fullscreen?", MB_YESNO);
switch (fc) {
case 7: {
posX = (windowWidth - 800) / 2;
posY = (windowHeight - 600) / 2;
windowWidth = 800;
windowHeight = 600;
}
case 6: {
DEVMODE dmScreenSettings;
posX = posY = 0;
ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)windowWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)windowHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Change the display settings to full screen.
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
}
}
}
bool SystemClass::InitializeWindows(HWND ihWnd) {
hWnd = ihWnd;
if (hWnd) {
//system->InitializeWindows(hWnd);
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
return true;
}
else {
MessageBoxEx(NULL, L"Could not create window.", L"ERROR!", MB_OK | MB_ICONEXCLAMATION, NULL);
return false;
}
}
void SystemClass::ShutDown() {
delete input;
input = 0;
DestroyWindow(hWnd);
hWnd = NULL;
ApplicationHandle = NULL;
}
void SystemClass::Run() {
bool done;
MSG msg;
done = false;
while (!done) {
// Handle the windows messages.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (input->IsKeyDown(VK_ESCAPE)) {
done = true;
MessageBoxEx(NULL, L"input broken.", L"ERROR!", MB_OK | MB_ICONEXCLAMATION, NULL);
}
// If windows signals to end the application then exit out.
if (msg.message == WM_QUIT) { done = true; }
}
}
int SystemClass::GetWindowPosX(){ return posX; }
int SystemClass::GetWindowPosY() { return posY; }
int SystemClass::GetWindowWidth() { return windowWidth; }
int SystemClass::GetWindowHeight() { return windowHeight; }
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_KEYDOWN: { input->KeyDown((unsigned int)wparam); }
case WM_KEYUP: { input->KeyUp((unsigned int)wparam); }
default: { return DefWindowProc(hwnd, message, wparam, lparam); }
}
}
The error message given when when I hit the escape key:
Unhandled exception at 0x00881E08 in DX11 Engine 2.exe: 0xC0000005: Access violation reading location 0x00000004.
OK: this is where it gets interesting, the values in the local field (specific to the second callback function) are as follows:
lparam: 65537
wparam: 27
message: 256
hwnd: 0x01b80460 {unused=???}
this: 0x00000000
The value of hwnd, wparam, and lparam are all displayed in red.
I feel like the values are supposed to tell me something about what is going on here but I just don't really understand. Is there a reason why the variable "this" is set to adress 0x00000000? this is a pointer to an instance of the systemclass... or it's supposed to be.
Also, the unused comment in hwnd throws me off, though I'm not sure what is going wrong there since the program is very clearly at least DETECTING a keypress attributed to the window.
I hope this helps anyone with any ideas.
EDIT: You got me looking for a misused pointer and I discovered it had EVERYTHING to do with the "this" pointer and the way I was using system and ApplicationHandle. I fixed it by changing ApplicationHandle to system and simply using the same pointer everywhere. The way I was using it before was illogical and senseless.
Thank you all for helping me find it!