如何将位图加载到 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 上编译。
控制台没有任何输出,所以没有错误。但是,图像永远不会出现。这些问题似乎解决了类似的问题,但我已经看过它们并找不到解决方案:
- I cannot load image from folder using win32
- Win32 application. HBITMAP LoadImage fails to load anything
问题可能出在哪里?
完整代码:
#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);
}
您只是将位图加载到内存中,但实际上并没有在任何地方显示它。您需要:
创建子 STATIC
control on your window, giving it the SS_BITMAP
window style, and then send it a STM_SETIMAGE
消息。
使用 CreateCompatibleDC()
and SelectObject()
, and then copy that HDC
onto your window's HDC
(returned by BeginPaint()
) using BitBlt()
or StretchBlt()
将您的 window 的 WM_PAINT
消息处理程序 select 位图放入内存中 HDC
。
您只需更改 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
我正在尝试在 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 上编译。
控制台没有任何输出,所以没有错误。但是,图像永远不会出现。这些问题似乎解决了类似的问题,但我已经看过它们并找不到解决方案:
- I cannot load image from folder using win32
- Win32 application. HBITMAP LoadImage fails to load anything
问题可能出在哪里?
完整代码:
#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);
}
您只是将位图加载到内存中,但实际上并没有在任何地方显示它。您需要:
创建子
STATIC
control on your window, giving it theSS_BITMAP
window style, and then send it aSTM_SETIMAGE
消息。使用
CreateCompatibleDC()
andSelectObject()
, and then copy thatHDC
onto your window'sHDC
(returned byBeginPaint()
) usingBitBlt()
orStretchBlt()
将您的 window 的WM_PAINT
消息处理程序 select 位图放入内存中HDC
。
您只需更改 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