C++ Win32: HDC и отладка

Я пишу код для того, что должно быть игрой в тетрис. Это рано, и сейчас он показывает только один кусок (кусок, который будет "падать" в этот момент), и это все, что он должен делать. Стрелка вверх позволяет циклически перемещаться вперед (в частности, только) по случайно сгенерированной последовательности фрагментов (используя метод "bag"). И, используя стрелки влево и вправо, вы можете вращать части. В любом случае, это кодируется на платформе win32, и я обнаружил, что после определенного количества кадров (с WM_PAINT) основной HDC обнуляется, и все останавливается. Чтобы достичь этого, требуется примерно вдвое больше кадров, удерживающих клавиши со стрелками вправо или влево, чем при удерживании клавиши со стрелкой вверх. Что-то странное в том, что после примерно 1000 кадров область консоли, которую я активно закрашиваю (рамка 600x600 px), станет черной (hdc еще не был обнулен), и только когда нажата стрелка вверх, HDC аннулируется. Я подозреваю, что проблема в том, что методы, вызываемые при нажатии клавиши со стрелкой вверх, передают hdc в качестве параметра для методов в классе (скажите, если это плохая практика или я должен что-то делать вместо этого). Я думаю, что HDC может быть портит или что-то (честно говоря, я понятия не имею). Клавиши со стрелками влево и вправо не вызывают напрямую методы с HDC в качестве параметра. Из-за меток дел и того, как спроектирован шаблон win32, я должен хранить HDC, область которого выпадает из любой метки дела, чтобы я мог получить доступ к дескриптору окна вне случая рисования (я чувствую, что это плохая практика, но я хотел бы понять, почему, прежде чем я изо всех сил, чтобы найти новый путь). Я опубликую код, сохраненный HDC называется main HDC, и он определен непосредственно перед основным оператором case. Чтобы пояснить вам, я дам обзор структуры кода:

Основной файл.cpp, который содержит базовую программу win32, вызывает конструктор класса Tetris в WM_PAINT и сохраняет его повсеместно, подобно main HDC, и, при запросе, методу "next" (который приносит следующий фрагмент), "turnPiece" метод (который вращает фигуру по часовой стрелке или против часовой стрелки в зависимости от параметра) и метод "рисования", который обновляет экран, перерисовывая текущую фигуру. В классе tetris (который находится в его собственном заголовочном файле) есть подкласс, называемый "части", который содержит информацию о его объектах, которые определены другим уровнем подклассов, названных с единственным символом, изображенным частями форма. Форма, цвет и размер фрагментов хранятся в двумерном массиве указателей (используя COLORREF). "Pieces" содержит свой собственный метод "DrawObject", который рисует вызывающий его объект (который, как и все методы рисования / рисования, имеет HDC в качестве аргумента). Есть также метод, который вращает фигуру, называемую "turnTet" (метод "turnPiece" переводит вызов из основного файла.cpp в "куски"). Единственными другими применимыми методами являются те, которые встречаются в классе "tetris", это "paint" и "next" (в конечном итоге они рисуют объект). Случаи WM_KEY, исключая случай VK_UP, не используют сохраненный hdc, а используют InvalidateRect().

Вот соответствующая часть.cpp файла

int tempt = 2;
int tempvar = 0;
tetris *mainOBJ;
HDC mainHDC;
HDC testHDC;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_KEYDOWN:
        switch (wParam) {
        case VK_LEFT:
            mainOBJ->turnPiece(false);
            InvalidateRect(hWnd, 0, FALSE);
            break;
        case VK_RIGHT:
            mainOBJ->turnPiece(true);
            InvalidateRect(hWnd, 0, FALSE);
            break;
        case VK_UP:
            mainOBJ->next(mainHDC);
            InvalidateRect(hWnd, 0, FALSE);
            break;
        }
        break;
    case WM_COMMAND:
        //Non-applicable & has not been changed
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            mainHDC = hdc;

            HPEN oldP;
            HPEN newP;
            COLORREF qLC;
            qLC = RGB(0, 0, 0);
            newP = CreatePen(PS_SOLID, 1, qLC);
            oldP = (HPEN) SelectObject(hdc, newP);


            tempt++;
        //USED FOR COUNTING FRAMES WITH DEBUGGER
            if (tempt % 1 == 0) {

                if (tempvar == 0) {
            //CONSTRUCTOR CALL
                    mainOBJ = new tetris(hdc);
                    tempvar++;
                }
            //PAINT METHOD CALL
                mainOBJ->paint(hdc);
            }



            if (hdc == NULL) {

                int x = 3;
                int y = x + 3; //SET DEBUG_BREAK POINT HERE
            }

            testHDC = hdc;
            SelectObject(hdc, oldP);
            DeleteObject(newP);
            EndPaint(hWnd, &ps);

        }
        break;
    }
}

Заголовочный файл, который содержит классы Tetris и Piece

