Не удается установить список изображений кнопки

Вопрос или проблема

Я использую 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() не возвращает никаких ошибок.

Анализ и возможные причины проблемы

  1. Правильность структуры: Одна из распространенных ошибок заключается в неправильном использовании структуры BUTTON_IMAGELIST. Вам не нужно выделять память для этой структуры динамически, так как это приводит к утечке памяти и может вызвать неопределенное поведение.

  2. Инициализация и параметры структуры: Убедитесь, что вы правильно инициализируете поля структуры BUTTON_IMAGELIST, особенно himl, margin и uAlign.

  3. Необходимые манифесты: Также важно убедиться, что ресурсный файл правильно включает необходимые константы для манифеста, а именно для CREATEPROCESS_MANIFEST_RESOURCE_ID и RT_MANIFEST.

Рекомендуемые изменения

Предлагаю внести следующие корректировки в ваш код:

  1. Правильная инициализация 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, а не ее указатель. Это важный момент, поскольку передача некорректной структуры может привести к сбоям.

  2. Ограничение динамической памяти:
    Уберите динамическое выделение памяти для структуры, так как это приводит к утечкам памяти и проблемам в последующих вызовах.

  3. Проверьте ресурсы:
    Убедитесь, что идентификаторы ресурсов и другие параметры, связанные с 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.

Оцените материал
Добавить комментарий

Капча загружается...