i've created s simple W32 application to cicle through two applications(hard coded window classes atm).
When i call the start button (IDC_Start) everything works fine, but when i change the focus to
hwnd the application hangs an cannot be closed. I just need a simple and clean method to
stop the loop, that start when calling IDC_Start. Any Help would be greatly apreciated!
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <resource.h>
#include <iostream>
using namespace std;
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
HWND hwnd1,hwnd2;
hwnd1 = FindWindow("Notepad++",0);
hwnd2 = FindWindow("Notepad",0);
BOOL bDone;
switch(Message)
{
case WM_INITDIALOG:
// This is where we set up the dialog box, and initialise any default values
{
SetDlgItemInt(hwnd, IDC_NUMBER, 5, FALSE);
HICON hIcon, hIconSm;
hIcon = (HICON)LoadImage(NULL, "e32.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
if(hIcon)
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
else
MessageBox(hwnd, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR);
hIconSm = (HICON) LoadImage(NULL, "e16.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
if(hIconSm)
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
else
MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_START:
{
BOOL bSuccess;
int nDelay = GetDlgItemInt(hwnd, IDC_NUMBER, &bSuccess, FALSE);
nDelay= nDelay*1000;
int i=1;
ShowWindow(hwnd,SW_MINIMIZE);
if(bSuccess)
{
if (hwnd1 != 0&&hwnd2 != 0)
{
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
while(i)
{
if(bDone!=TRUE)
{
SetDlgItemInt(hwnd, IDC_SHOWCOUNT, nDelay/1000, FALSE);
Sleep(nDelay);
SetForegroundWindow(hwnd1);
Sleep(nDelay);
SetForegroundWindow(hwnd2);
i++;
}
else
{
SetThreadExecutionState(ES_CONTINUOUS);
MessageBox(hwnd, "Stopped", "Warning", MB_OK);
break;
}
}
}
else
{
MessageBox(hwnd,"Cannot find suitable Window","AppDia",MB_OK);
}
}
else
{
MessageBox(hwnd, "Number not identified", "Warning", MB_OK);
}
}
break;
case IDC_STOP:
bDone==TRUE;
break;
}
break;
case WM_CLOSE:
EndDialog(hwnd, 0);
break;
default:
return FALSE;
}
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DlgProc);
}
Your logic loops with Sleeps, it doesn't give the dialog box a way to process it's messages, so it seems to hang -- try using a Timer instead, with something like:
static BOOL bWnd1 = TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{ case IDC_START:
{ int nDelay = GetDlgItemInt(hwnd, IDC_NUMBER, &bSuccess, FALSE);
nDelay= nDelay*1000;
ShowWindow(hwnd,SW_MINIMIZE);
SetTimer(hwnd, 1, nDelay, NULL);
break;
}
case IDC_STOP:
KillTimer(hwnd, 1);
break;
}
break;
case WM_TIMER:
{ HWND hwnd = (bWnd1 ? FindWindow("Notepad++",0) : FindWindow("Notepad",0));
SetForegroundWindow(hwnd);
bWnd1 = !bWnd1;
break;
}
case WM_CLOSE:
KillTimer(hwnd, 1);
EndDialog(hwnd, 0);
break;
default:
return FALSE;
This is just a sample code, you'll need to add error checking to it...
Related
I had another SO question and people there helped me solve an issue. I don't understand what DialogProc is supposed to return on each case. What does DialogProc returning TRUE mean? How does it compare to FALSE? What's the difference?
MSDN states that there is no return value.
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
wchar_t c0_txt[] = L"Title";
LVCOLUMNW col{};
col.mask = LVCF_TEXT | LVCF_WIDTH | LVIF_IMAGE;
col.cx = 60;
col.pszText = c0_txt;
ListView_InsertColumn(GetDlgItem(hWnd, IDC_LIST1), 0, &col);
return TRUE;
}
case WM_NCDESTROY:
PostQuitMessage(0);
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
DestroyWindow(hWnd);
break;
default:
break;
}
break;
case WM_SIZE:
{
const int width = LOWORD(lParam);
const int height = HIWORD(lParam);
// IDC_LIST1 will occupy the entire client area of its parent.
// Adjust as needed.
MoveWindow(GetDlgItem(hWnd, IDC_LIST1),
0, 0, width, height, TRUE);
return TRUE;
}
default:
return FALSE;
}
return TRUE;
}
int WINAPI WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nShowCmd
)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
HWND hWnd = CreateDialogParamW(hInstance, MAKEINTRESOURCEW(IDD_MAIN), nullptr, &DialogProc, 0);
if (!hWnd)
{
MessageBoxW(nullptr, L"Dialog Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
MSG msg;
while (GetMessageW(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
The basic idea is that you have a default: return FALSE;, while each case: returns TRUE. But Windows doesn't read your code. Windows doesn't even require your code to be written in C++, and other languages may implement the same idea in other ways. That's why the documentation describes the behavior, not how you should implement it.
The code below should create a simple window with a menu, static text, and an edit box but When I try to create an edit box it either does not run at all (with no errors) or when it does run and I try to click on the edit box the window closes. I am really stuck and any help would be greatly appreciated! Side note: I am a beginner at winapi/gui's with c++ so please be respectful.
#include <Windows.h>
#include <iostream>
#define FILE_MENU_NEW 1
#define FILE_MENU_OPEN 2
#define FILE_MENU_EXIT 3
struct WindowPosition
{
int x, y = 0;
} winPos;
struct WindowSize
{
int width = 600;
int height = 500;
} winSize;
HMENU hMenu;
// Window proc function
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void addMenus(HWND);
void AddControls(HWND);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow)
{
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc))
{
return -1;
}
CreateWindowW(L"myWindowClass", L"My Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, winPos.x, winPos.y, winSize.width, winSize.height,
NULL, NULL, NULL, NULL);
// Window loop
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
if (wp == 1)
{
MessageBeep(MB_OK);
}
else if (FILE_MENU_EXIT)
{
DestroyWindow(hWnd);
}
break;
case WM_CREATE:
addMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
}
void addMenus(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_NEW, L"New");
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_OPEN, L"Open");
AppendMenu(hFileMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_EXIT, L"Exit");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"File");
AppendMenu(hMenu, MF_STRING, 2, L"Help");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd)
{
CreateWindowW(L"static", L"Username: ", WS_VISIBLE | WS_CHILD, 200, 100, 100, 50, hWnd, NULL, NULL, NULL);
// This is where the problem is... (When I remove the second parameter and put L"Enter Username") the program does not run at all.
CreateWindowW(L"edit", NULL, WS_VISIBLE | WS_CHILD, 0, 0, 100, 50, hWnd, NULL, NULL, NULL);
}
When you use else if (FILE_MENU_EXIT), this result is always true. You can try:
case WM_COMMAND:
if (wp == 1)
{
MessageBeep(MB_OK);
}
else if (wp == FILE_MENU_EXIT)
{
DestroyWindow(hWnd);
}
break;
Also you can use:
case WM_COMMAND:
switch (wp)
{
case FILE_MENU_NEW:
MessageBeep(MB_OK);
break;
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
break;
}
break;
so a quick rundown of the Win32 app I'm making. It's basically supposed to change refresh rate between 60 and 144 Hz based on whether or not the laptop is plugged in. When I launch the app, the GUI starts but it crashes. I'll post the code and debug below.
#ifndef UNICODE
#define UNICODE
#define UNICODE_WAS_UNDEFINED
#endif
#include <Windows.h>
#ifdef UNICODE_WAS_UNDEFINED
#undef UNICODE
#endif
#include <iostream>
using namespace std;
BOOL checked = FALSE;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
WNDCLASS wc = { 0 };
wc.lpszClassName = L"autoRefresh";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
HWND hWnd = CreateWindowW(wc.lpszClassName, L"Refresh Changer", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 860, 540, 500, 150, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
RegisterPowerSettingNotification(hWnd, &GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
DEVMODE dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
switch (msg) {
case WM_CREATE: {
CreateWindow(TEXT("button"), TEXT("Enable automatic refresh rate changer (Will run at startup)"), WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 20, 20, 500, 35, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
break;
}
case WM_COMMAND: {
OutputDebugStringW(L"WM_COMMAND case\n");
checked = IsDlgButtonChecked(hwnd, 1);
if (checked) {
OutputDebugStringW(L"Box unchecked\n");
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
checked = FALSE;
}
else {
OutputDebugStringW(L"Box checked\n");
CheckDlgButton(hwnd, 1, BST_CHECKED);
checked = TRUE;
}
break;
}
case WM_POWERBROADCAST: {
OutputDebugStringW(L"WM_BROADCAST case\n");
if (checked) {
OutputDebugStringW(L"WM_BROADCAST checked is TRUE\n");
//std::wstring progPath = L"C:\\Users\\user\\AppData\\Roaming\\Microsoft\\Windows\\RefreshChanger.exe";
//HKEY hkey = NULL;
//LONG createStatus = RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &hkey); //Creates a key
//LONG status = RegSetValueEx(hkey, L"RefreshChanger", 0, REG_SZ, (BYTE*)progPath.c_str(), (progPath.size() + 1) * sizeof(wchar_t));
SYSTEM_POWER_STATUS powerStatus;
GetSystemPowerStatus(&powerStatus);
if (powerStatus.ACLineStatus == 1) {
OutputDebugStringW(L"Refresh rate before changing: " + dm.dmDisplayFrequency);
dm.dmDisplayFrequency = 144;
LONG ret = ChangeDisplaySettingsEx(NULL, &dm, NULL, 0, NULL);
OutputDebugStringW(L"ChangeDisplaySettingsEx returned " + ret);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
OutputDebugStringW(L"Refresh rate after changing: " + dm.dmDisplayFrequency);
}
switch (ret) {
case DISP_CHANGE_SUCCESSFUL:
OutputDebugStringW(L"Display successfully changed\n");
break;
case DISP_CHANGE_BADDUALVIEW:
OutputDebugStringW(L"The settings change was unsuccessful because the system is DualView capable\n");
break;
case DISP_CHANGE_BADFLAGS:
OutputDebugStringW(L"An invalid set of flags was passed in.\n");
break;
case DISP_CHANGE_BADMODE:
OutputDebugStringW(L"The graphics mode is not supported.\n");
break;
case DISP_CHANGE_BADPARAM:
OutputDebugStringW(L"An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n");
break;
case DISP_CHANGE_FAILED:
OutputDebugStringW(L"The display driver failed the specified graphics mode.\n");
break;
case DISP_CHANGE_NOTUPDATED:
OutputDebugStringW(L"Unable to write settings to the registry.\n");
break;
case DISP_CHANGE_RESTART:
OutputDebugStringW(L"The computer must be restarted for the graphics mode to work.\n");
break;
}//switch
}
else {
OutputDebugStringW(L"WM_BROADCAST checked is FALSE\n");
OutputDebugStringW(L"Refresh rate before changing: " + dm.dmDisplayFrequency);
dm.dmDisplayFrequency = 60;
LONG ret = ChangeDisplaySettingsEx(NULL, &dm, NULL, 0, NULL);
OutputDebugStringW(L"ChangeDisplaySettingsEx returned " + ret);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
OutputDebugStringW(L"Refresh rate after changing: " + dm.dmDisplayFrequency);
}
switch (ret) {
case DISP_CHANGE_SUCCESSFUL:
OutputDebugStringW(L"Display successfully changed\n");
break;
case DISP_CHANGE_BADDUALVIEW:
OutputDebugStringW(L"The settings change was unsuccessful because the system is DualView capable\n");
break;
case DISP_CHANGE_BADFLAGS:
OutputDebugStringW(L"An invalid set of flags was passed in.\n");
break;
case DISP_CHANGE_BADMODE:
OutputDebugStringW(L"The graphics mode is not supported.\n");
break;
case DISP_CHANGE_BADPARAM:
OutputDebugStringW(L"An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n");
break;
case DISP_CHANGE_FAILED:
OutputDebugStringW(L"The display driver failed the specified graphics mode.\n");
break;
case DISP_CHANGE_NOTUPDATED:
OutputDebugStringW(L"Unable to write settings to the registry.\n");
break;
case DISP_CHANGE_RESTART:
OutputDebugStringW(L"The computer must be restarted for the graphics mode to work.\n");
}//switch
}//if/else
}//if checked
}//case
case WM_DESTROY: {
OutputDebugStringW(L"WM_DESTROY case\n");
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
And here's a screenshot of the debug console:
When I unplug the charger, the GUI crashes. It will run from being unplugged, but it also crashes when I plug the charger in. The refresh rate isn't changed and WM_DESTROY gets called, even though I'm not clicking the X at the top of the window. I'm super new to Win32 so I'm sorry if I'm missing something super simple. My background is primarily in Android development. Thanks for any help!
You're not breaking out of your outer switch/case so you're falling through into the WM_DESTROY case.
I hope you dont mind me asking here, code review stackexchange did only want to help with working code.
I'm trying to understand why a program written in C++ can be ran perfectly through Visual Studio's 'Local Window Debugger' and when I build it and run the .exe file, the window opens and immediately closes.
Can someone tell me or better show me where the error is?
The game I am trying to get working is this: https://github.com/Zolomon/labyrinth. It's a labyrinth written in C++, uses the windows API.
Any help to identify the problem would be greatly appreciated!
#include <Windows.h>
#include <tchar.h>
#include <vector>
#include <chrono>
#include <memory>
#include "WindowOptions.h"
#include "Entity.h"
#include "Game.h"
#include "Level.h"
#include "Utils.h"
HWND btnNorth = NULL;
HWND btnEast = NULL;
HWND btnSouth = NULL;
HWND btnWest = NULL;
const int ID_OPEN = 1;
const int ID_QUIT = 2;
const int ID_ABOUT = 3;
const int BTN_NORTH_ID = 4;
const int BTN_EAST_ID = 5;
const int BTN_SOUTH_ID = 6;
const int BTN_WEST_ID = 7;
std::shared_ptr<Game> game;
std::weak_ptr<Game> wGame;
std::vector<int> WindowOption::ButtonIDs = []()->std::vector < int > {
std::vector<int> v;
v.push_back(BTN_NORTH_ID);
v.push_back(BTN_EAST_ID);
v.push_back(BTN_SOUTH_ID);
v.push_back(BTN_WEST_ID);
return v;
}();
std::vector<Entity*> entities;
HMENU CreateMainMenu()
{
HMENU file = CreateMenu();
AppendMenu(file, MF_STRING, ID_OPEN, _T("&New"));
AppendMenu(file, MF_SEPARATOR, 0, 0);
AppendMenu(file, MF_STRING, ID_QUIT, _T("&Quit"));
HMENU help = CreateMenu();
AppendMenu(help, MF_STRING, ID_ABOUT, _T("&About"));
HMENU main = CreateMenu();
AppendMenu(main, MF_POPUP, (UINT_PTR)file, _T("&File"));
AppendMenu(main, MF_POPUP, (UINT_PTR)help, _T("&Help"));
return main;
}
void SetupButtons(HWND hwnd, HINSTANCE hInstance) {
HFONT font = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
std::vector<HWND*> buttons;
buttons.push_back(&btnNorth);
buttons.push_back(&btnEast);
buttons.push_back(&btnSouth);
buttons.push_back(&btnWest);
size_t btnIndex = 0;
for (HWND* btn : buttons) {
int x, y;
std::tie(x, y) = WindowOption::ButtonPositions[btnIndex];
wchar_t* name = WindowOption::ButtonLabels[btnIndex];
*btn = CreateWindow(
_T("BUTTON"),
name,
WS_CHILD | WS_VISIBLE,
x, y,
WindowOption::ButtonWidth, WindowOption::ButtonHeight,
hwnd,
(HMENU)WindowOption::ButtonIDs[btnIndex],
hInstance, NULL);
SendMessage(*btn, WM_SETFONT, (WPARAM)font, NULL);
btnIndex++;
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
// TODO: fix duplication, casting char/ID to enum directly.
switch (msg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_QUIT:
PostQuitMessage(0);
return 0;
break;
case ID_ABOUT: {
std::wstring about( _T("You are a lonely duck trying to get home. \r\n"));
about += std::wstring(_T("Can you reach the exit in least amount of steps?\r\n"));
about += std::wstring(_T("Use the buttons or WASD-keys to explore the maze!\r\n"));
MessageBox(hwnd, about.c_str(), _T("About Labyrinth"), MB_OK);
}
break;
case ID_OPEN:
game->Start();
break;
case BTN_NORTH_ID:
game->ProcessInput(Command::MoveNorth);
break;
case BTN_EAST_ID:
game->ProcessInput(Command::MoveEast);
break;
case BTN_SOUTH_ID:
game->ProcessInput(Command::MoveSouth);
break;
case BTN_WEST_ID:
game->ProcessInput(Command::MoveWest);
break;
}
break;
case WM_KEYDOWN:
switch (wParam) {
case 'W':
game->ProcessInput(Command::MoveNorth);
break;
case 'D':
game->ProcessInput(Command::MoveEast);
break;
case 'S':
game->ProcessInput(Command::MoveSouth);
break;
case 'A':
game->ProcessInput(Command::MoveWest);
break;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
}
break;
case WM_ERASEBKGND:
return 1;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void Render(double interpolation) {
game->Render(interpolation);
}
void processInput(const std::shared_ptr<Game>& game, MSG* msg) {
while (PeekMessage(msg, NULL, NULL, NULL, PM_REMOVE)) {
if (msg->message == WM_QUIT) {
WindowOption::IsRunning = false;
}
TranslateMessage(msg);
DispatchMessage(msg);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
wchar_t className[] = _T("LabyrinthClass");
wchar_t windowName[] = _T("Labyrinth");
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = className;
RegisterClass(&wc);
HWND hwnd = CreateWindow(
className,
windowName,
WS_OVERLAPPEDWINDOW,
WindowOption::StartPositionX, WindowOption::StartPositionY,
WindowOption::WIDTH, WindowOption::HEIGHT,
NULL,
CreateMainMenu(),
hInstance, NULL);
SetupButtons(hwnd, hInstance);
UpdateWindow(hwnd);
ShowWindow(hwnd, nCmdShow);
game = std::make_shared<Game>();
game->InitializeGraphics(hwnd);
std::shared_ptr<Level> level0 = Utils::loadLevel(std::string("levels/level0.txt"));
game->AddLevel(level0);
game->Start();
MSG msg = { 0 };
const double FRAMES_PER_SEC = 60.0;
const double SEC_PER_UPDATE = 1.0 / FRAMES_PER_SEC;
auto previousTime = WindowOption::clock.now();
double lag = 0.0;
while (WindowOption::IsRunning) {
auto currentTime = WindowOption::clock.now();
auto deltaTime = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - previousTime).count();
previousTime = currentTime;
processInput(game, &msg);
Render(1.0);
game->CheckWinningCondition();
if (SEC_PER_UPDATE - deltaTime > 0)
Sleep(SEC_PER_UPDATE - deltaTime);
}
return msg.wParam;
}
Please add the resource file that needs to be loaded to run the exe file.
Include "levels file folder", "end.bmp", "grass.bmp", "player.bmp","start.bmp","wall.bmp".(They are all in the labyrint folder)
You can simply copy these bmp images and file to the generated Debug/Release file directory.
When you have added these files, the exe file will work well.
I'm trying to create an OpenGL context with WinAPI, it works great, but I think I messed up something, because when I click on the upper bar (where close button, minimize button is), it calls the ResizeWindow function somehow...Image showing this
Here is my main function:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
GLWindow *window = new GLWindow();
Event *evt = new Event();
window->Create("OpenGL Window", 800, 600, 32);
while (window->IsRunning())
{
evt->Clear();
while (window->DispatchEvent(evt))
{
}
Render();
window->Present();
}
delete evt;
delete window;
}
Event is just a class with a map for containing event params. I removed every event handling in WndProc so it couldn't be a problem
Window creation code:
bool GLWindow::Create(char* title, int width, int height, int bits)
{
GLuint PixelFormat;
WNDCLASS wClass;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.top = (long)0;
WindowRect.right = (long)width;
WindowRect.bottom = (long)height;
hInstance = GetModuleHandle(NULL);
wClass.cbClsExtra = 0;
wClass.cbWndExtra = 0;
wClass.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
wClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wClass.hInstance = hInstance;
wClass.lpfnWndProc = &GLWindow::WndProc;
wClass.lpszClassName = "GL";
wClass.lpszMenuName = NULL;
wClass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
dwStyle = WS_OVERLAPPEDWINDOW;
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
if (!RegisterClass(&wClass))
{
MessageBox(NULL, "Error! Cannot register window class!", "ERROR", MB_OK);
return 0;
}
AdjustWindowRectEx(&WindowRect, dwStyle, false, dwExStyle);
if (!(hWnd = CreateWindowEx(
dwExStyle,
"GL",
"Title",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
0,
0,
WINDOW_WIDTH,
WINDOW_HEIGHT,
NULL,
NULL,
hInstance,
NULL)))
{
KillWindow();
MessageBox(NULL, "Window creation error.", "Error", MB_OK);
return false;
}
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1, //Version number
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA, //Formats
bits, //color depth
0, 0, 0, 0, 0, 0, //color bits ignored
0, //no alpha buffer
0, //shift bit ignored
0, //no accumulation buffer
0, 0, 0, 0, //accumulation bits ignored
16, //16bit Zbuffer (depth buffer)
0, //no stencilbuffer
0, //no auxiliary buffer
PFD_MAIN_PLANE, //main drawing layer
0, //reserved
0, 0, 0 //layer masks ignored
};
if (!(hDC = GetDC(hWnd)))
{
KillWindow();
MessageBox(NULL, "Can't create OpenGL Window", "Error", MB_OK);
return false;
}
if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))
{
KillWindow();
MessageBox(NULL, "Can't find suitable PixelFormat", "Error", MB_OK);
return false;
}
if (!SetPixelFormat(hDC, PixelFormat, &pfd))
{
KillWindow();
MessageBox(NULL, "Can't set pixelformat", "Error", MB_OK);
return false;
}
if (!(hRC = wglCreateContext(hDC)))
{
KillWindow();
MessageBox(NULL, "Can't create OpenGL context", "Error", MB_OK);
return false;
}
if (!wglMakeCurrent(hDC, hRC))
{
KillWindow();
MessageBox(NULL, "Can't activate OGL context", "Error", MB_OK);
return false;
}
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
ResizeWindow(800, 600);
if (!InitGL())
{
KillWindow();
MessageBox(NULL, "Failed initialization", "Error", MB_OK);
return false;
}
return true;
}
Dispatching events:
bool GLWindow::DispatchEvent(Event* evt)
{
MSG msg;
bool wasThereAnyEvent = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (wasThereAnyEvent)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return wasThereAnyEvent;
}
I removed event buffer filling, so it just processes every message.
WndProc:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
break;
case WM_DESTROY:
case WM_QUIT:
case WM_CLOSE:
isRunning = false;
PostQuitMessage(0);
return 0;
case WM_ACTIVATE:
{
isActiveWindow = !HIWORD(wParam);
return 0;
}
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
case WM_SIZE:
ResizeWindow(LOWORD(lParam), HIWORD(lParam));
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
I think the problem is that you're not using any breaks inside you switch statement (of course they won't be needed in every case). When you receive a WM_SYSCOMMAND which not contains SC_SCREENSAVE or SC_MONITORPOWER the next case statement, in this case WM_SIZE, gets executed.
switch (msg)
{
case WM_CREATE:
break;
case WM_DESTROY:
case WM_QUIT:
case WM_CLOSE:
isRunning = false;
PostQuitMessage(0);
return 0;
break;
case WM_ACTIVATE:
{
isActiveWindow = !HIWORD(wParam);
return 0;
} break;
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
} break;
case WM_SIZE:
ResizeWindow(LOWORD(lParam), HIWORD(lParam));
return 0;
}