class tetris {
public:
    class pieces {
    private:
        COLORREF **test;
        int size;
    public:
    //Abbreviated for space
        class O {};
        class I {};
        class S {};
        class Z {};
        class T {};
        class L {};
        class J {};
        void setSize(int a) {
        //Initializing the piece-array
            test = new COLORREF*[a];
            size = a;
            int i = 0;
            while (i < a) {
                test[i] = new COLORREF[a];
                i++;
            }

        }
        void setShape(COLORREF **shape) {
            test = shape;
        }
        void setColor(HDC hdc, COLORREF rgb) {
            HPEN Penn = CreatePen(PS_SOLID, 1, rgb);
            HPEN Peno = (HPEN)SelectObject(hdc, Penn);
        }
        static pieces getObject(char type) {

            pieces Gen;
            switch (type) {

            case 'O':
            {
                //Identical (almost) to the other cases
                O pcs = O();
                Gen = *pcs.getObject();
                return Gen;
            }
            break;
            case 'I':
            case 'S':
            case 'Z':
            case 'T':
            case 'L':
            case 'J':

            return pieces();
        }

        void turnTet(bool clockwise) {
            int i = 0;
            int s;
            COLORREF **shape;
            int ter = size - 1;
            shape = new COLORREF*[2];

            while (i < size) {
                shape[i] = new COLORREF[2];

                s = 0;
                while (s < size) {
                    shape[i][s] = def;
                    s++;
                }
                i++;
            }
            i = 0;

            while (i < size) {

                s = 0;
                while (s < size) {
                    if (clockwise) {
                        shape[s][ter - i] = test[i][s];
                    }
                    else {
                        shape[ter - s][i] = test[i][s];
                    }
                    s++;
                }
                i++;
            }
            test = shape;
        }
        void drawObject(HDC hWnd) {
            int i = 0;
            int s;
            while (i < size) {
                s = 0;
                while (s < size) {
                    setColor(hWnd, test[i][s]);
                    int scaleOfBox = 90;
                    DrawBox((s + 1) * scaleOfBox, (i + 1) * scaleOfBox, scaleOfBox - 1, scaleOfBox - 1, hWnd);
                    s++;
                }
                i++;
            }
        }
        void DrawBox(int x, int y, int w, int h, HDC hdc) {
            if (h < 0) {
                h *= -1;
            }
            if (w < 0) {
                w *= -1;
            }

            int i = 0;
            while (i < h) {
                MoveToEx(hdc, x, y + i, NULL);
                LineTo(hdc, x + w, y + i);

                i++;
            }

        }

    };

    tetris(HDC hdc) {
        refresh();
        bagp[cur].drawObject(hdc);
    }
    void next(HDC hdc) {
        bagp[cur].DrawBox(0, 0, 600, 600, hdc);
        bagp[cur].drawObject(hdc);
        cur++;

        if (cur > 6) {
            refresh();
        }
    }
    void turnPiece(bool clockwise) {
        bagp[cur].turnTet(clockwise);
    }
    void refresh() {
        srand(time(NULL));
        bag[0] = rand() % 7;

        int i = 1;
        while (i < 7) {
            bool open = false;
            cur = i;

            while (!open) {
                bag[i] = rand() % 7;
                int s = 1;
                open = true;
                while (s <= i) {
                    if (bag[i] == bag[i - s]) {
                        open = false;
                    }
                    s++;
                }
            }
            i++;
        }

        cur = 0;
        while (cur < 7) {
            switch (bag[cur]) {
            case 0:
                bagp[cur] = pieces::getObject('O');
                break;
            case 2:
                bagp[cur] = pieces::getObject('T');
                break;
            case 1:
                bagp[cur] = pieces::getObject('I');
                break;
            case 3:
                bagp[cur] = pieces::getObject('S');
                break;
            case 4:
                bagp[cur] = pieces::getObject('Z');
                break;
            case 5:
                bagp[cur] = pieces::getObject('L');
                break;
            case 6:
                bagp[cur] = pieces::getObject('J');
                break;
            }

            cur++;
        }
        cur = 0;
    }
    void paint(HDC hdc) {
        COLORREF temp = def;
        bagp[cur].setColor(hdc, temp);
        bagp[cur].DrawBox(0, 0, 600, 600, hdc);
        bagp[cur].drawObject(hdc);
    }
private:
    int bag[7];
    int cur;
    pieces bagp[7];
};

Я не понимаю, почему HDC обнуляет, как это делает. Еще раз я подозреваю, что это связано с тем, как HDC передается в качестве параметра или, возможно, как я сохраняю HDC. Помогите... пожалуйста (и спасибо).

1 ответ

Решение

Ооо, окна старой школы программирования...

Это может быть не полная проблема, но в вашем setColor Функция вы создаете ручку с CreatePen но никогда не звонит DeleteObject в теме. Это приведет к утечке ресурса и, в конечном итоге, к возникновению проблем, когда в Windows не хватает дескрипторов ресурсов для объектов.

Кроме того, контекст устройства, возвращаемый BeginPaint, (как правило) действителен только до вызова EndPaint (если вы не укажете иначе в вызове CreateWindow, если я правильно помню). Это может быть еще одним источником утечки ручки.

На вкладке "Процесс" диспетчера задач вы можете добавить столбец "Объекты GDI", который будет увеличиваться по мере выполнения вашей программы, если у вас есть утечка дескрипторов. Я видел это однажды с чем-то, что я написал, когда.

Другие вопросы по тегам