C/C++ 实现动态资源文件释放

这篇具有很好参考价值的文章主要介绍了C/C++ 实现动态资源文件释放。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当我们开发Windows应用程序时,通常会涉及到使用资源(Resource)的情况。资源可以包括图标、位图、字符串等,它们以二进制形式嵌入到可执行文件中。在某些情况下,我们可能需要从可执行文件中提取自定义资源并保存为独立的文件。在这篇博客文章中,我们将讨论如何使用C++和WinAPI实现这个目标。

简介

首先,让我们考虑一个场景:我们有一个 Windows 应用程序,其中包含了一个自定义的二进制资源比如默认的配置文件,我们希望将这个资源提取出来并保存为一个独立的文件以用于初始化程序配置项。为了实现这个目标,我们可以使用Windows API提供的相关函数,来完成对资源的释放工作。

关键函数概述

GetModuleHandle

该函数用于获取指定模块的句柄。模块可以是一个可执行文件(例如 .exe 文件)或一个动态链接库(例如 .dll 文件)。该函数返回指定模块的实例句柄,以便在后续的操作中使用。

以下是 GetModuleHandle 函数的一般形式:

HMODULE GetModuleHandle(
  LPCTSTR lpModuleName
);

参数说明:

  • lpModuleName:指定要获取句柄的模块的名称。如果为 NULL,则返回调用线程的可执行模块句柄。

在许多情况下,GetModuleHandle 主要用于获取当前进程的模块句柄,以便在后续的操作中使用该句柄。模块句柄通常用于在进程中查找资源、定位函数地址等目的。

FindResource

该函数用于定位并返回指定模块(通常是 .exe 或 .dll 文件)中的资源。资源可以是诸如位图、图标、对话框模板、字符串等等的数据。

以下是 FindResource 函数的一般形式:

HRSRC FindResource(
  HMODULE hModule,
  LPCTSTR lpName,
  LPCTSTR lpType
);

参数说明:

  • hModule:指定包含资源的模块的句柄。如果为 NULL,则表示使用当前可执行模块的句柄。
  • lpName:指定资源的名称或标识符。可以是字符串或整数标识符。
  • lpType:指定资源的类型。通常是一个字符串,如 "RT_BITMAP" 表示位图资源。

如果找到,则返回指向资源的句柄(HRSRC)。这个句柄可以用于后续的资源加载和操作,函数的第二个参数经常配合MAKEINTRESOURCE一起使用,MAKEINTRESOURCE 是一个宏(macro),用于将整数标识符(ID)转换为字符串指针。在 Windows 编程中,通常用于标识资源的 ID。

#define MAKEINTRESOURCE(i) ((LPCTSTR)((DWORD)((WORD)(i))))

这个宏接受一个整数参数 i,然后将其转换为字符串指针。在资源标识符上下文中,通常将整数标识符转换为字符串是为了在使用相关资源函数时传递正确的参数。

举个例子,如果有一个字符串资源的标识符是 IDR_MYSTRING,则可以使用 MAKEINTRESOURCE 将其转换为字符串:

LPCTSTR pszResourceName = MAKEINTRESOURCE(IDR_MYSTRING);

在这里,pszResourceName 将指向字符串 "IDR_MYSTRING"。

在前面提到的 FindResource 中,通常将 MAKEINTRESOURCE(IDR_MYSTRING) 作为 lpName 参数传递给 FindResource。这是因为 FindResource 函数期望资源名称是字符串类型,而 IDR_MYSTRING 可能是一个整数标识符。通过使用 MAKEINTRESOURCE,则可以将整数标识符转换为字符串,以便正确地在资源中查找。

SizeofResource

该函数用于获取指定资源的大小。它返回资源的字节数,可以用于确定加载资源所需的内存大小。

以下是 SizeofResource 函数的一般形式:

DWORD SizeofResource(
  HMODULE hModule,
  HRSRC   hResInfo
);

参数说明:

  • hModule:指定包含资源的模块的句柄。如果为 NULL,则表示使用当前可执行模块的句柄。
  • hResInfo:指定资源的句柄,通常由 FindResource 返回。

SizeofResource 返回资源的大小,以字节为单位。这个函数在加载资源之前可以用来分配足够的内存空间。

LoadResource

该函数用于加载指定资源的数据。该函数返回一个全局内存块的句柄,该内存块包含了资源的实际数据,你可以通过 LockResource 函数获取该内存块的指针来访问资源数据。

以下是 LoadResource 函数的一般形式:

HGLOBAL LoadResource(
  HMODULE hModule,
  HRSRC   hResInfo
);

