Windows dc (c++)类中奇怪的数组行为

Weird array behavior in classes along with Windows DCs (C++)?

本文关键字:数组 dc c++ Windows      更新时间:2023-10-16

我正在创建一个基于文本的Windows游戏,我有一个问题(我猜)与数组不工作相同的类范围内的主要功能。据我所知,这是一个更大的数组类成员(或大量变量)和Windows创建DC或其他Windows API调用和/或变量之间的某种交互。

我想做的是有一个叫做Map的类,它包含一个二维tile数组。Tile只是一个带有基本Tile信息的简单结构体。我想把数组设为256 × 256。在我看来,这应该不成问题。每个Tile应该是32字节。这个数组总共有2mb。

然而,当我在main函数中声明Map类的变量,然后用Windows dc做事情时,游戏崩溃了。返回值似乎有所不同,在目前的形式中,它通常返回255,但我也得到了"进程终止状态-1073741571"。一个128 x 128的数组在类中是可以工作的。它也工作得很好,如果我删除数组或代码在DisplayScreen。正如我所暗示的,如果我只是将tile数组移动到main函数中,它也可以工作。

我真的很困惑。我不知道会有什么不同。没有什么是超出范围的。不管它是公共成员还是私有成员。非动态类成员都应该在堆栈上声明它在类中和在其他类中不应该有任何不同,对吧?

对于其他信息,我使用代码::块与最小GW编译器。一切都是最新的。我用的是Windows 10。我的电脑规格应该也不是问题,但如果有问题的话,我有16gb内存和4Ghz Athlon FX 8核处理器。

编辑:这里是完整的代码,所以没有遗漏

Game.h:

#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
struct Tile
{
    char chr[2];
    int  r[2], b[2], g[2];
    bool solid;
    bool translucent;
    int  opacity;
};
class Map
{
    Tile tileMap[256][256];
public:
    Map();
};
Map::Map()
{
    int i, j;
    for(i=0;i<256;i++)
    {
        for(j=0;j<256;j++)
        {
            tileMap[i][j].chr[0] = 'X';
            tileMap[i][j].b[0] = 255;
            tileMap[i][j].r[0] = 255;
            tileMap[i][j].g[0] = 255;
            tileMap[i][j].chr[1] = ' ';
            tileMap[i][j].b[1] = 0;
            tileMap[i][j].r[1] = 0;
            tileMap[i][j].g[1] = 0;
            tileMap[i][j].solid = false;
            tileMap[i][j].translucent = false;
            tileMap[i][j].opacity = 255;
        }
    }
}

main.cpp:

