I'm trying to create a simple OpenGL context but the program crashes on ChoosePixelFormat with the error "Unhandled exception at 0x779CE0E6 (ntdll.dll) in OpenGL.exe: 0xC0000005: Access violation reading location 0x00000044." This same code used to work a while back but for some reason doesn't work anymore. I tried updating my graphics drivers to no avail. If it matters, I have a 64-bit Windows 7 Home premium, a GeForce 570 and a Intel Core i7-2600 3,40 GHz.
This is the code I use in the order of execution to the point it crashes:
GLEngine gl(WndProc); //WndProc just calls DefWindowProc
- calls ->
GLEngine::GLEngine(WNDPROC wndproc) { //Initialize class
hRC = NULL;
hDC = NULL;
hWnd = NULL;
fullscreen = false;
active = false;
proc = wndproc;
itemsLength = 0;
currentActive = this;
success = true;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) {
gl.CreateGL2Window("Test", 1300, 900, 8, false, true);
- calls ->
bool GLEngine::CreateGL2Window(char* title, int width, int height, bool internalflag) {
GLuint pixelFormat;
WNDCLASSEX wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT windowRect;
windowRect.left = (long)0;
windowRect.right = (long)width;
windowRect.top = (long)0;
windowRect.bottom = (long)height;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance; //hInstance is NULL here, should it be something else?
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = _T("OpenGL");
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, _T("Failed To Register The Window Class."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return false;
}
hInstance = wc.hInstance; //hInstance isn't NULL anymore
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle);
if(!(hWnd = CreateWindowEx(dwExStyle, _T("OpenGL"),
(wchar_t*)title,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
0, 0,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top,
NULL,
NULL,
hInstance,
NULL))) {
DestroyGLWindow();
MessageBox(NULL, _T("Window Creation Error."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return false;
}
if(!(hDC = GetDC(hWnd))) {
DestroyGLWindow();
MessageBox(NULL, _T("Can't Create A GL Device Context."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return false;
}
PIXELFORMATDESCRIPTOR pfd2 = { sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
32,
8,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
if(!(pixelFormat = ChoosePixelFormat(hDC, &pfd2)) {
GLEngine is in a dll. It shouldn't matter but the information can't hurt.
Did you get address of function with GetProcAddress? Faulty drivers can cause crash on this too. ChoosePixelFormat may be implemented and exported driver-side, but it might be not exported, then system procedure should be used. exported one may or may not filling descriptor structure, depending on implementation, so you need to call DescribePixelFormat.
Related
I have a main HWND with several child HWNDs. When I start the code the windows all draw properly and show up as they should, I can even move the main window around which essentially invokes InvalidateRect() calls which call a redraw of the main and child windows. However, after about two seconds, all of this functionality stops and upon moving the window the main window draw ends up drawing all of the child windows at the size of the main window. Note that this problem occurs with any redrawing of the main window. This is quite strange, and I am inclined to think that the problem lies with my HWND setup and not the OpenGL integration as both my GL child window and the other HWND child windows are subject to the issue.
Here is my main window creation:
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(7, 7, 8));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
//MessageBox(NULL, _T("This message box is completely unnecessary and is designed to annoy you."), _T("Annoyance"), NULL);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
HWND hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1600, 900, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindowEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
Here is the main window procedure:
LRESULT CALLBACK WndProc(_In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam) {
//a = std::make_tuple<float, float, float>(1.0f, 0.0f, 0.0f);
PAINTSTRUCT ps;
HDC hdc = GetDC(hWnd);
TCHAR greeting[] = _T("Data Grapher for Paper");
RECT rcClient;
WNDCLASSEXW wcex1;
wcex1.cbSize = sizeof(WNDCLASSEX);
wcex1.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex1.lpfnWndProc = (WNDPROC)GLProc;
wcex1.cbClsExtra = 0;
wcex1.cbWndExtra = 0;
wcex1.hInstance = glInstance;
wcex1.hIcon = LoadIcon(wcex1.hInstance, IDI_APPLICATION);
wcex1.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex1.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
wcex1.lpszMenuName = nullptr;
wcex1.lpszClassName = _T("GLClass");
wcex1.hIconSm = LoadIcon(wcex1.hInstance, IDI_APPLICATION);
RegisterClassExW(&wcex1);
WNDCLASSEXW dataViewClass;
dataViewClass.cbSize = sizeof(WNDCLASSEX);
dataViewClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
dataViewClass.lpfnWndProc = (WNDPROC)DataProc;
dataViewClass.cbClsExtra = 0;
dataViewClass.cbWndExtra = 0;
dataViewClass.hInstance = hInst;
dataViewClass.hIcon = LoadIcon(dataViewClass.hInstance, IDI_APPLICATION);
dataViewClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
dataViewClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
dataViewClass.lpszMenuName = nullptr;
dataViewClass.lpszClassName = _T("DataClass");
dataViewClass.hIconSm = LoadIcon(dataViewClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&dataViewClass);
WNDCLASSEXW dataTextClass;
dataTextClass.cbSize = sizeof(WNDCLASSEX);
dataTextClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
dataTextClass.lpfnWndProc = (WNDPROC)dataTextProc;
dataTextClass.cbClsExtra = 0;
dataTextClass.cbWndExtra = 0;
dataTextClass.hInstance = hInst;
dataTextClass.hIcon = LoadIcon(dataTextClass.hInstance, IDI_APPLICATION);
dataTextClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
dataTextClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
dataTextClass.lpszMenuName = nullptr;
dataTextClass.lpszClassName = _T("dataTextClass");
dataTextClass.hIconSm = LoadIcon(dataTextClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&dataTextClass);
WNDCLASSEXW quitButtonClass;
quitButtonClass.cbSize = sizeof(WNDCLASSEX);
quitButtonClass.style = BS_OWNERDRAW;//CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
quitButtonClass.lpfnWndProc = (WNDPROC)quitButtonProc;
quitButtonClass.cbClsExtra = 0;
quitButtonClass.cbWndExtra = 0;
quitButtonClass.hInstance = hInst;
quitButtonClass.hIcon = LoadIcon(quitButtonClass.hInstance, IDI_APPLICATION);
quitButtonClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
quitButtonClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
quitButtonClass.lpszMenuName = nullptr;
quitButtonClass.lpszClassName = _T("quitButtonClass");
quitButtonClass.hIconSm = LoadIcon(quitButtonClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&quitButtonClass);
WNDCLASSEXW saveImageButtonClass;
saveImageButtonClass.cbSize = sizeof(WNDCLASSEX);
saveImageButtonClass.style = BS_OWNERDRAW;//CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
saveImageButtonClass.lpfnWndProc = (WNDPROC)saveImageButtonProc;
saveImageButtonClass.cbClsExtra = 0;
saveImageButtonClass.cbWndExtra = 0;
saveImageButtonClass.hInstance = hInst;
saveImageButtonClass.hIcon = LoadIcon(saveImageButtonClass.hInstance, IDI_APPLICATION);
saveImageButtonClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
saveImageButtonClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
saveImageButtonClass.lpszMenuName = nullptr;
saveImageButtonClass.lpszClassName = _T("saveImageButtonClass");
saveImageButtonClass.hIconSm = LoadIcon(saveImageButtonClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&saveImageButtonClass);
WNDCLASSEXW switchModeButtonClass;
switchModeButtonClass.cbSize = sizeof(WNDCLASSEX);
switchModeButtonClass.style = BS_OWNERDRAW;//CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
switchModeButtonClass.lpfnWndProc = (WNDPROC)switchModeButtonProc;
switchModeButtonClass.cbClsExtra = 0;
switchModeButtonClass.cbWndExtra = 0;
switchModeButtonClass.hInstance = hInst;
switchModeButtonClass.hIcon = LoadIcon(switchModeButtonClass.hInstance, IDI_APPLICATION);
switchModeButtonClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
switchModeButtonClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
switchModeButtonClass.lpszMenuName = nullptr;
switchModeButtonClass.lpszClassName = _T("switchModeButtonClass");
switchModeButtonClass.hIconSm = LoadIcon(switchModeButtonClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&switchModeButtonClass);
switch (message)
{
case WM_PAINT:
/*
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, Windows desktop!"
// in the top left corner.
//doGL(hdc);
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
// End application-specific layout section.
EndPaint(hWnd, &ps);
ReleaseDC(hWnd, hdc);
*/
break;
case WM_CREATE:
{
InitCommonControls();
CreateWindowEx(WS_EX_APPWINDOW, _T("quitButtonClass"), _T("Quit"), WS_CHILD, 20, 50, 100, 25, hWnd, (HMENU)1, hInst, NULL);
CreateWindowEx(WS_EX_APPWINDOW, _T("saveImageButtonClass"), _T("Save Image"), WS_CHILD, 140, 50, 80, 25, hWnd, (HMENU)2, hInst, NULL);
CreateWindowEx(WS_EX_APPWINDOW, _T("switchModeButtonClass"), _T("Toggle Clock"), WS_CHILD, 20, 90, 100, 25, hWnd, (HMENU)3, hInst, NULL);
w = CreateWindowEx(WS_EX_APPWINDOW, _T("GLClass"), _T("GL"), WS_CHILD, 0, 0, 160, 90, hWnd, (HMENU)4, hInst, NULL);
HDC dc = GetDC(w);
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
//glfwInit();
int argc = 1;
char* argv[1] = { (char*)"Something" };
glutInit(&argc, argv);
glewInit();
initializeText();
imageSaveQueued = false;
graphScale = .8f;
HWND da = CreateWindowEx(WS_EX_APPWINDOW, _T("DataClass"), _T("Data"), WS_CHILD, 0, 0, 160, 90, hWnd, (HMENU)5, hInst, NULL);
//makes it so the data field accepts files
DragAcceptFiles(da, TRUE);
//set the data mode to by bz graph by default
mode = 1;
//dataList = CreateWindow(WC_LISTVIEW, TEXT("Load Data"), WS_CHILD | LVS_REPORT | LVS_EDITLABELS, 300, 700, 500, 100, hWnd, (HMENU)6, hInst, NULL);
//dataText = CreateWindowEx(WS_EX_APPWINDOW, _T("dataTextClass"), _T("dataText"), WS_CHILD, 200, 200, 200, 200, hWnd, (HMENU)7, hInst, NULL);
//createListColumn(dataList, 1, L"Year", 0);
//createListItem(dataList, _T("Thing"), 0);
//SendMessage(dataList, LB_ADDSTRING, NULL, (LPARAM)"words");
//CreateWindow(TEXT("button"), TEXT("Save Graph"), WS_VISIBLE | WS_CHILD, 140, 90, 100, 25, hWnd, (HMENU)7, NULL, NULL);
//trackA = CreateWindowEx(0, TRACKBAR_CLASS, _T("Start"), WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE, 900, 700, 200, 30, hWnd, (HMENU)8, hInst, NULL);
//trackB = CreateWindowEx(0, TRACKBAR_CLASS, _T("End"), WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE, 900, 730, 200, 30, hWnd, (HMENU)8, hInst, NULL);
//SendMessage(trackA, TBM_SETRANGE,
//(WPARAM)TRUE, // redraw flag
//(LPARAM)MAKELONG(0, 100));
GetClientRect(hWnd, &rcClient);
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&rcClient);
break;
}
case WM_COMMAND:
{
/*
if (LOWORD(wParam) == 2) {
PostQuitMessage(0);
}
*/
if (LOWORD(wParam) == 7) {
smoothLine = !smoothLine;
InvalidateRect(w, NULL, TRUE);
}
break;
}
case WM_DESTROY:
FreeLibrary(comctllib);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
I'm reluctant to paste more code here in the initial question as there is quite a lot more code, but if there is something more needed (including screenshots) I am happy to add it.
I built a simplest progress bar which shows the progress of my png frame generation. Here is the process
BOOL myProc(HWND hwndParent, HINSTANCE hInst) {
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hwndParent, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR) NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hwndParent, (HMENU) 0, hInst, NULL);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
for (int i = 0; i < N + 1; i++) {
int frame = create_pngInt(i);
SendMessage(hwndPB, PBM_STEPIT, 0, 0);
}
DestroyWindow(hwndPB);
DestroyWindow(hwndParent);
return TRUE;
}
I want my window to host just this progress bar. When the loop in myProc is done, the host window should be destroyed.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL);
std::thread q(myProc, hMainWindow, hInst);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
However, the window hMainWindow is not destroyed (!) and the process myProc doesn't terminate by itself (after the loop in myProc is comlete).
It seems I don't understand something important.
I checked. If I don't create a separate thread but just run myProc in WinMain, the window hosting the progress bar destroyed after myProc returns. And this is precisely what I want. But the progress bar freezes after several seconds(. That is why I need a separate thread.
Following your remarks I modified the code like this:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
RECT rect;
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL);
SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hMainWindow, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR)NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hMainWindow, (HMENU)0, hInst, NULL);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
std::thread q(myProc, hMainWindow, hInst, hwndPB);
MSG msg = { 0 };
while (GetMessage(&msg, hMainWindow, NULL, NULL))
{
if (msg.message == WM_QUIT) {
DestroyWindow(hMainWindow);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
However, I know that I haven't handled WM_QUIT event properly, and the whole thing is not destroyed. Could you please, elaborate just a little bit more and if the rest of the code is ok?
The thread which calls CreateWindowEx needs to be the one executing the GetMessage loop.
It won't get destroyed, as there is nothing processing the events and messages for it, including the WM_DESTROY message.
Keep your window creation in your main thread (and that thread only!), and use only PostMessage / SendMessage to send update events and finally a destroy message to the window owned by the main thread.
Ultimately handle a WM_DESTROY to your main window with PostQuitMessage and your are done.
In full:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
RECT rect;
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(
L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL
);
SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hMainWindow, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(
0, PROGRESS_CLASS, (LPTSTR)NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hMainWindow, (HMENU)0, hInst, NULL
);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
std::thread q([hMainWindow, hInst, hwndPB, N]() {
for (int i = 0; i < N + 1; i++) {
SendMessage(hwndPB, PBM_STEPIT, 0, 0);
}
DestroyWindow(hMainWindow);
});
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
if (msg.message == WM_DESTROY) {
PostQuitMessage(0);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
q.join();
// Exit code from PostQuitMessage() is still in msg.param
return msg.param;
}
I tried to create a window in an Empty C++ Project in Visual Studio, but when I run it, it shows me no window. However, it doesn't give me any error too.
#include <Windows.h>
using namespace std;
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
const auto pClassName = "TextClass";
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(wc);
wc.style = CS_OWNDC;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = nullptr;
wc.hCursor = nullptr;
wc.hbrBackground = nullptr;
wc.lpszMenuName = pClassName;
wc.hIconSm = nullptr;
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(
0,
pClassName,
"A sad Window",
WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
200, 200, 640, 480,
nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, SW_SHOW);
while (true);
return 0;
}
You have a typo: you are setting
wc.lpszMenuName = pClassName;
instead of wc.lpszClassName.
I believe just fixing that will get the window on the screen but the executable will then hang with it on the screen because nothing is fielding messages.
A minimal message loop instead of
while (true) ...
would be
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
DispatchMessage( &msg );
Im making a game with a custom game engine and when you have selected the window that it creates it doesn't allow you to use media keys e.g. changing volume or playing/pausing music or anything that has to do with windows like getting the windows start menu and alt+tab behaves weird
It feels like my window is "blocking" all system specific keys and commands
The code is written in c++
Heres the code i'm using for creating the window:
bool FrameWork::CreateDXWnd(int x, int y, int width, int height)
{
HWND hwnd;
WNDCLASSEX wc;
m_hInstance = GetModuleHandle(nullptr);
//setup window class with default setings:
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hInstance;
//wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
wc.hIcon = (HICON)LoadImage(m_hInstance, ".\\Assets\\Icons\\NgineIcon512.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(nullptr, IDC_HAND);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = nullptr;
wc.lpszClassName = applicationName.c_str();
wc.cbSize = sizeof(WNDCLASSEX);
if (!RegisterClassEx(&wc))
{
Error(1);
return false;
}
//Style of window
//int nStyle = WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX;
int nStyle = WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX;
SettingsManager::GetInstance()->SetNativeResolution(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
if (SettingsManager::GetInstance()->GetDisplayMode() == FULLSCREEN)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)SettingsManager::GetInstance()->GetScreenWidth();
dmScreenSettings.dmPelsHeight = (unsigned long)SettingsManager::GetInstance()->GetScreenHeight();
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
}
else
{
}
if ((SettingsManager::GetInstance()->GetDisplayMode() == BORDERLESS))
{
hwnd = CreateWindowEx(WS_EX_APPWINDOW, applicationName.c_str(), applicationName.c_str(), WS_POPUP, x, y, SettingsManager::GetInstance()->GetScreenWidth(), SettingsManager::GetInstance()->GetScreenHeight(), nullptr, nullptr, m_hInstance, nullptr);
}
else
{
hwnd = CreateWindowEx(WS_EX_APPWINDOW, applicationName.c_str(), applicationName.c_str(), nStyle, x, y, SettingsManager::GetInstance()->GetScreenWidth(), SettingsManager::GetInstance()->GetScreenHeight(), nullptr, nullptr, m_hInstance, nullptr);
}
if (hwnd == nullptr)
{
Error(2);
Ngine::GetInstance()->Release();
PostQuitMessage(0);
return false;
}
if (!Ngine::GetInstance()->InitGraphics(hwnd))
{
Error(hwnd, 30);
Ngine::GetInstance()->Release();
PostQuitMessage(0);
UnregisterClass(applicationName.c_str(), m_hInstance);
m_hInstance = nullptr;
DestroyWindow(hwnd);
return false;
}
Ngine::GetInstance()->GetGraphics()->SetHwnd(hwnd);
ShowWindow(hwnd, SW_SHOW);
SetForegroundWindow(hwnd);
SetFocus(hwnd);
return true;
}
Tim. The code you are showing deals with creating a window, not with how to handle the input to the window. To handle input, you need to set up a Message handling loop in your code.
Typically, in a game engine, you will have a main loop or "Game Loop", with each pass through the loop typically resulting in a single frame drawn. The first thing the Game Loop does is handle window messages. This allows you to handle the typical windows functions. Then, once you have no more messages to deal with, you will move on to handling your game's logic and rendering.
I recommend you take a look at Braynzarsoft's tutorials. The tutorial I linked deals with setting up your window and how to make a bare-bones Windows Message system.
Once you understand the basics of that, you can refine your post if needed to get more information.
Have a kiosk system with a small touchscreen and a large display, and I have an app that works well playing video on the large display. For some reason, when Direct3D stops (app quits), both screens flicker (turn black, then recover).
I simplified the problem down to a program that simply opens a focus window, initializes a Direct3D device, then releases it. On release (or stopping the program without releasing), both screens flicker.
Can someone who's familiar with Direct3D look at this and tell me if I'm doing something wrong?
#include <iostream>
#include <windows.h>
#include <d3d9.h>
const char g_szClassName[] = "myWindowClass";
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"Focus Window",
WS_POPUP | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
IDirect3D9* m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (m_pD3D == NULL) {
MessageBox(NULL, "Failed to initialize direct3D!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// second display is 1920 x 1080
D3DPRESENT_PARAMETERS m_param;
ZeroMemory(&m_param, sizeof(m_param));
m_param.BackBufferWidth = 1920;
m_param.BackBufferHeight = 1080;
m_param.BackBufferFormat = D3DFMT_X8R8G8B8;
m_param.BackBufferCount = 1;
m_param.MultiSampleType = D3DMULTISAMPLE_NONE;
m_param.SwapEffect = D3DSWAPEFFECT_COPY;
m_param.hDeviceWindow = hwnd;
m_param.Windowed = FALSE;
m_param.Flags = D3DPRESENTFLAG_VIDEO;
m_param.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
m_param.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
HRESULT hr;
IDirect3DDevice9* m_pD3DD;
hr = m_pD3D->CreateDevice(
1,
D3DDEVTYPE_HAL,
hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED,
&m_param,
&m_pD3DD
);
if (hr != S_OK) {
MessageBox(NULL, "Failed to create direct3D device!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
Sleep(3000);
// flicker occurs here
m_pD3DD->Release();
m_pD3D->Release();
return 0;
}
NOTE: This program should run on any setup with 2 screens on the same video card, but the second screen's width/height might need to be adjusted (it's hardcoded in BackBufferWidth and BackBufferHeight)
Not sure if that is workable for you, but in trying various examples around the interwebs, it seems the only way to avoid the flicker is to use windowed mode with a borderless window:
...
HWND hwnd = CreateWindowEx(
0,
g_szClassName,
"Focus Window",
WS_POPUP | WS_VISIBLE, // <-- borderless window
800, 0, // <-- position on 2nd screen
1920, 1080, // <-- fill entire 2nd screen
NULL, NULL, hInstance, NULL);
...
D3DPRESENT_PARAMETERS m_param;
ZeroMemory(&m_param, sizeof(m_param));
m_param.BackBufferWidth = 1920;
m_param.BackBufferHeight = 1080;
m_param.BackBufferFormat = D3DFMT_X8R8G8B8;
m_param.BackBufferCount = 1;
m_param.MultiSampleType = D3DMULTISAMPLE_NONE;
m_param.SwapEffect = D3DSWAPEFFECT_COPY;
m_param.hDeviceWindow = hwnd;
m_param.Windowed = TRUE; // <-- use windowed mode
m_param.Flags = D3DPRESENTFLAG_VIDEO;
m_param.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
m_param.PresentationInterval = D3DPRESENT_INTERVAL_ONE;