如何将位图加载到 Win32 应用程序中?

How do I load a bitmap into a Win32 application?

我正在尝试在 Win32 应用程序中加载位图,但由于某些奇怪的原因,位图没有加载。这是我目前所拥有的:

HANDLE hImg = LoadImageW(
    NULL,
    L"img.bmp",
    IMAGE_BITMAP,
    0,
    0,
    LR_LOADFROMFILE
);
if (hImg == NULL) {
    std::cout << GetLastError();
}

使用 -Wall -municode 在 GCC 8.1.0 上编译。

控制台没有任何输出,所以没有错误。但是,图像永远不会出现。这些问题似乎解决了类似的问题,但我已经看过它们并找不到解决方案:

问题可能出在哪里?

完整代码:

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <iostream>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
    const wchar_t CLASS_NAME[] = L"Window Class";

    WNDCLASS wc = {};

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,
        CLASS_NAME,
        L"My Application",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (hwnd == NULL) {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    HANDLE hImg = LoadImageW(
        NULL,
        L"img.bmp",
        IMAGE_BITMAP,
        0,
        0,
        LR_LOADFROMFILE
    );
    if (hImg == NULL) {
        std::cout << GetLastError();
    }

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);

            FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

            EndPaint(hwnd, &ps);
            break;
        }
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

您只是将位图加载到内存中,但实际上并没有在任何地方显示它。您需要:

您只需更改 window 程序即可完成 WM_PAINT 中的所有绘图。图像加载成功后,创建一个内存DC,select将位图放入内存DC,并将内存DC绘制到目标window DC上。

当不再需要来自 LoadImage 的位图句柄时,应将其删除 DeleteObject(或 DestroyCursor/DestroyIcon,具体取决于加载的资源)

HANDLE hImg = NULL;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{
    switch (uMsg) 
    {
    case WM_CREATE:
        if (!hImg)
            hImg = LoadImage(NULL, L"img.bmp", IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
        if (!hImg) { DWORD err = GetLastError(); std::cout << err; }
        return 0;

    case WM_PAINT: 
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

        if (hImg) {
            BITMAP bm;
            GetObject(hImg, sizeof(bm), &bm);//get bitmap dimension
            auto memdc = CreateCompatibleDC(hdc);
            auto oldbmp = SelectObject(memdc, (HBITMAP)hImg);
            BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);
            SelectObject(memdc, oldbmp);//restore memdc
            DeleteDC(memdc);//delete memdc, we don't need it anymore
        }

        EndPaint(hwnd, &ps);
        return 0;
    }

    case WM_DESTROY:
        if (hImg) DeleteObject(hImg);//release resource
        hImg = NULL;
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

使用GetLastError时,确保函数在失败后立即被调用。示例:

if (hImg == NULL) 
{
    DWORD err = GetLastError();
    std::cout << err << '\n';
}

如果已经定义了UNICODE,我们可以使用LoadImage代替LoadImageW