MAKEINTRESOURCE详解

一、引言

在Windows开发中,总免不了载入一些资源(resource)。例如,在rc文件中,声明图标资源:

/
//
// 图标
//

IDI_SMALL               ICON         "small.ico"

加载图标可以用下面的方式:

HICON hIcon = (HICON)LoadImage(hInstance, L"small.ico", IMAGE_ICON, 0, 0, 0);

或者:

HICON hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_SMALL), IMAGE_ICON, 0, 0, 0); // 标记为A

这两种方式是等价的,第一种方式中,为LoadImage的第二个参数传入资源的名称,第二种方式中,传入资源的ID,不过要加上一个MAKEINTRESOURCE。

那么MAKEINTRESOURCE是个什么东西呢?


二、疑惑

在Unicode环境下,

#define MAKEINTRESOURCE  MAKEINTRESOURCEW

#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))

又因为

typedef wchar_t WCHAR;
typedef WCHAR *LPWSTR, *PWSTR;

所以,在Unicode环境下,

MAKEINTRESOURCE(i)

就是

((wchar_t*)((ULONG_PTR)((WORD)(i))))

因此,我们可以将MAKEINTRESOURCE看作一个函数:

wchar_t *MakeIntResource(WORD i)
{
    return (wchar_t*)i;
}

这样一来就很清楚了,就是把一个WORD解释成wchar_t*。如果IDI_SMALL为40001,前文那行标记为A的代码就等价于:

HICON hIcon = (HICON)LoadImage(hInstance, (wchar_t*)40001, IMAGE_ICON, 0, 0, 0);

这就让人感到奇怪。以字符串的形式传递名称(L"small.ico")好理解,把ID(40001)以wchar_t*的方式传进去算怎么回事?LoadImage在其内部如何知道传进来的是资源的ID还是一个字符串的首地址呢?


三、原理

原来,Windows有这么一个性质:任何一个变量,它的地址一定大于等于65536。例如,定义一个变量:

int n = 0;

我们可以作出一个断言:

ASSERT(reinterpret_cast<UINT_PTR>(&n) >= 65536);

这个断言在Windows上是永远成立的。

这时,所有的疑惑都可以解开了。

由于MAKEINTRESOURCE宏会先把宏参数转换成WORD,所以通过MAKEINTRESOURCE得到的wchar_t*一定不超过65535。

如此一来,在使用MAKEINTRESOURCE向LoadImage传递资源ID的时候,LoadImage可以通过第二个参数值决定应该把传入的参数作为ID还是一个字符串的首地址。

猜测LoadImage的实现是这样的:

HANDLE _LoadImage(
    _In_opt_ HINSTANCE hInst,
    _In_ const wchar_t *name,
    _In_ UINT type,
    _In_ int cx,
    _In_ int cy,
    _In_ UINT fuLoad
    )
{
    if ((ULONG_PTR)name >> 16 == 0)
    {
        // 传入的是ID
    }
    else
    {
        // 传入的字符串
    }

    // 其他代码
}

转载于:https://my.oschina.net/jthmath/blog/414074

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值