我正在将游戏的开端编写为 Win32 应用程序。当我在 Main.cpp 中注册该类时,一切正常,但现在我正试图将其移至 Game 类以使代码更易于使用。
由于我已将代码移入 Game 类,因此窗口类注册失败。这是我的代码,请注意,有些函数是空的,因为我还没有那么远。
GetLastError() 返回 87。
主文件
#include "Main.h"
// entry point for the program, see Game for explanation of parameters
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
game = std::unique_ptr<Game>(new Game(hInstance, hPrevInstance, lpCmdLine, nCmdShow));
game->Init();
// main game loop
while(game->IsRunning())
{
game->HandleMessages();
game->Update(0.0f);
game->Render();
}
return EXIT_SUCCESS;
}
游戏.cpp
#include "Game.h"
#include <Windows.h>
LPCWSTR g_szClassName = L"Life Simulator Window Class";
Game::Game(HINSTANCE _hInstance, // handle to an instance of the application
HINSTANCE _hPrevInstance, // handle to previous instance of the application
LPSTR _lpCmdLine, // command line parameters
int _nCmdShow) // controls how the window is show)
{
hInstance = _hInstance;
hPrevInstance = _hPrevInstance;
lpCmdLine = _lpCmdLine;
nCmdShow = _nCmdShow;
return;
}
Game::~Game(void)
{
}
bool
Game::Init()
{
// set paramaters for window class
wc.cbClsExtra = 0; // number of extra bytes to allocate after window class, not needed but showing for verbosity
wc.cbSize = sizeof(WNDCLASSEX); // stores the size of the WNDCLASSEX structure, helping future proof your application in case new fields are added
wc.cbWndExtra = 0; // similar to cbClsExtra, but refers to the window itself rather than the window class
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); // handle to a background brush, in this case it's simply a colour cast into a brush handle
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // handle to cursor, first paramater is a handle to the instance of the application containing the cursor (not needed in this case), second is the resource identifier
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // similar to hCursor, but for the application icon instead
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // as above, but for the smaller version of the icon
wc.hInstance = hInstance; // handle to the instance of the application that contains the window procedure
wc.lpfnWndProc = Game::WndProc; // a pointer to the window procedure
wc.lpszClassName = g_szClassName; // the window class name (see global variables)
wc.lpszMenuName = NULL; // specifies the resource name of the menu, which isn't used in this case
wc.style = CS_HREDRAW | CS_VREDRAW; // style for the window class, which in this case means to redraw if it's affected (i.e. resized or moved) vertically or horizontally
// register the window class
if(!RegisterClassEx(&wc))
{
// this code is executed if the window class fails to register successfully
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Class Registation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
// create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // extended window style
g_szClassName, // class of window to be created (this is the window class created earlier)
L"Life Simulator", // title of the window
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of the window, here default values are used
CW_USEDEFAULT, // as above, but for the y position
wndWidth, // width of the window
wndHeight, // height of the window
NULL, // parent window, if it has one
NULL, // handle to the menu for the window
hInstance, // handle to the instance of the application
NULL); // lpParam can be passed on here
if(hWnd == NULL)
{
// this code is executed if the creating the window failed
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Creation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
ShowWindow(hWnd, // handle to the window to be shown
nCmdShow); // passed on from WinMain, controls how the window should be shown (i.e. minimised or maximised)
UpdateWindow(hWnd); // forces the window the be updated by forcing a WM_PAINT message past the application queue
}
// window procedure for the game
LRESULT CALLBACK
Game::WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam) // even more additional message information
{
switch(msg)
{
case WM_CLOSE: // red X has been clicked
DestroyWindow(hWnd); // sends WM_DESTROY to the window
break;
case WM_DESTROY: // some part of the program has requested the window to be destroyed
PostQuitMessage(0); // sends quit message to window
break;
default: // unhandled messages
return DefWindowProc(hWnd, msg, wParam, lParam);// windows will handle any messages that haven't been handled explicitly
}
return 0;
}
void
Game::HandleMessages()
{
while(PeekMessage(&msg, // container for the message
NULL, // when multiple windows are used, you can specify which one here
0, // used to filter messages, not needed here
0, // as above
PM_REMOVE)) // remove messages after they've been processed
{
TranslateMessage(&msg); // turns virtual key messages into character messages
DispatchMessage(&msg); // sends the message on to its window procedure (i.e. WndProc)
}
return;
}
void
Game::Update(float elapsedTime)
{
return;
}
void
Game::Render()
{
return;
}
以前工作的 Main.cpp
#include <Windows.h>
// global variables
LPCWSTR g_szClassName = L"Life Simulator Window Class"; // the L casts the string to a wide string and it is called g_szClassName by convention, making the code easier to read for others
static const int wndHeight = 800;
static const int wndWidth = 600;
// window procedure for the program
LRESULT CALLBACK WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam) // even more additional message information
{
switch(msg)
{
case WM_CLOSE: // red X has been clicked
DestroyWindow(hWnd); // sends WM_DESTROY to the window
break;
case WM_DESTROY: // some part of the program has requested the window to be destroyed
PostQuitMessage(0); // sends quit message to window
break;
default: // unhandled messages
return DefWindowProc(hWnd, msg, wParam, lParam);// windows will handle any messages that haven't been handled explicitly
}
}
// entry point for the program
int WINAPI WinMain(HINSTANCE hInstance, // handle to an instance of the application
HINSTANCE hPrevInstance, // handle to previous instance of the application
LPSTR lpCmdLine, // command line parameters
int nCmdShow) // controls how the window is show
{
// initialise variables
HWND hWnd; // handle to window
WNDCLASSEX wc; // window class container
MSG msg; // window message container
// set paramaters for window class
wc.cbClsExtra = 0; // number of extra bytes to allocate after window class, not needed but showing for verbosity
wc.cbSize = sizeof(WNDCLASSEX); // stores the size of the WNDCLASSEX structure, helping future proof your application in case new fields are added
wc.cbWndExtra = 0; // similar to cbClsExtra, but refers to the window itself rather than the window class
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); // handle to a background brush, in this case it's simply a colour cast into a brush handle
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // handle to cursor, first paramater is a handle to the instance of the application containing the cursor (not needed in this case), second is the resource identifier
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // similar to hCursor, but for the application icon instead
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // as above, but for the smaller version of the icon
wc.hInstance = hInstance; // handle to the instance of the application that contains the window procedure
wc.lpfnWndProc = WndProc; // a pointer to the window procedure
wc.lpszClassName = g_szClassName; // the window class name (see global variables)
wc.lpszMenuName = NULL; // specifies the resource name of the menu, which isn't used in this case
wc.style = CS_HREDRAW | CS_VREDRAW; // style for the window class, which in this case means to redraw if it's affected (i.e. resized or moved) vertically or horizontally
// register the window class
if(!RegisterClassEx(&wc))
{
// this code is executed if the window class fails to register successfully
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Class Registation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
// create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // extended window style
g_szClassName, // class of window to be created (this is the window class created earlier)
L"Life Simulator", // title of the window
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of the window, here default values are used
CW_USEDEFAULT, // as above, but for the y position
wndWidth, // width of the window
wndHeight, // height of the window
NULL, // parent window, if it has one
NULL, // handle to the menu for the window
hInstance, // handle to the instance of the application
NULL); // lpParam can be passed on here
if(hWnd == NULL)
{
// this code is executed if the creating the window failed
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Creation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
ShowWindow(hWnd, // handle to the window to be shown
nCmdShow); // passed on from WinMain, controls how the window should be shown (i.e. minimised or maximised)
UpdateWindow(hWnd); // forces the window the be updated by forcing a WM_PAINT message past the application queue
// message loop
while(true){ // program closes instantly otherwise
while(PeekMessage(&msg, // container for the message
NULL, // when multiple windows are used, you can specify which one here
0, // used to filter messages, not needed here
0, // as above
PM_REMOVE)) // remove messages after they've been processed
{
TranslateMessage(&msg); // turns virtual key messages into character messages
DispatchMessage(&msg); // sends the message on the its window procedure (i.e. WndProc)
}
}
return msg.wParam; // contains the exit code from the last message, most likely WM_QUIT
}
游戏.h
#pragma once
#include <Windows.h>
class Game
{
public:
Game(HINSTANCE hInstance, // handle to an instance of the application
HINSTANCE hPrevInstance, // handle to previous instance of the application
LPSTR lpCmdLine, // command line parameters
int nCmdShow); // controls how the window is show
~Game(void);
bool Init();
bool IsRunning(){return isRunning;}
// window procedure for the game
static LRESULT CALLBACK WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam); // even more additional message information
void HandleMessages(); // messages are translated and dispatched here
void Update(float elapsedTime); // game logic
void Render(); // display results
public: // changed to public until I can get it all working
bool isRunning;
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
LPSTR lpCmdLine;
int nCmdShow;
LPCWSTR g_szClassName; // the L casts the string to a wide string and it is called g_szClassName by convention, making the code easier to read for others
static const int wndHeight = 600; // window height
static const int wndWidth = 800; // window width
HWND hWnd; // handle to window
WNDCLASSEX wc; // window class container
MSG msg; // window message container
};