I am attempting a new user graphics tutorial but I am very stuck. I am a very new programmer...I was under the impression that most of these definitions would be included in I included. My message handler is missing an identifier 'DefWindowProcess', WINDCLASSEX is also not being identified, GetModuleHandle function, PeekMessage/TranslateMessage etc. The Microsoft dev center says that all these definitions should be in windows.h.
#ifndef _SYSTEMCLASS_H_
#define _SYSTEMCLASS_H_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "inputclass.h"
#include "graphicsclass.h"
class SystemClass
{
public:
SystemClass();
SystemClass(const SystemClass&);
~SystemClass();
bool Initialize();
void Shutdown();
void Run();
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
private:
bool Frame();
void InitializeWindows(int&, int&);
void ShutdownWindows();
private:
LPCWSTR m_applicationName;
HINSTANCE m_hinstance;
HWND m_hwnd;
InputClass* m_Input;
GraphicsClass* m_Graphics;
};
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static SystemClass* ApplicationHandle = 0;
#endif
my systemclass.cpp is as follows
#include "pch.h"
#include "systemclass.h"
SystemClass::SystemClass()
{
m_Input = 0;
m_Graphics = 0;
}
bool SystemClass::Initialize()
{
int screenWidth, screenHeight;
bool result;
screenWidth = 0;
screenHeight = 0;
// Initialize the windows api.
InitializeWindows(screenWidth, screenHeight);
m_Input = new InputClass;
if (!m_Input)
{
return false;
}
// Initialize the input object.
m_Input->Initialize();
// Create the graphics object. This object will handle rendering all the graphics for this application.
m_Graphics = new GraphicsClass;
if (!m_Graphics)
{
return false;
}
// Initialize the graphics object.
result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
if (!result)
{
return false;
}
return true;
}
void SystemClass::Shutdown()
{
// Release the graphics object.
if (m_Graphics)
{
m_Graphics->Shutdown();
delete m_Graphics;
m_Graphics = 0;
}
// Release the input object.
if (m_Input)
{
delete m_Input;
m_Input = 0;
}
// Shutdown the window.
ShutdownWindows();
return;
}
void SystemClass::Run()
{
MSG msg;
bool done, result;
// Initialize the message structure.
ZeroMemory(&msg, sizeof(MSG));
// Loop until there is a quit message from the window or the user.
done = false;
while (!done)
{
// Handle the windows messages.
if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// If windows signals to end the application then exit out.
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
// Otherwise do the frame processing.
result = Frame();
if (!result)
{
done = true;
}
}
}
return;
}
bool SystemClass::Frame()
{
bool result;
// Check if the user pressed escape and wants to exit the application.
if (m_Input->IsKeyDown(VK_ESCAPE))
{
return false;
}
// Do the frame processing for the graphics object.
result = m_Graphics->Frame();
if (!result)
{
return false;
}
return true;
}
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch (umsg)
{
// Check if a key has been pressed on the keyboard.
case WM_KEYDOWN:
{
m_Input->KeyDown((unsigned int)wparam);
return 0;
}
// Check if a key has been released on the keyboard.
case WM_KEYUP:
{
m_Input->KeyUp((unsigned int)wparam);
return 0;
}
default:
{
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
}
}
void SystemClass::InitializeWindows(int& screenWidth, int& screenHeight)
{
WNDCLASSEX wc; //THIS IS THE PROBLEM
DEVMODE dmScreenSettings;
int posX, posY;
// Get an external pointer to this object.
ApplicationHandle = this;
// Get the instance of this application.
m_hinstance = GetModuleHandle(NULL);
// Give the application a name.
m_applicationName = L"Engine";
// Setup the windows class with default settings.
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hinstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = m_applicationName;
wc.cbSize = sizeof(WNDCLASSEX);
// Register the window class.
RegisterClassEx(&wc);
// Determine the resolution of the clients desktop screen.
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
if (FULL_SCREEN)
{
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Change the display settings to full screen.
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
// Set the position of the window to the top left corner.
posX = posY = 0;
}
else
{
// If windowed then set it to 800x600 resolution.
screenWidth = 800;
screenHeight = 600;
// Place the window in the middle of the screen.
posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
}
// Create the window with the screen settings and get the handle to it.
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
// Bring the window up on the screen and set it as main focus.
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
SetFocus(m_hwnd);
// Hide the mouse cursor.
ShowCursor(false);
return;
}
void SystemClass::ShutdownWindows()
{
// Show the mouse cursor.
ShowCursor(true);
// Fix the display settings if leaving full screen mode.
if (FULL_SCREEN)
{
ChangeDisplaySettings(NULL, 0);
}
// Remove the window.
DestroyWindow(m_hwnd);
m_hwnd = NULL;
// Remove the application instance.
UnregisterClass(m_applicationName, m_hinstance);
m_hinstance = NULL;
// Release the pointer to this class.
ApplicationHandle = NULL;
return;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
switch (umessage)
{
// Check if the window is being destroyed.
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
// Check if the window is being closed.
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
// All other messages pass to the message handler in the system class.
default:
{
return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
}
}
}
Figured it out, directx projects don't recognize window API, I needed a win32 project, apply #stdafx headers on all my cpp files to get precompiled headers to work an also add #pragma once to all header files to avoid pch errors. VS is a bit quirky it turns out. Also for all the other noobs, make sure you set up file paths for directx and that you add files through project ->add->newfile->appropriate file type. it will save you headaches from VS knowing correct file locations.
Related
I am Following a C++ game tutorial using the DirectX 11 engine. In the first two parts, my code was fine, but on the third part (creating the SwapChain) the DirectX window decided to not show up, leaving me with the console. I don't really know how to describe the code so I will just insert all the classes, header files, etc.
main.cpp:
#include "AppWindow.h"
int main()
{
AppWindow app;
if (app.Init())
{
while (app.isRun())
{
app.brodcast();
}
}
return 0;
}
AppWindow.cpp:
#include "AppWindow.h"
void AppWindow::onCreate()
{
GraphicsEngine::get()->init();
m_swap_chain = GraphicsEngine::get()->crreateSwapChain();
RECT rc = this->getClientWindowRect();
m_swap_chain->init(this->m_hwnd, rc.right-rc.left, rc.bottom-rc.top);
}
void AppWindow::onUpdate()
{
}
void AppWindow::onDestroy()
{
Window::onDestroy();
GraphicsEngine::get()->release();
}
AppWindow.h:
#pragma once
#include "Window.h"
#include "GraphicsEngine.h"
#include "SwapChain.h"
class AppWindow: public Window
{
public:
// Inherited via Window
virtual void onCreate() override;
virtual void onUpdate() override;
virtual void onDestroy() override;
private:
SwapChain * m_swap_chain;
};
Window.cpp:
#include "Window.h"
Window* window = nullptr;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE:
{
//Event fired when the window will be created
//collected here...
Window* window = (Window*)((LPCREATESTRUCT)lparam)->lpCreateParams;
//...and then stored here for later look up
SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)window);
window->setHWND(hwnd);
window->onCreate();
break;
}
case WM_DESTROY:
{
//Event fired when the window will be destroyed
window->onDestroy();
::PostQuitMessage(0);
break;
}
default:
return ::DefWindowProc(hwnd, msg, wparam, lparam);
}
return NULL;
}
bool Window::Init()
{
WNDCLASSEX wc;
wc.cbClsExtra = NULL;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = NULL;
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance = NULL;
wc.lpszClassName = "MyWindowClass";
wc.lpszMenuName = "";
wc.style = NULL;
wc.lpfnWndProc = &WndProc;
if (!::RegisterClassEx(&wc)) //if the registration of the class will fail, the function will return false
return false;
if (!window)
window = this;
//creation of the window
m_hwnd=::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MyWindowClass", "DirectX Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768, NULL, NULL, NULL, NULL);
//if the creation fails then the method will return false
if (!m_hwnd)
return false;
//show up the window
::ShowWindow(m_hwnd, SW_SHOW);
::UpdateWindow(m_hwnd);
//set this flag to true to indicate that the window is initialized and running
m_is_run = true;
return true;
}
bool Window::brodcast()
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
window->onUpdate();
Sleep(0);
return true;
}
bool Window::Release()
{
//destroy the window
if (!::DestroyWindow(m_hwnd))
return false;
return true;
}
void Window::onDestroy()
{
m_is_run = false;
}
bool Window::isRun()
{
return m_is_run;
}
RECT Window::getClientWindowRect()
{
RECT rc;
::GetClientRect(this->m_hwnd, &rc);
return rc;
}
void Window::setHWND(HWND hwnd)
{
this->m_hwnd = hwnd;
}
Window.h:
#pragma once
#include <windows.h>
class Window
{
public:
//Initialize the window
bool Init();
bool brodcast();
//Release the window
bool Release();
bool isRun();
RECT getClientWindowRect();
void setHWND(HWND hwnd);
//EVENTS
virtual void onCreate()=0;
virtual void onUpdate()=0;
virtual void onDestroy()=0;
protected:
HWND m_hwnd;
bool m_is_run;
};
GraphicsEngine.cpp:
#include "GraphicsEngine.h"
#include <d3d11.h>
#include "SwapChain.h"
bool GraphicsEngine::init()
{
D3D_DRIVER_TYPE driver_types[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE
};
UINT num_driver_types = ARRAYSIZE(driver_types);
D3D_FEATURE_LEVEL feature_levels[]=
{
D3D_FEATURE_LEVEL_11_0
};
UINT num_feature_levels = ARRAYSIZE(feature_levels);
HRESULT res = 0;
for (UINT driver_type_index = 0; driver_type_index < num_driver_types;)
{
res = D3D11CreateDevice(NULL, driver_types[driver_type_index], NULL, NULL, feature_levels,
num_feature_levels, D3D10_1_SDK_VERSION, &m_d3d_device, &m_feature_level, &m_imm_context);
if (SUCCEEDED(res))
break;
++driver_type_index;
}
if (FAILED(res))
{
return false;
}
m_d3d_device->QueryInterface(__uuidof(IDXGIDevice), (void**)&m_dxgi_device);
m_dxgi_device->GetParent(__uuidof(IDXGIAdapter), (void**)&m_dxgi_adapter);
m_dxgi_adapter->GetParent(__uuidof(IDXGIFactory), (void**)&m_dxgi_factory);
return true;
}
bool GraphicsEngine::release()
{
m_dxgi_device->Release();
m_dxgi_adapter->Release();
m_dxgi_factory->Release();
m_imm_context->Release();
m_d3d_device->Release();
return true;
}
GraphicsEngine * GraphicsEngine::get()
{
static GraphicsEngine engine;
return &engine;
}
SwapChain * GraphicsEngine::crreateSwapChain()
{
return new SwapChain();
}
GraphicsEngine.h
#pragma once
#include <d3d11.h>
class SwapChain;
class GraphicsEngine
{
public:
//initialize graphics engine and DirectX 11 device
bool init();
//release all the resources loaded
bool release();
static GraphicsEngine* get();
SwapChain* crreateSwapChain();
private:
ID3D11Device * m_d3d_device;
D3D_FEATURE_LEVEL m_feature_level;
ID3D11DeviceContext * m_imm_context;
IDXGIDevice * m_dxgi_device;
IDXGIAdapter * m_dxgi_adapter;
IDXGIFactory * m_dxgi_factory;
friend class SwapChain;
};
SwapChain.cpp:
#include "SwapChain.h"
#include "GraphicsEngine.h"
bool SwapChain::init(HWND hwnd, UINT width, UINT height)
{
ID3D11Device *device = GraphicsEngine::get()->m_d3d_device;
DXGI_SWAP_CHAIN_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.BufferCount = 1;
desc.BufferDesc.Width = width;
desc.BufferDesc.Height = height;
desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.RefreshRate.Denominator = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.OutputWindow = hwnd;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Windowed = TRUE;
//Create the SwapChain for the window initialized by the HWND paramater
HRESULT hr = GraphicsEngine::get()->m_dxgi_factory->CreateSwapChain(device, &desc, &m_swap_chain);
if (FAILED(hr))
{
return false;
}
return true;
}
bool SwapChain::release()
{
m_swap_chain->Release();
delete this;
return true;
}
SwapChain.h:
#pragma once
#include <d3d11.h>
class SwapChain
{
public:
//Initialize a SwapChain for a window
bool init(HWND hwnd, UINT width, UINT height);
//release the SwapChain
bool release();
private:
IDXGISwapChain* m_swap_chain;
};
In window.cpp I get an Exception at this->m_hwnd = hwnd;
The problem is in this line of code:
Window* window = (Window*)((LPCREATESTRUCT)lparam)->lpCreateParams;
The incoming lparam is a null value, making window a null pointer, which eventually leads to an access error.
How to solve?
When call CreateWindowEx, you need to pass a pointer to Window class in the final void* parameter.
//creation of the window
m_hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MyWindowClass", "DirectX Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768, NULL, NULL, NULL, window);
Note: (Problems you may encounter)
If the Direct3D 11.1 runtime is present on the computer and
pFeatureLevels is set to NULL, this function won't create a
D3D_FEATURE_LEVEL_11_1 device. To create a D3D_FEATURE_LEVEL_11_1
device, you must explicitly provide a D3D_FEATURE_LEVEL array that
includes D3D_FEATURE_LEVEL_11_1. If you provide a D3D_FEATURE_LEVEL
array that contains D3D_FEATURE_LEVEL_11_1 on a computer that doesn't
have the Direct3D 11.1 runtime installed, this function immediately
fails with E_INVALIDARG.
Refer: D3D11CreateDevice function
You may need to use D3D11_SDK_VERSION instead of D3D10_1_SDK_VERSION in D3D11CreateDevice.
Refer: How To: Get the Device Feature Level
I've made two simple classes to use for displaying UIs with Awesomium. However creating the Awesomium WebView and setting the parent window to my Win32 window causes the program to hang and the page is never displayed. The classes are simple and creating a window is simple so there isn't much I can think of that could be going wrong. Perhaps there is something else required than what I've done to display a WebView?
To clarify: Creating the Win32 window without creating the WebView works fine, the window functions including the drag code etc... The hang only happens when you call set_parent_window.
UI.h
#pragma once
#include <Windows.h>
#include <windowsx.h>
#include <Awesomium/WebCore.h>
#include <Awesomium/STLHelpers.h>
using namespace Awesomium;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
class UI
{
public:
//Window Variables
HINSTANCE instance;
HWND window;
BOOL drag_window = false;
SHORT mouse_x, mouse_y, mouse_x_prev, mouse_y_prev;
//Awesomium Variables
WebCore* webcore = 0;
WebView* webview;
static HWND InitWindow(INT width, INT height, WNDPROC callback)
{
HWND hwnd;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = callback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyUI";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
hwnd = CreateWindow("MyUI",
"",
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
NULL,
NULL,
GetModuleHandle(0),
NULL);
if (!hwnd)
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
SetTimer(hwnd, 0, 15, NULL);
return hwnd;
}
};
class LoginUI : public UI
{
public:
INT width = 600;
INT height = 600;
INT RunUI()
{
this->window = UI::InitWindow(this->width, this->height, ::LoginUICallback);
if (!this->window)
return 0;
WebConfig config;
this->webcore = WebCore::Initialize(config);
this->webview = this->webcore->instance()->CreateWebView(this->width, this->height, 0, kWebViewType_Window);
this->webview->set_parent_window(this->window);
this->webview->LoadURL(WebURL(WSLit("http://www.google.com")));
MSG msg;
while(GetMessage(&msg, this->window, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WebCore::Shutdown();
return 1;
}
}login_ui;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_TIMER:
break;
case WM_MOUSEMOVE:
{
if (login_ui.drag_window && (wParam & MK_LBUTTON))
{
// code executed when the dialog window is moved around on the screen
RECT win_rect;
GetWindowRect(hWnd, &win_rect);
int x_coord = GET_X_LPARAM(lParam);
int y_coord = GET_Y_LPARAM(lParam);
MoveWindow(hWnd,
win_rect.left + x_coord - login_ui.mouse_x_prev,
win_rect.top + y_coord - login_ui.mouse_y_prev,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
false
);
}
break;
}
case WM_LBUTTONDOWN:
{
login_ui.mouse_x = GET_X_LPARAM(lParam);
login_ui.mouse_y = GET_Y_LPARAM(lParam);
if (login_ui.mouse_y < 41)
{
login_ui.mouse_x_prev = login_ui.mouse_x;
login_ui.mouse_y_prev = login_ui.mouse_y;
SetCapture(hWnd);
login_ui.drag_window = true;
}
break;
}
case WM_LBUTTONUP:
{
if (login_ui.drag_window)
{
login_ui.drag_window = false;
ReleaseCapture();
}
break;
}
case WM_SIZE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_QUIT:
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Main.Cpp
#include "UI.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, char*, int nCmdShow)
{
login_ui.RunUI();
}
Have not used Awesomium but your GetMessage only pumps messages for the WebCore window. So instead you should pass NULL so your message pump dispatches messages for all windows created on that thread.
I am creating a simple window but when I see the window being created and closes it, not WM_QUIT message is ever gotten. Here's some code:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
cWindowApplication app(hInstance);
const long width = 1024L;
const long height = 768L;
if (app.CreateWindowApplication(width, height) == false)
{
MessageBox(NULL, "Unable to create OpenGL Window", "An error occurred", MB_ICONERROR | MB_OK);
app.DestroyWindowApplication();
return 1;
}
return app.MainLoop();
}
Here's the CreateWindowApplication(int, int) function:
bool cWindowApplication::CreateWindowApplication(long width, long height, bool full_screen /*= false*/)
{
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
mWindowRect.left = 0L; // Set Left Value To 0
mWindowRect.right = width; // Set Right Value To Requested Width
mWindowRect.top = 0L; // Set Top Value To 0
mWindowRect.bottom = height; // Set Bottom Value To Requested Height
mFullScreen = full_screen;
// fill out the window class structure
const char* class_name = "MyClass";
mWindowClass.cbSize = sizeof(WNDCLASSEX);
mWindowClass.style = CS_HREDRAW | CS_VREDRAW;
mWindowClass.lpfnWndProc = cWindowApplication::StaticWindowsProcessCallback;
mWindowClass.cbClsExtra = 0;
mWindowClass.cbWndExtra = 0;
mWindowClass.hInstance = mhInstance;
mWindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // default icon
mWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // default arrow
mWindowClass.hbrBackground = NULL; // don't need background
mWindowClass.lpszMenuName = NULL; // no menu
mWindowClass.lpszClassName = class_name;
mWindowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // windows logo small icon
// register the windows class
if (!RegisterClassEx(&mWindowClass))
{
return false;
}
if (mFullScreen == true) //If we are Full Screen, we need to change the display mode
{
DEVMODE dmScreenSettings; // device mode
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width; // screen width
dmScreenSettings.dmPelsHeight = height; // screen height
dmScreenSettings.dmBitsPerPel = BITS_PER_PIXEL; // bits per pixel
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
// setting display mode failed, switch to windowed
MessageBox(NULL, "Display mode failed", NULL, MB_OK);
mFullScreen = false;
}
}
if (mFullScreen == true) // Are We Still In Full Screen Mode?
{
dwExStyle = WS_EX_APPWINDOW; // Window Extended Style
dwStyle = WS_POPUP; // Windows Style
//ShowCursor(false); // Hide Mouse Pointer
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle = WS_OVERLAPPEDWINDOW; // Windows Style
}
AdjustWindowRectEx(&mWindowRect, dwStyle, false, dwExStyle); // Adjust Window To True Requested Size
// class registered, and create our window
mHWND = CreateWindowEx(NULL, // extended style
class_name, // class name
"My Windows", // application name
dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, // x,y coordinate
mWindowRect.right - mWindowRect.left,
mWindowRect.bottom - mWindowRect.top, // width, height
NULL, // handle to parent
NULL, // handle to menu
mhInstance, // application instance
this); // this pointer to call member functions
// check if window creation failed (hwnd would equal NULL)
if (mHWND == false)
{
return false;
}
mHDC = GetDC(mHWND);
ShowWindow(mHWND, SW_SHOW); // display the window
UpdateWindow(mHWND); // update the window
return true;
}
Basically after this function call, the CreateWindowEx() function will call StaticWindowProcessCallback() that looks like this:
LRESULT cWindowApplication::StaticWindowsProcessCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
cWindowApplication* win_app = NULL;
if (msg == WM_CREATE)
{
//Creation event
//Get the pointer we pass during CreateWindowApplication() call
win_app = (cWindowApplication*)((LPCREATESTRUCT)lParam)->lpCreateParams;
//Associate window pointer with the hwnd for the other events to access
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)win_app);
}
else
{
//Non-creation event
win_app = (cWindowApplication*)GetWindowLongPtr(wnd, GWLP_USERDATA);
if (win_app != NULL)
{
return DefWindowProc(wnd, msg, wParam, lParam);
}
}
//call member
return win_app->WindowsProcessCallback(wnd, msg, wParam, lParam);
}
Finally, the last line of this function calls the member function WindowProcessCallback() that looks like this:
LRESULT cWindowApplication::WindowsProcessCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
mHDC = GetDC(wnd);
SetupPixelFormat();
//Set the version that we want, in this case 3.0
int attribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 0, 0 }; //zero indicates the end of the array
//Create temporary context so we can get a pointer to the function
HGLRC tmp_context = wglCreateContext(mHDC);
//Make it current
wglMakeCurrent(mHDC, tmp_context);
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
if (wglCreateContextAttribsARB == NULL)
{
//No OpenGL 3.0, back to 2.0
mHGLRC = tmp_context;
}
else
{
//Create OpenGL 3.0
mHGLRC = wglCreateContextAttribsARB(mHDC, 0, attribs);
//Delete the temp context
wglDeleteContext(tmp_context);
}
//Make OpenGL 3.0
wglMakeCurrent(mHDC, mHGLRC);
mIsRunning = true;
}
break;
case WM_QUIT:
case WM_DESTROY:
case WM_CLOSE:
wglMakeCurrent(mHDC, NULL);
wglDeleteContext(mHGLRC);
mIsRunning = false;
PostQuitMessage(0); //Send a WM_QUIT message
return 0;
default:
break;
}
return DefWindowProc(wnd, msg, wParam, lParam);
}
As you can see, there are some message processing code there ... but other than the WM_CREATE, no other cases are being hit. After the WM_CREATE message being sent, the function MainLoop() is being called that looks like this:
int cWindowApplication::MainLoop()
{
while (mIsRunning == true)
{
ProcessWindowsMessages();
}
DestroyWindowApplication();
return 0;
}
Basically the ProcessWindowsMessages() function does not get any message after the window closes ... I have to press stop VS from running in order to kill the process. The ProcessWindowsMessages() function looks like this:
void cWindowApplication::ProcessWindowsMessages()
{
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
This logic in StaticWindowsProcessCallback looks backwards:
if (win_app != NULL)
{
return DefWindowProc(wnd, msg, wParam, lParam);
}
If you don't have a pointer to the window wrapper object, you'll need to call DefWindowProc. So that should happen if (win_app == NULL). This is to handle a handful of messages that are sent before WM_CREATE. As a result of this, your code has undefined behavior on messages processed before WM_CREATE, and discards (by applying default processing) all messages after WM_CREATE.
It would be even better to use WM_NCCREATE for setting up the link, though. As well, win_app is not a very good name for this, maybe win_obj or something.
You also shouldn't handle WM_QUIT in your window procedure, since it isn't sent to a window. And the default behavior of WM_CLOSE should be fine, it will call DestroyWindow which will trigger WM_DESTROY.
But the first, failure to forward any messages after WM_CREATE to your window procedure, likely explains your lack of WM_QUIT in the main message loop.
In my application I'm loading (for example) Device_Manager.dll and this Device_Manager depend on the selected model start to load the correct Devices.dll.
In my Device_Manager.dll, I created a window to use its handle later on my Devices because Devices uses this handle when they want to send messages to the application.
So, I made the new thread in my Device_Manager.dll to get these message when ever they arrive!
(I'm also using QT for create/load .dlls.)
After I created a thread, I received this error:
Windows has triggered a breakpoint in sepanta.agent.exe.
This may be due to a corruption of the heap, which indicates a bug in sepanta.agent.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while sepanta.agent.exe has focus.
The output window may have more diagnostic information.
I use these two methods to initialize and start my device manager:
(These methods are called in the main application after I successfully load the .dll.)
bool DeviceManagerPlugin::initializeDeviceManager()
{
EventManager pEventManager = new EventManager();
bool init_result = pEventManager->initilize_window();
...
if(initilize_status == S_OK)
{
return true;
}
else
{
return false;
}
}
void DeviceManagerPlugin::startDeviceManager()
{
handle_of_thread = 0;
int data_of_thread = 1;
handle_of_thread = CreateThread(NULL, 0,listenToIncomingWFSMessages2, &data_of_thread, 0, NULL);
my_thread_handle = handle_of_thread;
}
This is my EventManager class, which created windows:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
...
default:
return DefWindowProc(hWnd, msg, wParam, lParam );
}
}
bool EventManager::initialize_window()
{
WNDCLASS Wclass;
HWND gHwnd = NULL;
HINSTANCE gHinstance = NULL;
ZeroMemory(&Wclass, sizeof(WNDCLASS));
Wclass.hInstance = gHinstance;
Wclass.cbClsExtra = 0;
Wclass.cbWndExtra = 0;
Wclass.lpszClassName = TEXT("Device_Manager_Class_Name");
Wclass.lpszMenuName = NULL;
Wclass.lpfnWndProc = WndProc;
Wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
Wclass.hCursor = LoadIcon(NULL, IDC_ARROW);
Wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Wclass.style = CS_OWNDC;
if(!RegisterClass(&Wclass))
{
cout<<"Unable to Register Class";
return false;
}
ULONG Window_Width;
ULONG Window_Height;
DWORD style;
bool full_screen = false;
if(full_screen)
{
Window_Width = GetSystemMetrics(SM_CXSCREEN);
Window_Height = GetSystemMetrics(SM_CYSCREEN);
style = WS_POPUP;
}
else
{
Window_Width = SCREEN_WIDTH;
Window_Height = SCREEN_HEIGHT;
style = WS_OVERLAPPED|WS_SYSMENU;
}
gHwnd = CreateWindow(TEXT("Device_Manager_Class_Name")
, TEXT("Device_Manager_Class_Title")
, style
, 0
, 0
, Window_Width
, Window_Height
, GetDesktopWindow()
, NULL
, gHinstance
, NULL);
if(!gHwnd)
{
cout<<"Unable to create the main window";
return false;
}
//ShowWindow(gHwnd, SW_SHOW);
//UpdateWindow(gHwnd);
//SetFocus(gHwnd);
return true;
}
DWORD WINAPI listenToIncomingWFSMessages2(LPVOID lpParam)
{
MSG msg;
SecureZeroMemory(&msg, sizeof(MSG));
BOOL bRet;
HWND windows_handle;
SecureZeroMemory(&windows_handle, sizeof(HWND));
windows_handle = FindWindow(TEXT("Device_Manager_Class_Name"), 0);
while( (bRet = GetMessage( &msg, windows_handle, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
What am I doing wrong here? What did I miss? If you have a better solution for what I'm about to do, please feel free to share it with me.
Okay, i can understand if the function would return an error or throw an exception, but for some reason my call to DestroyWindow literally exits the program at that point. Like with the actual exit() function changing my program flow. The documentation mentions nothing like this and i have no means of figuring out what is going on since i get no error code. Has anyone ever encountered something like this?
I'm doing quite a bit more with this object than using winapi, so ignore the rest of it. What else could be wrong here?
SYNC_WinSystem.h
#ifndef SYNC_WINSYSTEM_H
#define SYNC_WINSYSTEM_H
#include "SYNC_ISystem.h"
#include <Windows.h>
#include <array>
#include "SYNC_Winput.h"
#include "SYNC_IRenderer.h"
#include "SYNC_D3D11Renderer.h"
#define FULL_SCREEN true
// SYNC_WinSystem
class SYNC_WinSystem : public SYNC_ISystem
{
public:
class WindowsContext;
SYNC_WinSystem();
virtual long Initialize(InitializeContext *);
virtual void Init_Loop();
virtual void Shutdown();
virtual long MakeDirectory(std::string);
virtual bool CreateSkin(std::string, std::string, SYNC::ISkin *&);
virtual ISound * CreateSound();
LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
private:
virtual long InitializeWindows();
virtual bool Frame();
virtual void ShutdownWindows();
private:
SYNC_Winput m_Input;
private:
std::shared_ptr<SYNC_IRenderer> m_Graphics;
HINSTANCE m_hinstance;
HWND m_hwnd;
int m_screenWidth;
int m_screenHeight;
std::string m_WindowName;
};
// SYNC_WinSystem::WindowsContext
class SYNC_WinSystem::WindowsContext : public SYNC_ISystem::InitializeContext
{
public:
WindowsContext();
std::string Type();
HINSTANCE m_hinstance;
std::string m_WindowName;
private:
const static std::string m_Identifier;
};
#endif
SYNC_WinSystem.cpp
#include "SYNC_WinSystem.h"
// SYNC_WinSystem definitions
SYNC_WinSystem * g_windows;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
SYNC_WinSystem::SYNC_WinSystem()
: m_Graphics(new SYNC_D3D11Renderer)
{
m_hinstance = nullptr;
m_hwnd = nullptr;
m_screenWidth = 0;
m_screenHeight = 0;
}
long SYNC_WinSystem::Initialize(InitializeContext * context)
{
long result = 0;
char errors[256];
WindowsContext * cContext;
if(context->Type() == "WindowsContext")
cContext = static_cast<WindowsContext *>(context);
else
return false;
m_hinstance = cContext->m_hinstance;
m_WindowName = cContext->m_WindowName;
g_windows = this;
result = InitializeWindows();
if(result)
{
sprintf_s(errors, "The Window could not initialize. Windows error code: %i", result);
MessageBox(NULL, errors, "Error!", MB_OK);
return result;
}
std::array<std::string, 3> folderNames=
{{
"Compiled_Models",
"Temp_Models",
"Materials"
}};
for(int i = 0; i < (int) folderNames.size(); i++)
{
result = MakeDirectory(folderNames[i]);
if( result && (result != ERROR_ALREADY_EXISTS))
{
sprintf_s(errors, "Error creating directory \" %s \" for system. Windows error code: %i", folderNames[i].c_str(), result);
MessageBox(NULL, errors, "Error!", MB_OK);
return result;
}
result = 0;
}
SYNC_D3D11Renderer::D3D11Context graphicsContext;
graphicsContext.fullscreen = true;
graphicsContext.hwnd = m_hwnd;
graphicsContext.screenDepth = 1000.0f;
graphicsContext.screenNear = 0.1f;
graphicsContext.screenWidth = m_screenWidth;
graphicsContext.screenHeight = m_screenHeight;
if(!m_Graphics->Initialize(&graphicsContext))
return false;
return result;
}
void SYNC_WinSystem::Init_Loop()
{
MSG msg;
bool done, result;
ZeroMemory(&msg, sizeof(MSG));
done = false;
while(!done)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(m_Input.IsKeyPressed(VK_ESCAPE))
{
done = true;
}
else
{
result = Frame();
if(!result)
{
done = true;
}
}
}
}
void SYNC_WinSystem::Shutdown()
{
ShutdownWindows();
}
long SYNC_WinSystem::MakeDirectory(std::string dirName)
{
DWORD result = 0;
long returnValue = 0;
dirName.insert(0, ".\\");
result = CreateDirectory(dirName.c_str(), NULL);
if(result == 0)
{
returnValue = GetLastError();
}
return returnValue;
}
bool SYNC_WinSystem::Frame()
{
if(!m_Graphics->Frame())
return false;
return true;
}
long SYNC_WinSystem::InitializeWindows()
{
DWORD result = 0;
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = &WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hinstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = m_WindowName.c_str();
wc.cbSize = sizeof(WNDCLASSEX);
if(RegisterClassEx(&wc) == 0)
{
result = GetLastError();
return result;
}
m_screenWidth = GetSystemMetrics(SM_CXSCREEN);
m_screenHeight = GetSystemMetrics(SM_CYSCREEN);
if(FULL_SCREEN)
{
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long) m_screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long) m_screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
posX = posY = 0;
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW,
m_WindowName.c_str(),
m_WindowName.c_str(),
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, m_screenWidth, m_screenHeight,
NULL, NULL, m_hinstance, NULL);
}
else
{
m_screenWidth = 800;
m_screenHeight = 600;
posX = ((GetSystemMetrics(SM_CXSCREEN)/2) - (m_screenWidth/2));
posY = ((GetSystemMetrics(SM_CYSCREEN)/2) - (m_screenHeight/2));
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW,
m_WindowName.c_str(),
m_WindowName.c_str(),
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, m_screenWidth, m_screenHeight,
NULL, NULL, m_hinstance, NULL);
}
if(!m_hwnd)
{
result = GetLastError();
return result;
}
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
SetFocus(m_hwnd);
return result;
}
void SYNC_WinSystem::ShutdownWindows()
{
ShowCursor(true);
if(FULL_SCREEN)
{
ChangeDisplaySettings(NULL, 0);
}
if(DestroyWindow(m_hwnd) == 0)
{
char meh[256];
sprintf(meh, "error: %i" , GetLastError());
MessageBox(NULL, meh, "error!", MB_OK);
}
m_hwnd = NULL;
UnregisterClass(m_WindowName.c_str(), m_hinstance);
m_hinstance = NULL;
g_windows = NULL;
return;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
default:
{
return g_windows->MessageHandler(hwnd, msg, wparam, lparam);
}
}
}
LRESULT CALLBACK SYNC_WinSystem::MessageHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_KEYDOWN:
{
m_Input.KeyDown((unsigned int) wparam);
return 0;
}
case WM_KEYUP:
{
m_Input.KeyDown((unsigned int) wparam);
return 0;
}
default:
{
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
}
ISound * SYNC_WinSystem::CreateSound()
{
return nullptr;
}
bool SYNC_WinSystem::CreateSkin(std::string filename, std::string shaderName, SYNC::ISkin *& skin)
{
if(!m_Graphics->CreateSkin(filename, shaderName, skin))
return false;
return true;
}
// SYNC_WinSystem::WindowsContext definitions
const std::string SYNC_WinSystem::WindowsContext::m_Identifier = "WindowsContext";
SYNC_WinSystem::WindowsContext::WindowsContext()
{
}
std::string SYNC_WinSystem::WindowsContext::Type()
{
return m_Identifier;
}
quick explanation of how i do this. window handle and hinstance have private members in the object, and during the Initialize() and InitializeWindows() functions, the window class and window itself is created. The windows procedure is defined below as a global function, because you can't use a member function as a windows procedure. I dodge around this by making a global pointer (gasp) at the top, and assigning it to the this pointer of the system, which allows the procedure to call a member function procedure. Still only allows one instance of the system, but that's all i need :. Anywho, during shutdown, ShutdownWindows() is called, which then calls DestroyWindow. It is during this call, that my program simply ends, no error, no exception. MSVC++ express tells me it returns error code 3, but as far as windows error codes, that's just an ERROR_PATH_NOT_FIND which makes no sense in this context. Anyone have a clue?
main.cpp
#include <memory>
#include <Windows.h>
#include "Syncopate.h"
#include "SYNC_WinSystem.h"
using namespace std;
#include "SYNC_Winput.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR lpCmdLine, INT nCmdShow)
{
//create a new instance of the engine
std::shared_ptr<SYNC_WinSystem> system( new SYNC_WinSystem);
// create an init context for this specific derivative of SYNC_ISystem
SYNC_WinSystem::WindowsContext context;
context.m_hinstance = hInstance;
context.m_WindowName = "Syncopate";
// Initialize the system object. if something goes wrong, return ERROR
if(system->Initialize(&context))
return 1;
SYNC::ISkin * model;
if(!system->CreateSkin("data.txt", "ColorShader", model))
return 1;
system->Init_Loop();
system->Shutdown();
return 0;
}
There's nothing in your message loop that will notice a WM_QUIT and abort. The "standard" practice for a message loop is to call GetMessage() until it fails, which indicates WM_QUIT, but you're calling PeekMessage() which has no handling for WM_QUIT at all. Your message loop only exits when done is true, which will only happen when escape is pressed or your Frame() call fails.
As you discovered, the solution was to redesign your loop to properly handle WM_QUIT messages and to not call DestroyWindow after the loop has already ended.
What seems to be going on is that you handle the WM_DESTROY message and explicitly call PostQuitMessage. I suspect somewhere that WM_QUIT message is being processed and causing an exit of some sort. I'll see if I can find any further information, but that's my understanding so far.
Rule of Thumb:
When you receive a WM_CLOSE message, call DestroyWindow. When you receive a WM_DESTROY message, call PostQuitMessage. Because you are using PeekMessage, you will get a message structure for a WM_QUIT message. When you find this message, you should end your loop.
IIRC exit code 3 is what you get by calling abort.
Anyway,
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
is very ungood (it terminates your message loop), and most likely the cause of your problems.
Just remove that.
Update: since the above recommendation didn't improve things, I suspect that you're calling DestroyWindow on an already destroyed window.
As a rule you should only call DestroyWindow in response to WM_CLOSE. For general windows that's the default handling. There is no indication in the presented code (as I'm writing this) of how your "shutdown" code is called, but due to the identical handling of WM_CLOSE and WM_DESTROY I suspect that it's a call placed after the message loop.
And in that case it is indeed likely that you're calling DestroyWindow on an already destroyed window.