Windows C++自定义通知窗口图片加载失败问题求助
自定义Windows通知窗口图片加载失败排查与解决
问题背景
开发一款可发送自定义通知的Windows C++程序,通知窗口能正常显示,但图片无法加载。尝试用ChatGPT排查,但因其知识截止到2021年9月,无法适配API更新给出有效方案。
相关代码
#include <Windows.h> #include <Shellapi.h> // Constants #define WM_CLOSENOTIFICATION (WM_USER + 1) #define BUTTON_OPENURL_ID 100 #define BUTTON_CLOSE_ID 101 #define IDB_NOTIFICATION_BITMAP 108 // Replace with your bitmap resource ID // Global variables HWND hMainWindow; HWND hNotificationWindow; HBITMAP hBitmap; // Function to create and show the notification window void ShowNotification() { // Get the screen dimensions int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenHeight = GetSystemMetrics(SM_CYSCREEN); // Calculate the center position for the notification window int notificationWidth = 400; // Set your desired width int notificationHeight = 200; // Set your desired height int notificationX = (screenWidth - notificationWidth) / 2; int notificationY = (screenHeight - notificationHeight) / 2; // Create the custom notification window hNotificationWindow = CreateWindow( L"NotificationWindowClass", // Class name L"Custom Notification", // Window title WS_POPUP | WS_VISIBLE | WS_BORDER, // Window styles notificationX, notificationY, // Position notificationWidth, notificationHeight, // Size nullptr, nullptr, nullptr, nullptr // Parent window, Menu handle, Instance, Additional data ); // Load the bitmap resource hBitmap = LoadBitmap(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDB_NOTIFICATION_BITMAP)); if (hBitmap == nullptr) { OutputDebugStringA("Error Bitmap Null Value"); // Display appropriate error message or take necessary actions } // Create a static control for the image HWND hImageStatic = CreateWindow( L"STATIC", // Window class name nullptr, // Text content (empty for image) WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_CENTERIMAGE, // Window styles 10, 10, notificationWidth - 20, notificationHeight - 20, // Position and size hNotificationWindow, nullptr, nullptr, nullptr // Parent window, Menu handle, Instance, Additional data ); SendMessage(hImageStatic, STM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>(hBitmap)); // Create a button to open a website HWND hOpenButton = CreateWindow( L"BUTTON", // Window class name L"Open Website", // Text content WS_CHILD | WS_VISIBLE | BS_CENTER | BS_DEFPUSHBUTTON, // Window styles 10, notificationHeight - 60, (notificationWidth - 40) / 2, 30, // Position and size hNotificationWindow, reinterpret_cast<HMENU>(BUTTON_OPENURL_ID), nullptr, nullptr // Parent window, Menu handle, Instance, Additional data ); // Create a button to close the notification HWND hCloseButton = CreateWindow( L"BUTTON", // Window class name L"Close", // Text content WS_CHILD | WS_VISIBLE | BS_CENTER | BS_DEFPUSHBUTTON, // Window styles 20 + (notificationWidth - 40) / 2, notificationHeight - 60, (notificationWidth - 40) / 2, 30, // Position and size hNotificationWindow, reinterpret_cast<HMENU>(BUTTON_CLOSE_ID), nullptr, nullptr // Parent window, Menu handle, Instance, Additional data ); } // Window procedure for the notification window LRESULT CALLBACK NotificationWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: // Handle command messages if (LOWORD(wParam) == BUTTON_OPENURL_ID) { // Open a website when the button is clicked ShellExecute(nullptr, L"open", L"https://example.com", nullptr, nullptr, SW_SHOWNORMAL); } else if (LOWORD(wParam) == BUTTON_CLOSE_ID) { // Show the main window again ShowWindow(hMainWindow, SW_SHOW); // Clean up and exit the notification window DestroyWindow(hNotificationWindow); } break; case WM_CLOSE: // Show the main window again ShowWindow(hMainWindow, SW_SHOW); // Clean up and exit the notification window DestroyWindow(hNotificationWindow); break; } return DefWindowProc(hWnd, message, wParam, lParam); } // Entry point int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { // Create and register the window class for the notification window WNDCLASS wc = {}; wc.lpfnWndProc = NotificationWindowProc; wc.hInstance = hInstance; wc.lpszClassName = L"NotificationWindowClass"; RegisterClass(&wc); // Create the main window hMainWindow = CreateWindow( L"MainWindowClass", // Window class name L"Main Window", // Window title WS_OVERLAPPEDWINDOW, // Window styles CW_USEDEFAULT, CW_USEDEFAULT, // Position CW_USEDEFAULT, CW_USEDEFAULT, // Size nullptr, nullptr, hInstance, nullptr // Parent window, Menu handle, Instance, Additional data ); // Show the main window ShowWindow(hMainWindow, nCmdShow); // Show the initial notification ShowNotification(); // Message loop MSG msg = {}; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Clean up resources if (hBitmap != nullptr) { DeleteObject(hBitmap); } return 0; }
补充信息
- VS中.rc文件截图显示:资源定义内包含ID为108的位图资源
IDB_NOTIFICATION_BITMAP - 程序运行效果:通知窗口正常显示,但图片区域为空,仅可见按钮和窗口边框
排查与解决方案
1. 替换老旧的位图加载API
LoadBitmap是兼容性较差的旧API,在高DPI环境或资源格式不匹配时易加载失败,改用LoadImage替代:
// 替换原LoadBitmap代码 hBitmap = (HBITMAP)LoadImage( GetModuleHandle(nullptr), MAKEINTRESOURCE(IDB_NOTIFICATION_BITMAP), IMAGE_BITMAP, 0, 0, // 按资源原始尺寸加载,可指定宽高强制缩放 LR_DEFAULTCOLOR | LR_SHARED );
若需适配高DPI,可结合GetDpiForWindow获取当前窗口DPI值,计算缩放后的宽高传入LoadImage。
2. 修正资源释放逻辑
调用STM_SETIMAGE后,静态控件会接管位图资源的所有权,原代码在消息循环结束后删除位图会导致资源提前释放。应在通知窗口销毁时释放资源,修改窗口过程:
LRESULT CALLBACK NotificationWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { // ... 保留原有WM_COMMAND、WM_CLOSE处理逻辑 case WM_DESTROY: if (hBitmap != nullptr) { DeleteObject(hBitmap); hBitmap = nullptr; } break; } return DefWindowProc(hWnd, message, wParam, lParam); }
3. 增强错误排查能力
添加详细错误日志,通过GetLastError获取具体错误码,快速定位问题:
if (hBitmap == nullptr) { DWORD errCode = GetLastError(); char errMsg[256]; sprintf_s(errMsg, "位图加载失败,错误码:%lu", errCode); OutputDebugStringA(errMsg); }
常见错误码对应问题:
ERROR_RESOURCE_NAME_NOT_FOUND:资源名称/ID不匹配ERROR_RESOURCE_TYPE_NOT_FOUND:资源类型错误(非BITMAP)ERROR_FILE_NOT_FOUND:位图文件路径错误或缺失
4. 项目资源编译检查
- 确认位图文件已正确添加到项目,.rc文件被包含在编译流程中
- 检查位图格式是否为BMP(
LoadBitmap仅支持BMP,LoadImage支持更多格式但需对应参数) - 清理项目后重新编译,确保资源被正确嵌入可执行文件
内容的提问来源于stack exchange,提问作者Michael Guida
相关产品推荐
相关产品推荐

