【问题标题】:What is the correct way to embed a resource in a reusable MFC class?将资源嵌入可重用 MFC 类的正确方法是什么?
【发布时间】:2012-08-01 01:03:28
【问题描述】:

我正在编写一个 C++(尤其是 MFC)类,它使用外部 .gif 图像文件并在经过一些处理后生成另一个图像文件。如果初始图像可以以某种方式嵌入到代码中,那就太好了。我在 MSDN 中阅读了有关使用多个 .rc 文件的信息,整个事情看起来相当复杂。

我想从经历过这个问题的人那里知道如何处理这个问题。

编辑:对不起,我不清楚。我正在编写的课程应该是独立的,所以我可以再次使用它。如果我将图像放在资源文件中,那么如果在新项目中使用该类将无法编译。

【问题讨论】:

  • 您是否希望在运行时或编译时将第二个生成的文件嵌入到 .exe 中?在编译时,您始终可以将 gif 导入资源文件并在代码中使用它。在运行时你不能真正做到这一点,唯一的方法是从磁盘读取它
  • 你用什么来阅读 gif?
  • @MarkRansom : 我正在使用 CImage::Load() 函数

标签: class mfc resource-files


【解决方案1】:

您不能将 MFC 资源嵌入到类或类似的 C++ 容器中。它们只能嵌入到 DLL 或 EXE 文件中——在生成的二进制文件的单独部分中。由于您希望您的类可重用,因此您必须将其放入 DLL 中。因此,您必须使用 AFX_EXT_CLASS 关键字标记您的课程。

有两种解决方案。

解决方案 #1:

  • 创建一个 MFC DLL 项目 (MFC Extension DLL)。称它为MyLibrary 或其他任何名称。
  • 将所有独立类放入此 DLL。
  • 嵌入所有必要的资源。
  • 让您的类从 DLL 的 HINSTANCE 加载资源,如下所述。

有几种方法可以检索 DLL 的 HINSTANCE。如果你问我,最好的解决方案是在DllMain 中获取它。如果您选择MFC Extension DLL 配置,这将自动完成:

static AFX_EXTENSION_MODULE MyLibDLL = { NULL, NULL }; // Make this variable global!
// Then access the hInstance as follows:
LoadResource(MyLibDLL.hModule, ...)

解决方案 #2:

将您的资源存储为字节缓冲区。或者更好的是,将其转换为 Base64 并将其存储为 ASCII 字符串。但请记住不要炸毁堆栈!在项目设置中保持资源较小或增加堆栈大小。示例:

const char *encodedResource = "SGVsbG8gd29ybGQh";
char *data = decode(encodedResource);
foo(data);

【讨论】:

  • 请问您选择了哪种解决方案?
【解决方案2】:

在解决方案资源管理器中转到资源视图,右键单击并单击Add Resource,然后单击Import 并添加 gif 文件。现在您可以使用 Resource ID 访问代码中的 gif 文件。

【讨论】:

    【解决方案3】:

    仅将文件添加到资源不会将该文件嵌入到实际资源文件中,它只是链接到该文件。如果你打开你的 .rc 文件,你会看到它是这样的:

    IDB_GIF_MYIMAGE     GIF     "artwork\\mygif.gif"
    

    在编译过程中,资源将包含在 EXE 中,您使用资源 ID IDB_GIF_MYIMAGE 引用它。您可以在其他项目中引用相同的文件,而无需复制该文件。

    【讨论】:

    • 是的,但是新项目会有自己的.rc文件,除非手动插入,否则不会包含资源。
    • 据我所知,没有 #pragma 允许您通过在 .h 或 .cpp 文件中指定资源来包含资源。因此,除非您愿意修改 .rc 文件或通过路径(而不是嵌入式资源)加载图像,否则您唯一的选择是将图像 BASE64 并将其作为文本包含,这将是管理的噩梦。
    【解决方案4】:

    要在不使用资源文件的情况下将图像(或任何其他类型的二进制数据)嵌入到您的类中,请使用 bin2c 实用程序,例如,您可以从此处下载它:http://www.opensource.apple.com/source/libpcap/libpcap-16/libpcap/msdos/bin2c.c。在文件上运行它会产生基本上是一个静态数组,其中文件的字节作为该数组的成员。将此数组填充到 .h 文件中(或将其放在类的标题中,或使其成为静态成员...),然后您将在内存中使用该文件,而无需使用 LoadResource() 及其兄弟.

    如果您想将它与 CImage::Load() 一起使用,您将必须编写自己的从 IStream 派生的类,并以某种方式实现一些方法,以便它们从内存中“读取”。我不知道有什么方法可以让 CImage 从 gif 文件的内存表示中解码图像。

    【讨论】:

    • 我知道这种方法。我正在寻找的是一种更清洁、更实用的嵌入图像的方法。 AFAIK 处理字节数组图像不是很方便。
    • “更干净、更实用”是什么意思?这种方法不符合您的要求怎么办?
    • 您在问题中声明您不想将图像放入资源中,因为当您将课程包含在另一个项目中时,您需要在资源部分中#include 其他资源。但是您确实想使用资源编辑器来编辑或查看图像。您不能同时拥有这两种方式 - 要么将图像放在单独的资源文件中,然后将其 #include 到要使用它的每个项目的资源部分,要么将图像放在代码中,在这种情况下,您将不会无法使用资源编辑器查看。
    【解决方案5】:

    我认为最好的解决方案只是记录要使用该类,您还必须将某个 .gif 文件导入到您的项目中,并为其指定一个预期的标识符(例如 IDB_MYCLASS_MYGIF)。然后您可以使用预处理器来检测资源是否已正确添加,例如:

    #ifndef IDB_MYCLASS_MYGIF
        #error Make sure you import mygif.gif to the project.  See docs for more info.
    #endif
    

    这将阻止类编译,直到用户正确导入图像。或者,如果未提供默认图像,您也可以使用 #ifdefs 回退到不使用默认图像的代码。

    【讨论】:

      【解决方案6】:

      查看http://www.codeproject.com/Articles/5371/ToDoList-6-5-4-Feature-Release-An-effective-and-fl 中提供的 CRuntimeDialog 类。它提供了一种从构成资源定义的字符串创建对话框的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-16
        • 2014-05-31
        • 1970-01-01
        • 2018-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多