参数说明:

  • hModule:指定包含资源的模块的句柄。如果为 NULL,则表示使用当前可执行模块的句柄。
  • hResInfo:指定资源的句柄,通常由 FindResource 返回。

LoadResource 用于将资源数据加载到全局内存块中,并返回该内存块的句柄。在加载资源后,可以使用 LockResource 函数获取指向资源数据的指针。

LockResource

用于获取指定资源的数据指针。它接受一个全局内存块的句柄,该内存块通常由 LoadResource 函数返回,然后返回一个指向资源数据的指针。

以下是 LockResource 函数的一般形式:

LPVOID LockResource(
  HGLOBAL hResData
);

参数说明:

  • hResData:指定资源数据的全局内存块句柄,通常由 LoadResource 函数返回。

LockResource 用于锁定指定资源的全局内存块,并返回指向资源数据的指针。请注意,这个函数实际上并不执行拷贝,而是返回指向内存块的指针,因此对返回指针的任何修改都会直接影响到内存块本身。

FreeResource

用于释放由 LoadResource 函数加载的资源。这个函数通常用于释放不再需要的资源,以防止资源泄漏。

以下是 FreeResource 函数的一般形式:

BOOL FreeResource(
  HGLOBAL hResData
);

参数说明:

  • hResData:指定要释放的全局内存块句柄,通常由 LoadResource 函数返回。

FreeResource 用于释放之前由 LoadResource 加载的资源。请注意,这个函数通常在资源的生命周期结束时调用,以确保释放资源占用的内存。但在实际应用中,现代 Windows 应用通常不需要显式调用 FreeResource,因为 Windows 会在程序退出时自动释放资源。

在实际的应用程序中,FindResource 可以与 LoadResourceLockResource 等函数一起使用,用于加载和操作资源数据。当数据资源被加载到内存之后则可以直接通过fwrite函数将其直接写出到磁盘中,以此来实现释放资源的目的。

代码功能实现

首先新建一个控制台程序以作为本次的测试环境,接着准备好我们需要写出的数据,这里就准备一个lyshark.ini配置文件,在项目中右键选择添加并添加资源,此时会弹出如下图所示的提示信息;

C/C++ 实现动态资源文件释放

此时会弹出添加资源菜单,通过点击导入按钮并输入资源类型为LYSHARK点击确定保存这个更改,如下图所示;

C/C++ 实现动态资源文件释放

此时我们在主程序中引入#include "resource.h"包含资源头文件,并修改FindResource中的特定位置使其指向我们导入的配置文件,在释放时同样需要保持fopen("map\\lyshark.ini", "wb+")配置文件的格式。

C/C++ 实现动态资源文件释放

这段资源释放的完整代码如下所示;

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
#include <WinUser.h>
#include "resource.h"

