Windows资源
Windows资源是一种二进制数据,由链接器链接进程序成为程序的一部分,通过资源的方式可以很方便的对应用程序进行扩展。在Windows中资源可以是系统自定义的,也可以是用户自定义的。在VC++中资源是以被称为资源脚本的文本文件描述的(扩展名为rc),另外为了方便代码中调用资源,VC++环境中还会自动生成一个resource.h的头文件供C++代码使用,这个文件中主要定义了各个资源的ID,在vc++中使用ID来唯一标识一个资源,这个ID可以是数字也可以是字符串,其实在VC中真正用来标识资源的是字符串,通过宏MAKEINTRESOURCE可以将数字型的ID转化为对应的字符串,一般的资源函数在操作资源时都需要提供一个资源的字符串,而这个串就是利用这个宏传入ID生成的。
在VC中资源脚本的基本格式为:
资源名(ID串) 类型名 [语言] 资源数据
资源数据可以是一段指定格式的文本或者一个文件,比如我们将wav作为资源加入到程序中,可以这样写:
MY_WAVE_RES IDR_WAVE sample.wav.其中语言如果没有指定,那么默认为操作系统当前的语言环境。
另外我们也可以将不同的资源放入不同的文本文件中,先定义好,然后在.rc文件中使用#include 来包含进来,比如在一个名为wav.resinclude文件中定义了一个WAV资源,然后可以在.rc文件中加上一句
“#include
引用自定义资源
对于系统自定义资源,系统都提供了专门的函数来进行加载和操作,但是对于自定义资源,在操作时相对比较复杂,一般先使用FindResource和FindResourceEx在进程中找到对应的资源句柄,然后使用LoadResource将资源加载到内存中,以后就可以使用这个资源了。
下面的一个例子演示了如何在当前exe中如何将另一个EXE作为资源加载,并执行它。
__inline VOID GetAppPath(LPTSTR pszBuf)
{
DWORD dwLen = 0;
if(0 == (dwLen = ::GetModuleFileName(NULL,pszBuf,MAX_PATH)))
{
printf("获取APP路径失败,错误码0x%08x\n",GetLastError());
return;
}
DWORD i = dwLen;
for(; i > 0; i -- )
{
if( '\\' == pszBuf[i] )
{
pszBuf[i + 1] = '\0';
break;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hModule = GetModuleHandle(NULL);
HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
if (INVALID_HANDLE_VALUE == hRsrc)
{
printf("加载自定义资源失败!\n");
return 0;
}
HGLOBAL hGlobalRes = LoadResource(hModule, hRsrc);
LPVOID pResMem = LockResource(hGlobalRes);
DWORD dwSize = SizeofResource(hModule, hRsrc);
if (NULL == pResMem)
{
printf("获取资源所在内存失败!\n");
return 0;
}
TCHAR szFilePath[MAX_PATH] = _T("");
GetAppPath(szFilePath);
StringCchCat(szFilePath, MAX_PATH, _T("test.exe"));
HANDLE hFile = CreateFile(szFilePath, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, 0, NULL);
if(!WriteFile(hFile, pResMem, dwSize, &dwSize, NULL))
{
printf("写文件失败\n");
return 0;
}
CloseHandle(hFile);
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
CreateProcess(szFilePath, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
为了执行上面的代码需要在该项目工程中新加一个资源,将目标EXE添加到资源中,其中资源文件会多出一行”IDR_RCDATA1 RCDATA “E:\Program\ResourcesDemo\Debug\stdWindow.exe” 在resource.h文件中生成了一个资源对应的ID,做好这些工作,该程序就能正常运行
在上面的代码中,依次调用FindResource、 LoadResource、LockResource,获取资源在进程空间中的地址,并将它对应的物理页面锁定在内存中,不允许其进行内存交换。然后将这个部分的内存写入到文件形成一个新的exe,最后执行这个exe,最终上面的程序编译运行后我们会发现在程序对应的目录下会生成一个test.exe文件。
更新资源
在有的时候需要对程序中的资源进行更新,这种情况下一般是在原始的工程下 更改资源,然后重新编译,但是这个时候用户需要下载新的更新程序,在原始程序比较大的情况下,为了更改一个简单的资源就要重新花大量的时间下载并更新程序,可能有点杀鸡用牛刀的意思,在我们只需要更新程序中的资源的情况下,Windows提供了一种方法。
1. 首先使用BeginUpdateResource建立可执行程序文件模块的更新句柄
2. 使用UpdateResource传入之前的更新句柄,更新资源数据
3. 使用EndUpdateResource函数关闭修改句柄,如果想让整个更改存盘需要将函数的第二个参数传入FALSE,这个参数的意思是是否放弃更新,传入false表示保存更新
下面是一个简单的例子
HMODULE hModule = GetModuleHandle(NULL);
//加载资源
HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(IDI_ICON1), RT_GROUP_ICON);
if (hRsrc == NULL)
{
printf("加载资源失败\n");
return GetLastError();
}
HGLOBAL hIcon = LoadResource(hModule, hRsrc);
PVOID pIconBuf = LockResource(hIcon);
int nIconSize = SizeofResource(hModule, hRsrc);
//更新资源
HANDLE hUpdate = BeginUpdateResource(_T("E:\\Program\\ResourcesDemo\\Debug\\stdWindow.exe"), TRUE);
BOOL bRet = UpdateResource(hUpdate, MAKEINTRESOURCE(RT_GROUP_ICON), MAKEINTRESOURCE(IDI_STDWINDOW), GetUserDefaultLangID(), pIconBuf, nIconSize);
bRet = EndUpdateResource(hUpdate, FALSE);
return 0;
枚举资源
枚举资源主要使用函数EnumResourceTypes EnumResourceNames, 和EnumResourceLanguages,这几个函数分别枚举资源类型,名称和语言,在msdn中查找函数的定义发现他们的调用顺序必须是type name language,下面是一个简单的枚举的例子:
BOOL CALLBACK EnumResLangProc(HANDLE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam)
{
printf("\tlanguage :%d\n", wIDLanguage);
return TRUE;
}
BOOL CALLBACK EnumRe1sNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
{
if ((ULONG)lpszName & 0xffff0000)
{
printf("\t名称:%s\n", lpszName);
}else
{
printf("\t名称:%d\n", (USHORT)lpszName);
}
return EnumResourceLanguages(hModule, lpszType, lpszName, (ENUMRESLANGPROCW)EnumResLangProc, NULL);
}
BOOL CALLBACK EnumResTypeProc(HMODULE hModule, LPTSTR lpszType,LONG_PTR lParam)
{
if ((ULONG)lpszType & 0xFFFF0000)
{
printf("类型:%s\n", lpszType);
}else
{
printf("类型:%d\n", (USHORT)lpszType);
}
return EnumResourceNames(hModule, lpszType, (ENUMRESNAMEPROCW)EnumRe1sNameProc, NULL);
}
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hExe = LoadLibrary(_T("E:\\Program\\ResourcesDemo\\Debug\\stdWindow.exe"));
if (hExe == NULL)
{
printf("加载目标程序出错!\n");
return GetLastError();
}
printf("目标程序中包含以下资源:\n");
EnumResourceTypes(hExe, EnumResTypeProc, NULL);
return 0;
}
这段代码有以下几点需要注意:
1. LoadLibrary不仅仅可以用来加载dll,实际上它可以加载任意的PE文件到内存,而GetModuleHandle是在内存中查找已经存在的一个模块的句柄,而我们这个地方这个exe事先并没有加载到内存,所以这里用GetModuleHandle是不能正确加载的,只有使用LoadLibrary
2. 这几个枚举函数都需要一个回调函数,这些函数指针类型可以在msdn中查找到,在VC环境下也定义了这些函数指针,但是不知道为什么在填入函数指针时需要强制转化,否则会报错
3. 资源可以使用字符串表示,也可以使用ID表示,这些回调函数虽说传入的都是枚举到的字符串指针,但是它仍然可能是ID,所以在这不能简单的直接把他们作为字符串使用,需要进行判断,判断的依据是它是否大于65536,因为我们说只有在ID值大于这个时,系统才会将ID作为字符串来使用
Windows资源的更多相关文章
- LR监控Windows资源
1.监控准备: 监控方: 1)安装tcp/ip协议下的netbios 2)用administrator登录 被监控方: 1)被监控的Windows开启两个服务: Remote ProcedureCal ...
- Loadrunner 添加windows资源没反应
使用 LoadRunner Controller 添加Windows资源系统没有反应, 解决办法 : 1.关闭Windows 防火墙 2.若使用的不是本机 1) 首先要启动所监测机器的remote r ...
- 利用Windows资源监视器解决文件夹无法改名无法删除问题
在win7等Windows系统操作文件夹更名.删除时经常会报错,操作无法完成,balabala 这个时候仅凭在用的软件去一个一个找是很难的,即便软件全关了,还有后台进程,,,奔溃吧 好了,现在我们有了 ...
- Windows资源监控神器——perfmon
一.简述 笔者在用lr中control监控Windows资源的时候,有时候总是遇到卡死和报错,所以就发现了Windows自带的监控神器————perfmon. Perfmon提供了图表化的系统性能实时 ...
- 分享一些 WINDOWS 资源站点(备用)
分享一些 WINDOWS 资源站点(备用) Windows Embedded http://www.10down.net/windows-embedded.php Windows 7 SP1 Upd ...
- Qt之添加Windows资源文件(.rc文件)
简述 在Windows下使用Qt时,通常会用到Windows的资源文件 - 为exe设置信息,其中包括:文件说明.产品名称.产品版本.版权等信息... 由于是Windows平台相关的东西,Qt助手中对 ...
- Qt之Windows资源文件(.rc文件)
简述 在Windows下使用Qt时,通常会用到Windows的资源文件 - 为exe设置信息,其中包括:文件说明.产品名称.产品版本.版权等信息... 由于是Windows平台相关的东西,Qt助手中对 ...
- windows 资源监视器
windows的资源监视器有很强大的资源监视能力 win+r输入resmon.exe即可打开
- WINDOWS资源编译器出错信息
ACCELERATORS语句的type域应包含ASCⅡ值或VIRTKEY值. BEGIN expected in table BEGIN关键字应紧跟在ACCELERATOR ...
随机推荐
- android 自己创建一个凝视模板
android 自己创建一个凝视模板 作为一名程序猿 不仅要有一个写代码的能力,养成一个良好的编写习惯也是非常重要的. 今天给大家具体介绍一下怎样创建凝视模板,给每一个类和方法都自己手动去凝视信息也 ...
- MySQL数据库使某个不是主键的字段唯一
在使用MySQL数据的过程中有时候我们须要某个不是主键的字段不反复.这个时候就要用到SQL的UNIQUE约束了. 以下摘抄自w3school里的一段介绍: UNIQUE 约束唯一标识数据库表中的每条记 ...
- bmp文件格式中rgb555与rgb888之间的转换,24位与16位位图的转换
今日,有同事问我.rgb555模式下的位图文件的格式问题,于是花了一下午的时间通过推測与測试,分析出了例如以下bmp文件在rgb555模式下的文件存储规律: 1:bmp文件的文件信息头中的biBitC ...
- Vue深度学习(5)-过渡效果
简介 通过 Vue.js 的过渡系统,你可以轻松的为 DOM 节点被插入/移除的过程添加过渡动画效果.Vue 将会在适当的时机添加/移除 CSS 类名来触发 CSS3 过渡/动画效果,你也可以提供相应 ...
- 【Java入门提高篇】Day10 Java代理——静态代理
今天要介绍的是一个Java中一个很重要的概念--代理. 什么是代理?联系生活想想看,代理似乎并不陌生,最形象的代表便是经纪人,明星一般都有经纪人,经纪人作为中间人,负责代理明星的相关事宜,比如说,有人 ...
- 将java项目打包为jar
打开Eclipse,点击file,选择export 选择java,选择其中的JAR file并点击next 选择需要的到处的项目,并在下方输入将项目保存为的目录,文件名字. 如果,已经将项目打包为一个 ...
- 前后端分离ueditor富文本编辑器的使用-Java版本
最近在写一个自己的后台管理系统(主要是写着玩的,用来熟悉后端java的知识,目前只是会简单的写点接口),想在项目中编写一个发布新闻文章的功能,想到了使用百度的ueditor富文本编辑器,网上找了很多j ...
- for in,Object.keys()与for of的区别
for in 1.for in一般用于遍历对象的属性: 2.作用于数组的for in除了会遍历数组元素外,还会遍历自定义可枚举的属性,以及原型链上可枚举的属性:3.作用于数组的for in的遍历结果是 ...
- Xcode极速代码,征服Xcode
当谈论到iOS开发工具时,有一个肯定是所有iOS开发者都熟悉的,那就是Xcode.Xcode是使所有令人赞叹的iOS app成为可能的驱动力. Xcode能帮助我们完成非常多的事情,但是这也有点让人头 ...
- 手动安装cloudera manager 5.x(tar包方式)详解
官方共给出了3中安装方式:第一种方法必须要求所有机器都能连网,由于最近各种国外的网站被墙的厉害,我尝试了几次各种超时错误,巨耽误时间不说,一旦失败,重装非常痛苦.第二种方法下载很多包.第三种方法对系统 ...