在 WinAPI 中使用资源名称

Nic*_*ler 4 c++ winapi embedded-resource

在WinAPI中,您可以通过FindResource和访问资源LoadResource

根据的文档FindResource,您可以指定资源的名称:

lpName [输入]

类型:LPCTSTR

资源的名称。或者,该参数可以是 MAKEINTRESOURCE(ID),而不是指针,其中 ID 是资源的整数标识符。有关详细信息,请参阅下面的备注部分。

我有两个问题:

首先,这似乎并不准确,因为指定 ID 或文件名都不起作用。为参数输入的正确值是多少lpName
这另一个问题似乎也有这个问题

其次,我想知道是否可以在运行时检索资源的文件名。这可能吗?或者文件打包成资源后文件名就被丢弃了?

测试代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

Resource.rc
这不是整个文件,因为它包含大量样板代码。以下是相关的资源声明。

IDR_DRAWING1            BINARY                  "Drawing1.dwg"
IDI_ICON1               ICON                    "icon1.ico"
IDR_HTML1               HTML                    "html1.htm"
Run Code Online (Sandbox Code Playgroud)

.ico 和 .htm 是使用 Visual Studio 自动创建的;通过添加相应类型的新资源。所以他们的格式不应该弄乱FindResource声明。

资源.h

#define IDR_DRAWING1                    101
#define IDI_ICON1                       102
#define IDR_HTML1                       103
Run Code Online (Sandbox Code Playgroud)

编辑:

根据 Ben Voigt 的评论,我已经更改了Resource.rc文件,以便使用非数字名称:

DWG1                    BINARY                  "Drawing1.dwg"
ICON1                   ICON                    "icon1.ico"
HTML1                   HTML                    "html1.htm"
Run Code Online (Sandbox Code Playgroud)

现在,resource.h文件根本没有被使用。以下是新的相关测试:

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.
Run Code Online (Sandbox Code Playgroud)

因此,我对二进制资源的期望得到了满足,但是 和 发生了ICON什么HTML

Nic*_*ler 5

解决方案及结果:

\n

好吧,我终于得到了可预测的结果。

\n

查找资源的方式部分取决于资源类型。在本例中,DWG1BINARY自定义类型的资源。资源类型RT_*中不存在预定义的类型,因此您需要将类型指定为:LPCTSTR

\n
FindResource(hInstance, _T("DWG1"), _T("BINARY"));\n
Run Code Online (Sandbox Code Playgroud)\n

对于预定义资源类型,您不能将类型名称指定为LPCTSTR. 相反,您必须使用相应的RT_*值。这可能是因为每个RT_*值对应于一个MAKEINTRESOURCE(WORD),如果我的理解是正确的,则该宏结果指向可移植可执行文件中的无效地址,而不是资源类型的文本表示。

\n

这个问题涉及 MAKEINTRESOURCE

\n

资源的问题ICON1在于类型应该是RT_GROUP_ICON而不是RT_ICON。这两种类型的区别在于,前者与硬件无关,后者与硬件相关。不过,我不知道为什么RT_ICON不起作用。

\n

最后,问题HTML1是我的错误,因为我没有确保引用的文件实际上包含数据。在构建过程中,它可能被省略,因为它本质上是一个空资源。用于此资源的正确类型是RT_HTML

\n

现在,关于名字。正如 Ben Voigt 在对其答案的评论中提到的,需要非数字名称才能将名称指定为LPCTSTR. 如果使用数字名称,则必须使用数字名称MAKEINTRESOURCE

\n

Visual Studio 的资源编辑器使得用字符串而不是数字来命名资源有点麻烦,因为默认情况下它会为每个资源创建宏。然后,这些宏在预处理阶段将资源名称替换为数字。

\n

为了将名称更改为字符串,您有 2 个选项:

\n
    \n
  • ID用双引号将资源(在属性中找到)引起来。这可以防止资源编辑器为该名称创建宏。但是,如果将引号放在先前设置的周围,则宏可能已经存在ID
  • \n
\n

\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2 \xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 \xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2 \xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 \xc2\xa0资源属性

\n
    \n
  • 或者,在任何文本编辑器中打开资源脚本文件并选择类似的名称。同样,这个想法是为了防止生成宏。因此,分离资源脚本和资源标头是可行的,或者只需确保标头中不存在宏即可。
  • \n
\n