#include <windows.h>
#include "Game.h"
#define FRAMERATE 60
//Function declarations
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void DisplayScreen(HWND pWnd, Map &pMap);
//Make the class name into a global variable
char strClassName[ ] = "GameApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpstrArgument,
                    int nCmdShow)
{
    HWND hWnd;               //This is the handle for our window
    MSG messages;            //Here messages to the application are saved
    WNDCLASSEX wndClassEx;   //Data structure for the windowclass
    Map test;
    DWORD  sysTimer;
    DWORD  sysPrevTime = 0;
    DWORD  timerDelta = 1000 / FRAMERATE;
    //Get a handle for the whole screen
    HDC hDC = GetDC(NULL);
    //Initalize the Window structure
    wndClassEx.hInstance = hThisInstance;
    wndClassEx.lpszClassName = strClassName;
    wndClassEx.lpfnWndProc = WindowProcedure;
    wndClassEx.style = CS_DBLCLKS;
    wndClassEx.cbSize = sizeof (WNDCLASSEX);
    wndClassEx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wndClassEx.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wndClassEx.hCursor = LoadCursor (NULL, IDC_ARROW);
    wndClassEx.lpszMenuName = NULL;                 //No menu
    wndClassEx.cbClsExtra = 0;
    wndClassEx.cbWndExtra = 0;
    wndClassEx.hbrBackground = CreateSolidBrush(RGB(0,0,0));
    //Register the window class, and if it fails quit the program
    if (!RegisterClassEx (&wndClassEx))
        return 0;
    //Create Window with registered window class
    hWnd = CreateWindowEx (
        0,                           
        strClassName,                //Class name
        "Game Test",                 //Title Text
        WS_OVERLAPPEDWINDOW,         //default window type
        0,                           //X pos of window at top left
        0,                           //Y pos of window at top left
        GetDeviceCaps(hDC, HORZRES), //Set window width to screen width
        GetDeviceCaps(hDC, VERTRES), //Set window height to screen height
        HWND_DESKTOP,                //Child-window to desktop
        NULL,                        //No menu
        hThisInstance,               //Program Instance handler
        NULL);                       //No Window Creation data

    //Removes borders from the window
    SetWindowLong(hWnd, GWL_STYLE, WS_POPUP);
    //Make the window visible on the screen
    ShowWindow (hWnd, nCmdShow);
    //Run the message and game loop
    while (true)
    {
        while(PeekMessage(&messages,NULL,0,0, PM_REMOVE))
        {
            if (messages.message == WM_QUIT)
            {
                ReleaseDC(NULL, hDC);
                DestroyWindow(hWnd);
                return 0;
            }
            TranslateMessage(&messages);
            DispatchMessage(&messages);
        }
        sysTimer = timeGetTime();
        if (sysTimer >= (sysPrevTime + timerDelta) )
        {
            sysPrevTime = sysTimer;
            DisplayScreen(hWnd, test);
        }
    }
}
//This function is called by the Windows function DispatchMessage()
LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage (0); //Send WM_QUIT to the message queue
            break;
        default:
            return DefWindowProc (hWnd, message, wParam, lParam);
    }
    return 0;
}
void DisplayScreen(HWND pWnd, Map &pMap)
{
    HDC hDC = GetWindowDC(pWnd);
    HDC hdcBuf = CreateCompatibleDC(hDC);
    HBITMAP hbmBuf = CreateCompatibleBitmap(hDC, 800, 600);
    HFONT hMapFont = CreateFont(17,11,0,0,400,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH | FF_MODERN,"Lucida Console");
    HFONT hTxtFont = CreateFont(17,11,0,0,400,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH | FF_MODERN,"Lucida Console");
    SelectObject(hdcBuf, hbmBuf);
    SelectObject(hdcBuf, hMapFont);
    SetBkColor(hdcBuf, RGB(0,0,0));
    SetTextColor(hdcBuf, RGB(255,255,255));
    //Draw to the buffer
    TextOut(hdcBuf, 10, 10, "Hello World   @", 15);
    //Tranfers the buffer to the Screen
    BitBlt(hDC, 100, 100, 800, 600, hdcBuf, 0, 0, SRCCOPY);
    //Release all object handles
    DeleteObject(hTxtFont);
    DeleteObject(hMapFont);
    DeleteObject(hbmBuf);
    DeleteDC(hdcBuf);
    ReleaseDC(pWnd, hDC);
}

即使只有一个创建DC的实例,它也会崩溃。它可以很好地创建和销毁dc,并一次又一次地显示位图,即使我离开它一个小时。一旦我创建了类,里面有一个大数组,它就死了。

实际上我曾经把Display函数作为一个类函数,我把它移了出来,因为我认为这是问题所在,但事实并非如此。

有趣的是,如果我将声明从'Map test;'更改为'Map* test = new Map;'并适当更改程序的其余部分,它就可以工作了。老实说,这样做似乎有点愚蠢,我认为如果我没有一个很好的理由把所有东西都放在堆上,这会减慢所有事情的速度。另外,我不喜欢绷带。如果有问题,我宁愿解决它。

任何想法?

你有一个堆栈溢出(条件,而不是网站)。

这个问题可以在这个程序中重现:

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    Map test;
    return 0;
}

由于达到堆栈限制而失败。

tileMap[i][j].chr[2]也在边界外。声明为char chr[2];,有效索引为0和1。只能上升到tileMap[i][j].chr[1]

同上b[], r[], g[]

更改Map类,以便它在堆上分配内存并修复chr:

class Map
{
    //Tile tileMap[256][256];
    Tile **tileMap;
public:
    Map();
    ~Map();
};
Map::Map()
{
    int i, j;
    tileMap = new Tile*[256];
    for (i = 0; i < 256; i++)
        tileMap[i] = new Tile[256];
    for (i = 0; i<256; i++)
    {
        for (j = 0; j<256; j++)
        {
            //tileMap[i][j].chr[1] = 'X';
            tileMap[i][j].chr[0] = 'X';  //<== meant to be 0?
            tileMap[i][j].b[0] = 255;
            tileMap[i][j].r[0] = 255;
            tileMap[i][j].g[0] = 255;
            //tileMap[i][j].chr[2] = ' ';
            tileMap[i][j].chr[1] = ' '; //<== meant to be 1?
            tileMap[i][j].b[1] = 0;
            tileMap[i][j].r[1] = 0;
            tileMap[i][j].g[1] = 0;
            tileMap[i][j].solid = false;
            tileMap[i][j].translucent = false;
            tileMap[i][j].opacity = 255;
        }
    }
}
Map::~Map()
{
    int i = 0;
    for (i = 0; i < 256; i++)
        delete[]tileMap[i];
    delete[]tileMap;
}