0

我正在将游戏的开端编写为 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
};
4

1 回答 1

2

问题是您已g_szClassName声明为成员变量和全局变量。成员变量g_szClassName没有在任何地方初始化,可以指向任何东西。

也没有理由将其wc声明msg为成员变量,因为它们不需要在对象的整个生命周期中持续存在。改为使它们成为局部变量。

于 2013-07-03T17:07:34.043 回答