在Win32API中注册窗口类
Registering a Window Class in the Win32API
尽管在网上阅读了大量信息,以及Petzold的书《Windows API编程》,并且几乎从书中复制了完全相同的方法,以及关于如何初始化OpenGL上下文的文档,但我还没能建立并运行Window class。
我试过在VC++和MinGW上编译(我使用的是QtCreator),看看这是否可行。我已经尝试将WNDCLASSEXA
作为指针,并在堆栈上分配它。两者都没有骰子。
因此,我很不确定该怎么办。有时,类只是无法注册,而其他时候,从CreateWindowExA
返回的HWND
根本不起作用,并返回NULL。在尝试继续这个程序之后,尽管发生了这些事件,但我最终得到了一个无法绘制窗口的应用程序。
想法很简单:我有一个结构,用来简单地存储所有使用的数据(DEVMODEA
、WNDCLASSEXA
、HGLRC
等)。
从那里,我使用该结构创建一个Window,然后将其传递回函数的调用方。
我真正想做的就是使用GLSL/ONGGL3.3在OpenGL中编写一个简单的类似乒乓球的游戏。要做到这一点,我显然首先需要一个上下文,但我无法判断问题是否是Qt Creator、Windows或其他什么。
那么,我可能做错了什么?
GameData
结构
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()
功能
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;
}
更新
在这里,我将发布我所做的程序:
我第一次尝试将cbClsExtra
设置为1,而之前是0。然后我将cbWndExtra
设置为1。之后,我尝试将cbSize
设置为sizeof( WNDCLASSEXA )
。
我还尝试了在VC++和MinGW下进行编译;在VC++中,类只是无法注册,而在MinGW中,类会注册,但实际上不会创建所需的hwnd
。
我还尝试通过将WNDCLASSEXA
(即dat->winClass
)作为指针来编辑代码,而不是使用堆栈分配的变量。
我还在if
检查中注释了我的exit
函数,看看类是否没有注册,或者hwnd
是不是创建。这在尝试用wglChoosePixelFormatARB
渲染OpenGL上下文时会产生分段错误。
更新2
这是我的WndProc:
LRESULT CALLBACK eventHandler( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
return DefWindowProcA( hwnd, uMsg, wParam, lParam );
}
我还没能找到一个正在运行的Window Class。
使用WinAPI注册和创建窗口确实没有太多。
例如,这个简单的test.cpp文件:
#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, ' ', 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);
}
可以从命令行编译和链接:
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
结果test.exe可以运行,它将显示一个窗口:
C:TEMP>test.exe
- 如何在Qt窗口小部件中使用QStringView(或QStringRef)
- 无法将结构注册为增强几何体3D点
- 问:如何使用C++中的按钮从窗口打开窗口
- SDL 窗口不会弹出
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息
- 如何使用AngelScript注册SFML Vector2运算符
- 如何在cpp文件之间切换窗口?在Qt中
- QuadTree只在窗口的右上角绘制
- 如何在 Win32 控制台应用程序中注册不可见的窗口类?
- 在 64 位和 32 位窗口中读取注册表
- 尝试使用窗口注册表中的路径和 DeleteFile() 方法删除.exe文件
- UWP,加载窗口运行时组件 == 请求的窗口运行时类型 "..." 未注册
- 从Windows注册表中保存的工作区检索窗口放置
- 通过注册表更改鼠标设置后,刷新窗口
- "Refreshing" 注册表项更改后的窗口注册表
- 使用面向对象注册窗口类
- 在Win32API中注册窗口类
- 有没有办法在窗口上注册热键而不会发生冲突
- 返回"file already exists"错误的窗口类的注册类
- c++ WinApi注册第二个窗口类错误