将全局变量添加到另一个文件中时的奇怪行为

时间:2018-04-28 06:25:07

标签: c++ winapi gdi

这是我的简单程序:

#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);
}

output符合预期。

我搬了

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];

我得到了错误的white window

我不明白为什么会发生这种情况,因为编译器无论如何都会将Global.h的内容复制到主文件中,因此两种变体都应该产生相同的结果。

这个问题的原因是什么?

1 个答案:

答案 0 :(得分:3)

这里有一个错误:

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,则调试器可能会给出#cr;堆损坏&#34;错误。

考虑使用std::vector以避免此问题。

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

旁注:SetDIBitsToDeviceStretchDIBits将直接设置位:

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);
}