在 WinAPI 中使用资源名称
Using resource names in WinAPI
在WinAPI中,您可以通过FindResource
and LoadResource
访问资源。
根据the documentation for FindResource
,可以指定资源名称:
lpName [in]
Type: LPCTSTR
The name of the resource. Alternately, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource. For more information, see the Remarks section below.
我有两个问题:
首先,这似乎并不准确,因为指定 ID 或文件名都不起作用。 lpName
参数的正确输入值是多少?
This other question seemed to have this issue as well
其次,我想知道是否可以在 运行 时检索资源的文件名。这可能吗?还是打包成资源后文件名被丢弃?
测试代码
#include <Windows.h>
#include <tchar.h>
#include "resource.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//This is the only test that succeeds.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_DRAWING1), _T("BINARY")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_DRAWING1); BINARY"), _T(""), MB_ICONERROR);
}
//This one fails.
if (!FindResource(hInstance, _T("IDR_DRAWING1"), _T("BINARY")))
{
MessageBox(NULL, _T("\"IDR_DRAWING1\"; BINARY"), _T(""), MB_ICONERROR);
}
//ICON - Each fails.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDI_ICON1), _T("ICON")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDI_ICON1); ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDI_ICON1"), _T("ICON")))
{
MessageBox(NULL, _T("\"IDI_ICON1\"; ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, MAKEINTRESOURCE(IDI_ICON1), RT_ICON))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDI_ICON1); RT_ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDI_ICON1"), RT_ICON))
{
MessageBox(NULL, _T("\"IDI_ICON1\"; RT_ICON"), _T(""), MB_ICONERROR);
}
//HTML - Each fails.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_HTML1), _T("HTML")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_HTML1); HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDR_HTML1"), _T("HTML")))
{
MessageBox(NULL, _T("\"IDR_HTML1\"; HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_HTML1), RT_HTML))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_HTML1); RT_HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDR_HTML1"), RT_HTML))
{
MessageBox(NULL, _T("\"IDR_HTML1\"; RT_HTML"), _T(""), MB_ICONERROR);
}
return 0;
}
Resource.rc
这不是整个文件,因为它包含大量样板代码。下面是相关的资源声明。
IDR_DRAWING1 BINARY "Drawing1.dwg"
IDI_ICON1 ICON "icon1.ico"
IDR_HTML1 HTML "html1.htm"
.ico 和 .htm 是使用 Visual Studio 自动创建的;通过添加相应类型的新资源。所以他们的格式不应该搞乱 FindResource
声明。
resource.h
#define IDR_DRAWING1 101
#define IDI_ICON1 102
#define IDR_HTML1 103
EDIT:
Per Ben Voigt's comment, I've gone ahead and changed the Resource.rc file so non-numeric names are used:
DWG1 BINARY "Drawing1.dwg"
ICON1 ICON "icon1.ico"
HTML1 HTML "html1.htm"
Now, the resource.h file isn't used at all. Following are the new relevant tests:
FindResource(hInstance, _T("DWG1"), _T("BINARY")); //Succeeds now.
FindResource(hInstance, _T("ICON1"), _T("ICON")); //Still fails.
FindResource(hInstance, _T("ICON1"), RT_ICON); //Still fails.
FindResource(hInstance, _T("HTML1"), _T("HTML")); //Still fails.
FindResource(hInstance, _T("HTML1"), RT_HTML); //Still fails.
So, my expectations are met for my binary resource, but what is happening with the ICON
and HTML
?
is the file name discarded once the file is packaged as a resource?
是的,完全正确。
例如ICON statement第一列是资源名,第三列是文件名..
nameID ICON filename
有些资源根本不是来自外部文件,例如 MENU statement 直接从资源脚本中嵌套的 MENU
和 MENUITEM
语句获取数据。 DIALOG
、STRINGTABLE
、VERSION
和 VERSIONINFO
只是一些不作为单独文件存在的其他公共资源。
解决方案和结果:
好的,所以我终于得到了可以预见的结果。
您查找资源的方式部分取决于资源类型。在这种情况下,DWG1
是一个 BINARY
资源,它是一种自定义类型。 resource types 中不存在预定义的 RT_*
,因此您需要将类型指定为 LPCTSTR
:
FindResource(hInstance, _T("DWG1"), _T("BINARY"));
对于预定义的资源类型,您不能将类型名称指定为 LPCTSTR
。相反,您必须使用相应的 RT_*
值。这可能是因为每个 RT_*
值对应一个 MAKEINTRESOURCE(WORD)
,如果我的理解是正确的,该宏结果指向 portable executable file 中的无效地址,而不是资源类型。
This questions addresses MAKEINTRESOURCE
ICON1
资源的问题是类型应该是 RT_GROUP_ICON
而不是 RT_ICON
。这两种类型的区别在于前者是hardware-independent,后者是hardware-dependent。虽然,我不知道为什么 RT_ICON
不起作用。
最后,HTML1
的问题是我的错,因为我没有确保引用的文件确实有数据。在构建期间,它可能被省略,因为它本质上是一个空资源。用于此资源的正确类型是 RT_HTML
.
现在,关于名字。正如 Ben Voigt 在对 his answer 的评论中提到的,需要 non-numeric 名称才能将名称指定为 LPCTSTR
。如果使用数字名称,则必须使用 MAKEINTRESOURCE
代替。
Visual Studio 的资源编辑器使得用字符串而不是数字命名资源有点麻烦,因为默认情况下它会为每个资源创建宏。这些宏然后在预处理阶段用数字替换资源名称。
为了将名称更改为字符串,您有 2 个选项:
- 用双引号将资源(在属性中找到)的
ID
括起来。这可以防止资源编辑器为该名称创建宏。但是,如果将引号放在先前设置的 ID
. 周围,则宏可能已经存在
- 或者,在任何文本编辑器中打开资源脚本文件并选择这样的名称。同样,这个想法是为了防止生成宏。因此,分离资源脚本和资源 header 是可行的,或者只需确保宏不存在于 header.
在WinAPI中,您可以通过FindResource
and LoadResource
访问资源。
根据the documentation for FindResource
,可以指定资源名称:
lpName [in]
Type: LPCTSTR
The name of the resource. Alternately, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource. For more information, see the Remarks section below.
我有两个问题:
首先,这似乎并不准确,因为指定 ID 或文件名都不起作用。 lpName
参数的正确输入值是多少?
This other question seemed to have this issue as well
其次,我想知道是否可以在 运行 时检索资源的文件名。这可能吗?还是打包成资源后文件名被丢弃?
测试代码
#include <Windows.h>
#include <tchar.h>
#include "resource.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//This is the only test that succeeds.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_DRAWING1), _T("BINARY")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_DRAWING1); BINARY"), _T(""), MB_ICONERROR);
}
//This one fails.
if (!FindResource(hInstance, _T("IDR_DRAWING1"), _T("BINARY")))
{
MessageBox(NULL, _T("\"IDR_DRAWING1\"; BINARY"), _T(""), MB_ICONERROR);
}
//ICON - Each fails.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDI_ICON1), _T("ICON")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDI_ICON1); ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDI_ICON1"), _T("ICON")))
{
MessageBox(NULL, _T("\"IDI_ICON1\"; ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, MAKEINTRESOURCE(IDI_ICON1), RT_ICON))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDI_ICON1); RT_ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDI_ICON1"), RT_ICON))
{
MessageBox(NULL, _T("\"IDI_ICON1\"; RT_ICON"), _T(""), MB_ICONERROR);
}
//HTML - Each fails.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_HTML1), _T("HTML")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_HTML1); HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDR_HTML1"), _T("HTML")))
{
MessageBox(NULL, _T("\"IDR_HTML1\"; HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_HTML1), RT_HTML))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_HTML1); RT_HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDR_HTML1"), RT_HTML))
{
MessageBox(NULL, _T("\"IDR_HTML1\"; RT_HTML"), _T(""), MB_ICONERROR);
}
return 0;
}
Resource.rc
这不是整个文件,因为它包含大量样板代码。下面是相关的资源声明。
IDR_DRAWING1 BINARY "Drawing1.dwg"
IDI_ICON1 ICON "icon1.ico"
IDR_HTML1 HTML "html1.htm"
.ico 和 .htm 是使用 Visual Studio 自动创建的;通过添加相应类型的新资源。所以他们的格式不应该搞乱 FindResource
声明。
resource.h
#define IDR_DRAWING1 101
#define IDI_ICON1 102
#define IDR_HTML1 103
EDIT:
Per Ben Voigt's comment, I've gone ahead and changed the Resource.rc file so non-numeric names are used:
DWG1 BINARY "Drawing1.dwg" ICON1 ICON "icon1.ico" HTML1 HTML "html1.htm"
Now, the resource.h file isn't used at all. Following are the new relevant tests:
FindResource(hInstance, _T("DWG1"), _T("BINARY")); //Succeeds now. FindResource(hInstance, _T("ICON1"), _T("ICON")); //Still fails. FindResource(hInstance, _T("ICON1"), RT_ICON); //Still fails. FindResource(hInstance, _T("HTML1"), _T("HTML")); //Still fails. FindResource(hInstance, _T("HTML1"), RT_HTML); //Still fails.
So, my expectations are met for my binary resource, but what is happening with the
ICON
andHTML
?
is the file name discarded once the file is packaged as a resource?
是的,完全正确。
例如ICON statement第一列是资源名,第三列是文件名..
nameID ICON filename
有些资源根本不是来自外部文件,例如 MENU statement 直接从资源脚本中嵌套的 MENU
和 MENUITEM
语句获取数据。 DIALOG
、STRINGTABLE
、VERSION
和 VERSIONINFO
只是一些不作为单独文件存在的其他公共资源。
解决方案和结果:
好的,所以我终于得到了可以预见的结果。
您查找资源的方式部分取决于资源类型。在这种情况下,DWG1
是一个 BINARY
资源,它是一种自定义类型。 resource types 中不存在预定义的 RT_*
,因此您需要将类型指定为 LPCTSTR
:
FindResource(hInstance, _T("DWG1"), _T("BINARY"));
对于预定义的资源类型,您不能将类型名称指定为 LPCTSTR
。相反,您必须使用相应的 RT_*
值。这可能是因为每个 RT_*
值对应一个 MAKEINTRESOURCE(WORD)
,如果我的理解是正确的,该宏结果指向 portable executable file 中的无效地址,而不是资源类型。
This questions addresses MAKEINTRESOURCE
ICON1
资源的问题是类型应该是 RT_GROUP_ICON
而不是 RT_ICON
。这两种类型的区别在于前者是hardware-independent,后者是hardware-dependent。虽然,我不知道为什么 RT_ICON
不起作用。
最后,HTML1
的问题是我的错,因为我没有确保引用的文件确实有数据。在构建期间,它可能被省略,因为它本质上是一个空资源。用于此资源的正确类型是 RT_HTML
.
现在,关于名字。正如 Ben Voigt 在对 his answer 的评论中提到的,需要 non-numeric 名称才能将名称指定为 LPCTSTR
。如果使用数字名称,则必须使用 MAKEINTRESOURCE
代替。
Visual Studio 的资源编辑器使得用字符串而不是数字命名资源有点麻烦,因为默认情况下它会为每个资源创建宏。这些宏然后在预处理阶段用数字替换资源名称。
为了将名称更改为字符串,您有 2 个选项:
- 用双引号将资源(在属性中找到)的
ID
括起来。这可以防止资源编辑器为该名称创建宏。但是,如果将引号放在先前设置的ID
. 周围,则宏可能已经存在
- 或者,在任何文本编辑器中打开资源脚本文件并选择这样的名称。同样,这个想法是为了防止生成宏。因此,分离资源脚本和资源 header 是可行的,或者只需确保宏不存在于 header.