Странное поведение, когда глобальные переменные добавляются в другой файл - PullRequest
0 голосов
/ 28 апреля 2018

Вот моя простая программа:

#include "stdafx.h"
#include<Windows.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);

HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;

const int WIDTH = 512;
const int HEIGHT = 512;

DWORD screenBuffer[WIDTH * HEIGHT];


void draw(HWND hwnd) {
    HDC hWinDC = GetDC(hwnd);

    SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
    BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
    ReleaseDC(hwnd, hWinDC);
}

int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
    memset(screenBuffer, 0, sizeof(screenBuffer));
    MSG msg = { 0 };
    WNDCLASS wnd = { 0 };

    wnd.lpfnWndProc = WndProc;
    wnd.hInstance = hInstace;
    wnd.lpszClassName = L"Window";

    if (!RegisterClass(&wnd)) {
        return 0;
    }

    HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);

    if (!hwnd) {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    for (int i = 0; i <= 512; i++) {
        screenBuffer[i * WIDTH + 0] = 0x00FF0000;
    }

    while (true) {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                break;
            }

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }


        draw(hwnd);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){

    switch (msg){
        case WM_CREATE:
            initBackBuffer(hwnd);
            break;
        case WM_DESTROY:
            DeleteDC(hBackDC);
            DeleteObject(hBackBitmap);
            PostQuitMessage(0);
            break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

void initBackBuffer(HWND hwnd) {
    HDC hWinDC = GetDC(hwnd);

    hBackDC = CreateCompatibleDC(hWinDC);
    hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT); 
    SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));

    SelectObject(hBackDC, hBackBitmap);
    ReleaseDC(hwnd, hWinDC);
}

Выход соответствует ожидаемому.

Я переехал

const int WIDTH = 512;
const int HEIGHT = 512;

DWORD screenBuffer[WIDTH * HEIGHT]; 

в Global.h, и я добавил #include "Global.h" в свой основной файл.

Основной файл:

#include "stdafx.h"
#include<Windows.h>
#include "Global.h"

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);

HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;


void draw(HWND hwnd) {
    HDC hWinDC = GetDC(hwnd);

    SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
    BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
    ReleaseDC(hwnd, hWinDC);
}

int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
    memset(screenBuffer, 0, sizeof(screenBuffer));
    MSG msg = { 0 };
    WNDCLASS wnd = { 0 };

    wnd.lpfnWndProc = WndProc;
    wnd.hInstance = hInstace;
    wnd.lpszClassName = L"Window";

    if (!RegisterClass(&wnd)) {
        return 0;
    }

    HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);

    if (!hwnd) {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    for (int i = 0; i <= 512; i++) {
        screenBuffer[i * WIDTH + 0] = 0x00FF0000;
    }

    while (true) {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                break;
            }

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }


        draw(hwnd);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){

    switch (msg){
        case WM_CREATE:
            initBackBuffer(hwnd);
            break;
        case WM_DESTROY:
            DeleteDC(hBackDC);
            DeleteObject(hBackBitmap);
            PostQuitMessage(0);
            break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

void initBackBuffer(HWND hwnd) {
    HDC hWinDC = GetDC(hwnd);

    hBackDC = CreateCompatibleDC(hWinDC);
    hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT); 
    SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));

    SelectObject(hBackDC, hBackBitmap);
    ReleaseDC(hwnd, hWinDC);
}

Global.h

#pragma once


const int WIDTH = 512;
const int HEIGHT = 512;

DWORD screenBuffer[WIDTH * HEIGHT];

Я получаю ошибочное белое окно .

Я не понимаю, почему это происходит, потому что компилятор все равно скопирует содержимое Global.h в основной файл, поэтому оба варианта должны давать одинаковые результаты.

В чем причина этой проблемы?

1 Ответ

0 голосов
/ 28 апреля 2018

Здесь есть ошибка:

const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void foo()
{
    for (int i = 0; i <= 512; i++) {
        screenBuffer[i * WIDTH + 0] = 0x00FF0000;
    }
}

Это должно быть i < 512. В противном случае он перезаписывает случайную ячейку памяти, это может привести к ошибке в другом месте или к ошибке, если вам повезет. Отладчик может сообщить о бессмысленной ошибке или вообще не сообщать об ошибке. Если screenBuffer было создано в стеке, отладчик может выдать ошибку «повреждение кучи».

Попробуйте использовать std::vector, чтобы избежать этой проблемы в будущем.

vector<int> vec;
vec[vec.size()] = 0;//<- debug error

Примечание: SetDIBitsToDevice или StretchDIBits будут устанавливать биты напрямую:

void draw(HWND hwnd) 
{
    BITMAPINFO bi;
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biWidth = WIDTH;
    bi.bmiHeader.biHeight = HEIGHT;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biCompression = BI_RGB;
    HDC hdc = GetDC(hwnd);
    SetDIBitsToDevice(hdc, 0, 0, WIDTH, HEIGHT, 0, 0, 0, HEIGHT, screenBuffer,
        &bi, DIB_RGB_COLORS);
    ReleaseDC(hwnd, hdc);
}
...