当前位置:C++技术网 > 资讯 > 资源怎么使用:6 如何使用文本文件资源

资源怎么使用:6 如何使用文本文件资源

更新时间:2015-06-24 22:28:45浏览次数:1+次

HRSRC  hData = FindResource(NULL,MAKEINTRESOURCE(IDR_TXT),_T("txt"));// - 获取资源
HGLOBAL hRes = LoadResource(NULL,hData);  // - 加载资源到内存
LPVOID pData = LockResource(hRes);// - 获取资源的内存指针
int iResSize = SizeofResource(NULL,hData);// - 获取资源大小

CStringA str;// - 声明窄字符串,用来存储资源数据,因为txt文件时ANSI编码的,因此是窄字符的,所以用窄字符串接收。
memcpy(str.GetBuffer(iResSize),pData,iResSize);// - 复制内存数据到缓冲
str.ReleaseBuffer(iResSize);// - 释放缓冲
CStringW msg(str);// - 将窄字符串转换成
MessageBox(msg);  // - 消息框显示


    资源使用原理,请阅读《资源怎么使用:自定义资源使用原理介绍》。

    代码解释:
    FindResource函数,第一个参数设置为NULL,表示为程序自己。如果是直接在自己的资源中加载,设置为空即可。第二个参数是资源的名称字符串,这时我们需要按照字符串。一般使用的是ID宏,此宏代表一个数字,并不是字符串。所以此处需要将数字ID转换成资源名称字符串,这就是MAKEINTRESOURCE宏的作用,传入ID,返回的就是字符串名称。如果想直接使用名字,则给资源ID命名时,在资源的属性中的ID中,使用英文字符双引号修改ID即可。见下图。
    命名完后,在资源视图可以看到资源的id是字符串形式的了。见下图:

    此时就可以直接传入这个字符串,而不需要MAKEINTRESOURCE了。
    代码类似于:

HRSRC  hData = FindResource(NULL,L"id",_T("txt"));// - 获取资源

    FindResource最后一个参数就是资源类型。如果是自定义类型,则没有默认的,此时需要传入的值就是添加自定义时的资源的类型名称,使用字符串传入,如上面的_T("txt")。而对于内置类型的,可以直接使用内置的类型宏。内置的类型列表如下:


RT_ACCELERATOR 加速键表
RT_ANICURSOR 动画光标 
RT_ANIICON 动画图标 
RT_BITMAP 位图资源 
RT_CURSOR 硬件依赖光标资源 
RT_DIALOG 对话框
RT_DLGINCLUDE   
RT_FONT 字体资源
RT_FONTDIR 字体目录
RT_GROUP_CURSOR 硬件无关的光标资源(独立于硬件)
RT_GROUP_ICON 硬件无关的图标资源(独立于硬件)
RT_HTML HTML网页文件  
RT_ICON 硬件依赖图标资源
RT_MANIFEST Windows XP: 混合的XML MANIFEST配置文件
RT_MENU 菜单资源 
RT_MESSAGETABLE 消息表资源
RT_PLUGPLAY 热插拔资源
RT_RCDATA 应用定义的资源(原始数据)
RT_STRING 字符串表
RT_VERSION 版本资源
RT_VXD VXD 


    FindResource返回的值就是资源信息块的句柄值,如果失败则为NULL。其实就是在可执行模块所在的位置。LoadResource函数则通过这个句柄在模块的数据段中加载这个资源,如果没有这个句柄,是找不到资源的。如果FindResource传入的是其他程序的实例句柄,则可以加载其他EXE或者dll文件的资源。
    LoadResource函数的第一个参数与FindResource一样。第二个参数就是FindResource函数返回的句柄。这样就将资源从模块加载到内存了,并返回一个句柄。通过这个句柄就可以在内存中找到加载进去的资源。但是只是一个句柄,不能直接操作数据,详细了解句柄,请阅读《浅析Windows中句柄Handle的本质》。
    LockResource函数用来锁定内存中的资源数据块,返回指向资源的地址的指针。在资源使用完毕后我们不需要使用UnlockResource和FreeResource来手动地释放资源,因为它们都是16位Windows遗留下来的,在Win32中,在使用完毕后系统会自动回收。这个是为了兼容以前的版本,才使用这个函数名字,名字的意思不代表函数的功能,此处只是返回指向资源起始地址的指针,通过这个指针就可以操作资源了。
    因为我实现保存的是ANSI文本文件,因此使用CStringA来接收。
    通过memcpy内存复制函数,将资源的二进制数据复制到字符串缓冲中。当然此处也可以使用char数组。而MessageBox是接受宽字符的,所以最后又将窄字符传给宽字符初始化为宽字符,并显示出来。

    下面给出宽字符的版本:

int iResSize = SizeofResource(NULL,hData)-2;// - 获取资源大小
CStringW str=L"";// - 宽字符串接收Unicode编码的文本文件。
memcpy(str.GetBuffer(iResSize),((char*)pData)+2,iResSize);// - 复制内存数据到
str.ReleaseBuffer(iResSize);
MessageBox(str);

    只是宽窄不一样,其他的部分都一样。就不多说。想了解宽窄字符的知识,请阅读《宽字符串与窄字符串的相互转换》。
    这样就将文本文件显示在消息框中了。当然,也可以他用,此处只是显示文本文件的内容,其他的自己发挥,原理一样。

    最后说明一点:
    系统自带的记事本保存的Unicode文本文件,前两个字节是0xff0xfe。这就是Unicode版本要在长度减掉2字节的原因。这个不是文本的内容,是windows为了区别ANSI和Uicode所设置的。所以,在读取Unicode版本的txt时,起始地址要+2。这样才读到的是真正的有效数据。
    而这样读取出来的是文件的所有数据。当然,文件很可能不是以空字符结尾的,如果出现乱码,可以在复制到缓冲后,在结尾加上一个空字符,或者声明一个字符数组,先清零初始化,然后接受,也可以。