VC中使用自定义资源

时间:2022-09-07 22:51:49

前言 

在VC环境中除了我们所常用的Dialog、Menu和Bitmap等标准资源类型之外,它还支持自定义资源类型(Custom Resource),我们自定义资源类型能做些什么呢?呵呵,用处多多。

1.      默认的皮肤压缩包或语言包。一些支持换肤的软件特别是一些媒体播放器常常有自定义的皮肤文件(你可以尝试将Media Player或千千静听等软件的Skins目录下的文件的扩展名改为.zip,然后使用WinZip打开看一下),但为了防止Skin文件丢失导致软件无 法显示,他们常常会在EXE文件中内置一套Skin作为默认的皮肤文件。同样,一些支持多语言的EXE文件中存在默认语言包也是这个道理(当然也可以使用 "String Table"资源类型);

2.      做为一些病毒/木马程序的寄生方式。如果不小心执行了带有病毒/木马的程序,它们会在你运行时释放出病毒/木马文件。当然许多病毒是将自身写入PE文件头来实现;

3.      合并EXE与它所需要的DLL文件。出于某些原因程序作者有时可能需要将DLL文件嵌入到可执行的EXE文件中,这可以通过使用自定义资源来实现;

4.      其它需要在程序中播放一个AVI动画等等,都可以通过将二进制的数据文件作为自定义资源加入到可执行文件中来实现;


添加资源

  添加资源时选择自定义,IDE会为你生成一个新的二进制资源,然后你就可以将你已经存在的二进制文件作为自定义的资源类型导入到项目中来了。

使用资源

  要使用自定义资源,我们可能要用到的几个API函数有FindResource、LoadResource和LockResource等,这里每一个函数的返回值分别作为下一个函数的参数,我来简要介绍一下。

    FindResource用来在一个指定的模块中定位所指定的资源:
HRSRC FindResource
(
     HMODULE hModule,        //包含所需资源的模块句柄,如果是程序本身,可以置为NULL
     LPCTSTR lpName,         //可以是资源名称或资源ID
     LPCTSTR lpType          //资源类型,在这里也就是我们自己指定的资源类型
);  
   
LoadResource用来将所指定的资源加载到内存当中;
HGLOBAL LoadResource
(
     HMODULE hModule,        //模块句柄,同上
     HRSRC hResInfo          //需要加载的资源句柄,这里也就是FindResource的返回值
);
             
LockResource用来锁定内存中的资源数据块,它的返回值也就是我们要使用的直系指向资源数据的内存指针;
LPVOID LockResource
(
     HGLOBAL hResData         //指向内存中要锁定的资源数据块,这里也就是LoadResource的返回值
); 

  另外我们还需要用SizeofResource来确定资源的尺寸,我们在操作资源时要用到它。

函数原型:DWORD SizeofResource(HMODULE hModule,HRSRC hReslnfo);
参数:
hModule:包合资源的可执行文件模块的句柄,如果是程序本身,可以置为NULL
hReslnfo:资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。
返回值:如果函数运行成功,返回值资源的字节数。如果函数运行失败,返回值为零。若想获得更多的错误信息,请调用GetLastError函数。

 在FindResource函数中经常用到宏MAKEINTERSOURCE来获得资源名称参数(LPCTSTR lpName),因为该参数需要LPCTSTR类型参数。MAKEINTERSOURCE是一个资源名转换的宏,这个宏是把一个数字类型转换成字符指针类型的宏,它不存在释放的问题。

它仅仅是把一个"数字形ID",转化为"字符串".但是执行前后,输入的数据的内容和长度是不变的!它只不过就是C语言里面"强制类型转换"而已.

用这个宏的主要原因是有的资源是用序号定义的,而不是字符串.所以要把数字转换成字符串指针,然后再传递给LoadResource之类的函数,这样才加载了资源.

要释放资源(用LoadResource加载的)可以调用FreeResource函数把LoadResource返回的指针传递给FreeResource.


在资源使用完毕后我们不需要使用 UnlockResource和FreeResource来手动地释放资源,因为它们都是16位Windows遗留下来的,在Win32中,在使用完毕后系统会自动回收。它们的使用很简单,大致上是这个样子的:

BOOL UseCustomResource()
{
        //定位我们的自定义资源,这里因为我们是从本模块定位资源,所以将句柄简单地置为NULL即可
        HRSRC hRsrc = Findresource(null, MAKEINTRESOURCE(ITEMID), TEXT("MyType"));
        if (NULL == hRsrc)
                return FALSE;

        //获取资源的大小
        DWORD dwSize = SizeofResource(NULL, hRsrc);
        if (0 == dwSize)
                return FALSE;

        //加载资源
        HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
        if (NULL == hGlobal)
                return FALSE;

        //锁定资源
        LPVOID pBuffer = LockResource(hGlobal);
        if (NULL == pBuffer)
                return FALSE;
    
       //我们用刚才得到的pBuffer和dwSize来做一些需要的事情。可以直接在内存中使
       //用,也可以写入到硬盘文件。这里我们简单的写入到硬盘文件,如果我们的自定
       //义资源是作为嵌入DLL来应用,情况可能要复杂一些。

        BOOL bRt = FALSE;
        FILE* fp = _tfopen(_T("demo.exe"), _T("wb"));
        if (fp != NULL)
        {
                if (dwSize == fwrite(pBuffer, sizeof(char), dwSize, fp))
                        bRt = TRUE;

                fclose(fp);
        }  

        //FreeResource(hGlobal);
        return bRt;


使用实例

功能:寻找软件中的资源(type:HELP_FILE,  Id:IDR_HELP_FILE1),并在本地临时文件夹temp中生成对应资源的文件(涉及查找资源中文件、加载资源到内存、得到资源大小、将资源内存写入文件),并打开文件

</pre><p><pre name="code" class="cpp">CString szPath, szDir;
TCHAR buf[MAX_PATH];
szPath.Empty();
szDir.Empty();

GetTempPath(MAX_PATH, buf);
szDir = buf;
szPath = szDir + _T("Help.pdf");

if (GFun::ReleaseRes(szPath, (WORD)IDR_HELP_FILE1, _T("HELP_FILE")) == TRUE)
{
	ShellExecute(NULL, _T("OPEN"), szPath, NULL, szDir, SW_SHOWNORMAL);
}


bool ReleaseRes(CString strFileName, WORD wResID, CString strFileType)
{
	// 资源大小    
	DWORD   dwWrite = 0;

	// 创建文件    
	HANDLE  hFile = CreateFile(strFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
					CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		return false;
	}

	// 查找资源文件中、加载资源到内存、得到资源大小    
	HRSRC   hrsc = FindResource(NULL, MAKEINTRESOURCE(wResID), strFileType);
	HGLOBAL hG = LoadResource(NULL, hrsc);
	DWORD   dwSize = SizeofResource(NULL, hrsc);

	// 写入文件    
	WriteFile(hFile, hG, dwSize, &dwWrite, NULL);
	CloseHandle(hFile);

	return true;
}


 说明: 

1、GetTempPath的功能是获取系统当前用户的临时文件夹路径,如:C:\Users\XXX\AppData\Local\Temp

2、ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件、打开一个目录、打印一个文件等等),并对外部程序有一定的控制。