Вопрос или проблема
Я использую MinGW32 с IDE Code::Blocks на Windows 10. Я пытаюсь присвоить список изображений кнопке через “BUTTON_IMAGELIST”, но функция “SendMessage” всегда терпит неудачу (возвращает ‘0’). Однако “GetLastError()” также не дает мне ошибку. Присвоение одного изображения кнопке работает, но при использовании списка изображений кнопка остается пустой. Что я делаю не так?
main.cpp
#include <iostream>
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
HIMAGELIST ImageList;
LRESULT CALLBACK WindowProcedure ( HWND WindowHandle, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_CREATE:
{
HWND ButtonOne = CreateWindowEx( 0, "BUTTON", "", BS_PUSHBUTTON | BS_BITMAP | WS_CHILD | WS_VISIBLE, 40, 10, 50, 50, WindowHandle, (HMENU)( IDC_BUTTON_ONE ), GetModuleHandle( nullptr ), nullptr );
HANDLE Image = LoadImage( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDB_BITMAP_SQUARE ), IMAGE_BITMAP, 50, 50, LR_DEFAULTCOLOR );
ImageList = ImageList_Create( 50, 50, ILC_COLORDDB, 1, 0 );
ImageList_Add( ImageList, (HBITMAP)Image, nullptr );
RECT rect = { 0, 0, 50, 50 };
BUTTON_IMAGELIST *ButtonImageList = new BUTTON_IMAGELIST;
ButtonImageList->himl = ImageList;
ButtonImageList->margin = rect;
ButtonImageList->uAlign = BUTTON_IMAGELIST_ALIGN_CENTER;
std::cout << SendMessage( ButtonOne, BCM_SETIMAGELIST, (WPARAM)0, (LPARAM)( ButtonImageList ) ); //output = 0
}
break;
case WM_DESTROY:
ImageList_Destroy( ImageList );
PostQuitMessage ( 0 );
break;
default:
return DefWindowProc ( WindowHandle, message, wParam, lParam );
}
return 0;
}
const std::string WindowClassName = "CommonControlsTest";
int WINAPI WinMain ( HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow )
{
INITCOMMONCONTROLSEX *ComCon;
ComCon->dwSize = sizeof( INITCOMMONCONTROLSEX );
ComCon->dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx( ComCon );
HWND WindowHandle;
MSG Messages;
WNDCLASSEX WindowClass;
WindowClass.hInstance = hThisInstance;
WindowClass.lpszClassName = WindowClassName.c_str();
WindowClass.lpfnWndProc = WindowProcedure;
WindowClass.style = CS_DBLCLKS;
WindowClass.cbSize = sizeof ( WNDCLASSEX );
WindowClass.hIcon = LoadIcon ( NULL, IDI_APPLICATION );
WindowClass.hIconSm = LoadIcon ( NULL, IDI_APPLICATION );
WindowClass.hCursor = LoadCursor ( NULL, IDC_ARROW );
WindowClass.lpszMenuName = NULL;
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_BACKGROUND );
if ( !RegisterClassEx ( &WindowClass ) )
return 0;
WindowHandle = CreateWindowEx ( 0, WindowClassName.c_str(), "Common Controls Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 300, HWND_DESKTOP, NULL, hThisInstance, NULL );
ShowWindow ( WindowHandle, nCmdShow );
UpdateWindow( WindowHandle );
while ( ( GetMessage ( &Messages, NULL, 0, 0 ) ) )
{
TranslateMessage( &Messages );
DispatchMessage( &Messages );
}
return Messages.wParam;
}
resource.rc
#include "Resource.h"
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "CommonControlsTest.exe.manifest"
IDB_BITMAP_SQUARE BITMAP "Square.bmp"
resource.h
#define IDC_BUTTON_ONE 101
#define IDB_BITMAP_SQUARE 201
CommonControlsTest.exe.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="CompanyName.ProductName.YourApplication"
type="win32"
/>
<description>Ваше описание приложения здесь.</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
Ваш файл resource.h
должен определить константы CREATEPROCESS_MANIFEST_RESOURCE_ID
и RT_MANIFEST
как 1 и 24 соответственно.
resource.h
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
#define IDC_BUTTON_ONE 101
#define IDB_BITMAP_SQUARE 201
Также вам не нужно динамически выделять BUTTON_IMAGELIST
(вы теряете его):
RECT rect = { 0, 0, 50, 50 };
BUTTON_IMAGELIST ButtonImageList;
ButtonImageList.himl = ImageList;
ButtonImageList.margin = rect;
ButtonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER;
std::cout << SendMessage( ButtonOne, BCM_SETIMAGELIST, 0, (LPARAM) &ButtonImageList );
Ответ или решение
Проблема, которую вы описываете, связана с использованием функции SendMessage
для установки списка изображений в кнопку Windows. Давайте детально разберем вашу проблематику и предложим решения.
Введение
Вы используете MinGW32 с IDE Code::Blocks на Windows 10. У вас возникла трудность при попытке назначить список изображений для кнопки с помощью сообщения BCM_SETIMAGELIST
. Функция SendMessage
всегда возвращает ‘0’, что указывает на неуспех, однако GetLastError()
не возвращает никаких ошибок.
Анализ и возможные причины проблемы
-
Правильность структуры: Одна из распространенных ошибок заключается в неправильном использовании структуры
BUTTON_IMAGELIST
. Вам не нужно выделять память для этой структуры динамически, так как это приводит к утечке памяти и может вызвать неопределенное поведение. -
Инициализация и параметры структуры: Убедитесь, что вы правильно инициализируете поля структуры
BUTTON_IMAGELIST
, особенноhiml
,margin
иuAlign
. -
Необходимые манифесты: Также важно убедиться, что ресурсный файл правильно включает необходимые константы для манифеста, а именно для
CREATEPROCESS_MANIFEST_RESOURCE_ID
иRT_MANIFEST
.
Рекомендуемые изменения
Предлагаю внести следующие корректировки в ваш код:
-
Правильная инициализация
BUTTON_IMAGELIST
:
Измените способ инициализации вашей структуры следующим образом:RECT rect = { 0, 0, 50, 50 }; BUTTON_IMAGELIST ButtonImageList; // Объявляем переменную на стеке ButtonImageList.himl = ImageList; ButtonImageList.margin = rect; ButtonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; // Теперь передаем адрес структуры в SendMessage std::cout << SendMessage(ButtonOne, BCM_SETIMAGELIST, 0, (LPARAM)&ButtonImageList);
Обратите внимание, что вы передаете адрес структуры
ButtonImageList
, а не ее указатель. Это важный момент, поскольку передача некорректной структуры может привести к сбоям. -
Ограничение динамической памяти:
Уберите динамическое выделение памяти для структуры, так как это приводит к утечкам памяти и проблемам в последующих вызовах. -
Проверьте ресурсы:
Убедитесь, что идентификаторы ресурсов и другие параметры, связанные сCREATEPROCESS_MANIFEST_RESOURCE_ID
иRT_MANIFEST
, указаны правильно вresource.h
:#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 #define RT_MANIFEST 24 #define IDC_BUTTON_ONE 101 #define IDB_BITMAP_SQUARE 201
Заключение
После внесения упомянутых выше модификаций ваша кнопка должна корректно отображать изображения из заданного списка изображений. Важно также удостовериться, что изображение загружается корректно из ресурса. Если проблема сохранится, проверьте, что изображение действительно загружается и добавляется в список изображений, а также, что параметры кнопки и управление сообщениями настроены правильно.
Применяя данные советы, вы устраните основные причины, которые могли вызвать проблему с установкой списка изображений для кнопки в вашем приложении на Windows.