【问题标题】:WinAPI: Displaying an image on a button - common way doesn't workWinAPI:在按钮上显示图像 - 常用方法不起作用
【发布时间】:2017-04-04 14:58:00
【问题描述】:

这让我很头疼:我不能使用给定的位图显示在按钮上 - Windows 说这是一个“无效参数”

这是我的代码:

// creating the button
const HWND hButton=::CreateWindow("button","text",WS_CHILD|VS_VISIBLE,0,0,100,100,hParent,0,editor.m_hInstance,NULL);
// loading the bitmap to be shown on a button
const HBITMAP hBmp=(HBITMAP)::LoadImage(editor.m_hInstance,MAKEINTRESOURCE(ID_MYBITMAP),IMAGE_BITMAP,0,0,LR_LOADTRANSPARENT);
// associating the bitmap with a button that lacks the BS_BITMAP style (I want both image and text to be shown)
::SendMessage( hButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp );
// getting the error
const int err=::GetLastError(); // returns 0x56, "Invalid parameter"

请注意,我可以在表单的画布上显示加载的图像,因此图像确实正确加载。

我尝试了位图的各种分辨率(每像素 4 位,每像素 8 位,标准调色板,真彩色,每像素 32 位) - 没有任何效果。我阅读了关于这个主题的大量先前问题,所有这些问题都声称::LoadImage / BM_SETIMAGE 组合是最终解决方案 - 到目前为止没有结果。

所以我的两个问题:

1) 图像要显示在按钮上是否需要满足任何要求?

2) 如果不是,那我到底做错了什么?

非常感谢您的回复。

托马斯

【问题讨论】:

  • 好吧,对于初学者来说,GetLastError 在这里不相关:大多数实际上通过SetLastError 传递错误代码的 Windows API 函数都被记录为这样做 - 通常可以从 'kernel32.lib' 获得函数。
  • 是的,我很想了解更多关于执行BM_SETIMAGE 时失败的信息,但GetLastError 是我在这种情况下能想到的最佳选择。
  • SendMessage 调用有一个返回值。当发送BM_SETIMAGE 消息时,它会将句柄返回到先前设置的图像。您将不得不查看返回值。此外,您需要设置某些button styles 才能显示图像,但您的问题没有显示创建按钮的代码(或资源脚本)。不要让我们猜测,而是提供minimal reproducible example
  • GetLastError() 仅在 SendMessage 调用本身失败时才有意义。
  • 按钮只有WM_CHILDWM_VISIBLE 样式。它没有设置BS_BITMAP(用于显示文本和图像)。

标签: c++ image winapi button bitmap


【解决方案1】:
const int err=::GetLastError(); // returns 0x56, "Invalid parameter"

首先,错误0x56 是网络错误。见System error codes

ERROR_INVALID_PASSWORD
86 (0x56)
指定的网络密码不正确。

这不可能。您可能会收到错误0x57 (ERROR_INVALID_PARAMETER)

其次,这是如何进行错误检查:

HBITMAP hBmp = (HBITMAP)::LoadImage(editor.m_hInstance, 
    MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP, 0, 0, LR_LOADTRANSPARENT);
DWORD error;
if(!hBmp)
{
    error = GetLastError();
    //report error
}

SetLastError(0);
SendMessage(hButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
error = GetLastError();
//report the result, it may not be an error

GetLastError 必须紧跟在失败的函数之后。如果你把GetLastError放在一个随机的地方,那么错误信息是没有意义的。

问题可能是您没有在应用程序中启用视觉样式。确保将视觉样式添加到清单文件中。

如果使用 Visual Studio,您只需将此行添加到您的 *.cpp 或 *.h 文件之一:

#pragma comment(linker,"/manifestdependency:\"type='win32' 
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' 
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

【讨论】:

  • SendMessage 不会(实际上也不能)报告BM_SETIMAGE 的错误。 NULL 的返回值表示以前该按钮没有关联的位图。这并不意味着对SendMessage 的调用失败。我相信这是一种情况,您将始终调用GetLastError,并测试已知/有趣的错误代码。
  • @IInspectable 你是对的,我编辑了答案。如果未设置视觉样式,错误0x57 将立即出现在SendMessage 之后,但显然SendMessage 将不会给出失败或未失败的指示。
  • SendMessageBM_SETIMAGE 不能报告错误,因为所有返回值都是有效的。虽然返回 HBITMAP(如 CreateBitmap)的其他 API 通过返回 NULL 来表示错误,但在发送 BM_SETIMAGE 消息时,该值是潜在的成功代码。
  • 抱歉让您感到困惑 - 错误代码确实是 87,而不是 86,谢谢 Barmak Shemirani。但是我很害怕,我已经完全按照您的建议使用了 Common Controls 版本 6,但它仍然无法正常工作。而且我还检查了错误之前调用SendMessage - 它为零,所以导致错误的是BM_SETIMAGE。那里会有一些非常愚蠢的事情。我将尝试一段时间,如果我没有找到解决方案,我将把自己变成一个所有者绘制的按钮作为最终解决方案。
【解决方案2】:

编写此代码(删除hButton的声明并编写我的代码):

在 main.cpp 中:

HWND hButton = CreateWindow("bttn", NULL, 
WS_VISIBLE | WS_CHILD, | 
BS_BITMAP,100,100,100,100,hwnd, 

(HMENU)44,NULL,NULL);

HBITMAP hBmp = LoadBitmap(g_hInstance, MYBMP);

在 bmp.h 中

#define TEMP 21
#define MYBMP MAKEINTRESOURCE(TEMP)

在set.rc中

#define TEMP 21
TEMP BITMAP"bitmap.bmp"

【讨论】:

    猜你喜欢
    • 2012-10-08
    • 2012-07-23
    • 2019-02-06
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 2019-03-10
    相关资源
    最近更新 更多