BOOL UseCustomResource()
{
	// 定位我们的自定义资源
	HMODULE hModule = GetModuleHandle(NULL);
	if (hModule == NULL)
	{
		std::cerr << "错误:获取模块句柄失败。" << std::endl;
		return FALSE;
	}

	HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(IDR_LYSHARK1), TEXT("LYSHARK"));
	if (hRsrc == NULL)
	{
		std::cerr << "错误:无法找到资源。" << std::endl;
		return FALSE;
	}

	// 获取资源大小
	DWORD dwSize = SizeofResource(hModule, hRsrc);
	if (dwSize == 0)
	{
		std::cerr << "错误:无效的资源大小。" << std::endl;
		return FALSE;
	}

	// 加载资源
	HGLOBAL hGlobal = LoadResource(hModule, hRsrc);
	if (hGlobal == NULL)
	{
		std::cerr << "错误:无法加载资源。" << std::endl;
		return FALSE;
	}

	// 锁定资源
	LPVOID lpVoid = LockResource(hGlobal);
	if (lpVoid == NULL)
	{
		std::cerr << "错误:无法锁定资源。" << std::endl;
		FreeResource(hGlobal);  // 在返回前释放资源
		return FALSE;
	}

	// 如果不存在,创建一个“map”目录
	if (!CreateDirectory("map", NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
	{
		std::cerr << "错误:无法创建目录。" << std::endl;
		FreeResource(hGlobal);
		return FALSE;
	}

	// 将资源写入文件
	FILE* fp = fopen("map\\lyshark.ini", "wb+");
	if (fp == NULL)
	{
		std::cerr << "错误:无法创建或打开文件。" << std::endl;
		FreeResource(hGlobal);
		return FALSE;
	}

	fwrite(lpVoid, sizeof(char), dwSize, fp);
	fclose(fp);

	// 释放资源
	FreeResource(hGlobal);

	return TRUE;
}

int main(int argc, char* argv[])
{
	BOOL ref = UseCustomResource();
	std::cout << "释放状态: " << ref << std::endl;

	system("pause");
	return 0;
}

以管理员模式运行上述程序,并等待,此时会释放一个目录并包含一个配置文件,如下图所示的输出结果;

C/C++ 实现动态资源文件释放

结语

通过以上的代码实现,我们成功地将自定义资源提取并保存为一个独立的文件。这种技术在一些特殊情况下可能会很有用,例如需要动态加载或替换资源的情况。希望这篇博客对你理解如何使用 C++ 和 Windows API 进行资源操作有所帮助。文章来源地址https://www.toymoban.com/news/detail-749695.html

到了这里,关于C/C++ 实现动态资源文件释放的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Docker安装kkfileview,kkfileview在docker部署后预览出现预览中的字体样式与源文件不同的解决办法,动态水印 kkfileview漏洞修复

    目录 1.Docker安装kkfileview 2.kkfileview在docker部署后预览出现预览中的字体样式与源文件不同的解决办法 2.1. 物理机或虚拟机上运行  2.2. Docker容器环境环境运行  3.docker中更改kkfileview的配置文件application.properties 4.如何水印文本内容动态传值 动态水印 静态水印 5.扩展漏洞,修复

    2024年02月14日
    浏览(41)
  • C++共享之道:用extern实现源文件变量与类成员函数的巧妙共享

    概述: 在C++中,使用`extern`可实现在源文件之间共享变量与类成员函数。通过声明变量或类在头文件中,再在一个源文件中定义,其他源文件通过`extern`引用,促使模块化、可维护的代码组织。 在C++中, extern 可用于在源文件之间共享变量。它告诉编译器某个变

    2024年03月24日
    浏览(55)
  • 最新UI作品集源文件文件模板Sketch和Adobe XD源文件格式

    俗话说:人靠衣服马靠鞍!设计师要想进入面试环节,一个优秀的作品集是很有力的敲门砖。但是你想面试?你拿什么作品谈条件!你想跳槽?你拿什么作品跳槽! UI作品集 前几天更新过 今天小编给大家带来了 最新一整套作品集模板-64页 XD+Sketch格式的 可用于参考/学习/替换

    2024年02月11日
    浏览(52)
  • 【毕业设计】43-基于单片机的红外无线防盗报警系统设计与实现(原理图工程源文件+源代码+实物图+答辩论文)

    资料包含:毕业设计全套资料(精品) 原理图工程文件 原理图截图 PCB工程文件 实物图片 答辩论文低重复率文档,25923字 英文文献及翻译 主 要 研 究 内 容 、 方 法 和 要 求 主要研究内容: 基于单片机作为核心控制器,以89C52系列单片机来实现整个系统,需要人体检测设备

    2024年02月04日
    浏览(54)
  • vscode 无法打开源文件

    以下是c/c++插件的intelligense设置情况: 解决办法: 重新安装vsode无用;重新下载mingw64,管用了!(我猜可能是之前换电脑移植文件的时候导致了部分文件丢失)

    2024年02月07日
    浏览(47)
  • Figma怎么导出源文件?

    Figma 是一款备受网页和 UI 设计师喜爱的基于矢量的设计工具。那么,如何在 Figma 中导出源文件呢?本篇文章将为大家演示如何以更加简单的方式,从 Figma 快速、免费导出源文件。 即时设计 是一款拥有强大导入导出功能的设计工具,全面覆盖了 Figma 设计能力的且为全中文的

    2024年02月11日
    浏览(53)
  • VScode中添加头文件和源文件的方法

            在正常情况下,若同一文件夹下若头文件、源文件、和主要代码在同一文件夹下,则可以正常运行程序。 如图(此为Visual Studio 示例):   编译结果(无报错):     但在VScode中,同样的使用方式会产生报错。 如下:    main.c:  myheadfile.h: myheadfile.c:    报错如

    2023年04月09日
    浏览(43)
  • Visual Studio C++ 的 头文件和源文件

    在Visual Studio C++中,头文件(Header Files)和源文件(Source Files)是两种不同的文件类型,用于组织和管理C++代码。 头文件(Header Files): 后缀名为 .h 或 .hpp 的文件,例如 example.h 。 包含类、结构体、函数的声明、宏定义和类型定义等。 通常用于存放函数原型、类的声明、常

    2024年02月07日
    浏览(53)
  • CMake获取目录下所有源文件

    1、aux_source_directory指令         aux_source_directory( dir variable ) 比如:         aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} ALL_SOURCE) , 这样将当前目录所有的源文件(.cpp 和.c文件)都放到了ALL_SOURCE变量中,但是头文件并没有被包括进去,若在头文件有函数的实现部分,采用这

    2024年02月15日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包