Despite reading plenty of information throughout the web, along with Petzold's book, Programming the Windows API , and damn near copying the exact same methodology out of the book, along with this documentation on how to initialize an OpenGL context, I haven't been able to get an up and running Window Class.
I've tried compiling on both VC++ and MinGW (I'm using Qt Creator), in order to see if this would work. I've tried making my WNDCLASSEXA
a pointer, as well as allocating it on the stack. No dice for both.
Thus, I'm quite unsure what to do about this. Sometimes the class simply fails to register, where as other times the HWND
which is returned from CreateWindowExA
simply doesn't work and returns NULL. After trying to just continue the program, despite these incidents happening, I wind up with an application which fails to draw a window.
The idea is simple: I have a struct which I'm using to simply store all of the data used ( DEVMODEA
, WNDCLASSEXA
, HGLRC
, etc).
From there, I use that struct to create a Window, and then pass it back to the function's caller.
All I'm really looking to do is write a simple pong-like game in OpenGL using GLSL/OpenGL 3.3. To do that, I obviously need a context first, but I can't discern whether or not the issue is Qt Creator, Windows, or something else.
So, what could I be doing wrong?
GameData
Struct
typedef struct
{
HGLRC hrc;
HDC hdc;
HWND hwnd;
HINSTANCE hInstance;
UINT numFormats;
WNDCLASSEXA* winClass;
DWORD dwExStyle;
DWORD dwStyle;
RECT winRect;
DEVMODEA screenSettings;
bool fullscreen;
const char* winClassName;
int pixelFormat;
bool keys[ 256 ];
bool active;
}
GameData;
initPong()
function
static GameData* initContextAndWindow( void )
{
GameData* dat = new GameData;
const int width = 640;
const int height = 480;
const int bitsPerPixel = 32;
dat->winRect.left = ( long )0;
dat->winRect.right = ( long )width;
dat->winRect.top = ( long )0;
dat->winRect.bottom = ( long )height;
dat->fullscreen = false;
dat->hInstance = GetModuleHandleA( NULL );
dat->winClass = ( WNDCLASSEXA* )calloc( sizeof( WNDCLASSEXA ), 1 );
if( !dat->winClass )
MessageBoxA( NULL, "Something wrong!", "ERROR", MB_OK | MB_ICONINFORMATION );
dat->winClass->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
dat->winClass->lpfnWndProc = ( WNDPROC ) eventHandler;
dat->winClass->cbClsExtra = 1;
dat->winClass->cbWndExtra = 1;
dat->winClass->cbSize = sizeof( WNDCLASSEXA );
dat->winClass->hInstance = dat->hInstance;
dat->winClass->hIcon = LoadIcon( NULL, IDI_WINLOGO );
dat->winClass->hCursor = LoadCursor( NULL, IDC_ARROW );
dat->winClass->hbrBackground = ( HBRUSH ) GetStockObject( WHITE_BRUSH );
dat->winClass->lpszMenuName = NULL;
dat->winClass->lpszClassName = "PongDH";
if ( !RegisterClassExA( dat->winClass ) )
{
MessageBoxA( NULL, "Failed to register class.", "ERROR", MB_OK | MB_ICONINFORMATION );
exit( 1 );
}
if ( dat->fullscreen )
{
memset( &dat->screenSettings, 0, sizeof( dat->screenSettings ) );
dat->screenSettings.dmSize = sizeof( dat->screenSettings );
dat->screenSettings.dmPelsWidth = width;
dat->screenSettings.dmPelsHeight = height;
dat->screenSettings.dmBitsPerPel = bitsPerPixel;
dat->screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if ( ChangeDisplaySettingsA( &dat->screenSettings, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
{
dat->fullscreen = false;
const int continuePlaying = MessageBoxA(
NULL,
"Could not implement fullscreen. Please check your drivers. Do you plan to continue?",
"ERROR",
MB_YESNO | MB_ICONEXCLAMATION
);
if ( continuePlaying == IDYES )
{
MessageBoxA( NULL, "Will revert back to fullscreen.", "Notifcation", MB_OK );
dat->fullscreen = false;
}
else
{
MessageBoxA( NULL, "The program will now close", "Notification", MB_OK );
exit( 1 );
}
}
}
if ( dat->fullscreen )
{
dat->dwExStyle = WS_EX_APPWINDOW;
dat->dwStyle = WS_POPUP;
ShowCursor( FALSE );
}
else
{
dat->dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dat->dwStyle = WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx( &dat->winRect, dat->dwStyle, FALSE, dat->dwExStyle );
dat->hwnd = CreateWindowExA(
dat->dwStyle,
dat->winClass->lpszClassName,
"PongDH",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
dat->winRect.right,
dat->winRect.bottom,
NULL,
NULL,
dat->hInstance,
NULL
);
if ( dat->hwnd == NULL )
{
MessageBoxA( NULL, "Failed to create window; exiting program.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
exit( 1 );
}
const int attrList[] =
{
WGL_DRAW_TO_WINDOW_ARB , GL_TRUE,
WGL_SUPPORT_OPENGL_ARB , GL_TRUE,
WGL_DOUBLE_BUFFER_ARB , GL_TRUE,
WGL_PIXEL_TYPE_ARB , WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB , 32,
WGL_DEPTH_BITS_ARB , 24,
WGL_STENCIL_BITS_ARB , 8,
0,
};
wglChoosePixelFormatARB( dat->hdc, attrList, NULL, 1, &dat->pixelFormat, &dat->numFormats );
const int contextList[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
0,
};
dat->hrc = wglCreateContextAttribsARB( dat->hdc, NULL, contextList );
if( !wglMakeCurrent( dat->hdc, dat->hrc ) )
{
MessageBoxA( NULL, "Error making OpenGL Rendering Context current.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
exit( 1 );
}
ShowWindow( dat->hwnd, SW_SHOW );
SetForegroundWindow( dat->hwnd );
SetFocus( dat->hwnd );
resizeScene( width, height );
UpdateWindow( dat->hwnd );
glEnable( GL_DEPTH_TEST );
return dat;
}
Update
Here, I'll post the procedure of what I did:
I first tried setting cbClsExtra
to 1, whereas before it was 0. Then I set cbWndExtra
to 1. After that I tried setting the cbSize
to sizeof( WNDCLASSEXA )
.
I also tried compiling under both VC++ and MinGW; in VC++, the class simply fails to register, where as in MinGW, the class will register, but it won't actually create the required hwnd
.
I've also tried editing my code by making WNDCLASSEXA
(which is dat->winClass
) a pointer, as opposed to a stack allocated variable.
I've also commenting out my exit
functions in my if
checks to see if either the class doesn't register, or if the hwnd
isn't created. This yields a segmentation fault upon trying to render the OpenGL context with wglChoosePixelFormatARB
.
Update 2
Here is my WndProc:
LRESULT CALLBACK eventHandler( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
return DefWindowProcA( hwnd, uMsg, wParam, lParam );
}
I haven't been able to get an up and running Window Class.
There really is not a lot to registering and creating a window using the WinAPI.
As an example this simple test.cpp file:
#define STRICT
#include <windows.h>
long PASCAL WndProc (HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdParam, int nCmdShow)
{
static char szClassName[] = "Hello World";
MSG msg;
WNDCLASS wndclass;
memset(&wndclass, '\0', sizeof(wndclass));
if (!hPrevInstance) {
// define the 'Hello World' window class
wndclass.style = CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = szClassName;
// register the 'Hello World' window class
RegisterClass (&wndclass);
}
// create a new window that is a 'Hello World' window class
HWND hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szClassName,
"My Hello World Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow (hwnd, nCmdShow);
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
long APIENTRY WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
can be compiled and linked from the command line:
C:\TEMP>cl test.cpp user32.lib gdi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
test.obj
user32.lib
gdi32.lib
and the resulting test.exe can be run and it will display a window:
C:\TEMP>test.exe
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.