对于rc资源中常见的类型:BITMAP、CURSOR和ICON,可以用LoadBitmap、LoadCursor和LoadIcon将它们加载到内存中,或者统一使用LoadImage API函数也可以。但是对于自定义类型的PNG、ZIP(在添加文件到资源中时会提示设定资源类型),则没有专门的函数来使用。LoadImage仅仅是支持BITMAP、CURSOR和ICON三种类型。
那应该如何将自定义类型的资源文件从rc资源加载到内存中或者导出呢?对于自定义类型的对象,可以使用FindResource、LoadResource、LockResource和SizeofResource等API函数来处理。大致的处理流程如下:
(i)先调用FindResource,根据资源ID和资源类型(注意:这个资源类型就是在资源中添加文件时提示输入的资源类型标识串,比如下面代码中的“PNG”和“ZIP”),找到资源信息块句柄;然后将句柄传给LoadResource去加载资源,将资源加载到全局内存中,注意此时不能直接操作返回的内存句柄;调用LockResource将资源数据锁住后再使用内存中的数据,进而可以进行资源的数据的拷贝或导出操作了;可以调用SizeofResource得到资源文件的大小。
(ii)当然在事务处理完之后,要调用UnlockResource解锁,最后调用FreeResource将调用LoadResource申请的内存释放掉。
为了说明相关函数的使用方法,下面给出从rc资源加载到内存中或者导出的例子代码。
1、将PNG图片读出到CImage对象中
由于PNG图片可以做到很多透明效果,界面用PNG后效果非常好,所以现在很多软件都会使用到。PNG图片在高版本的VS中都使用CImage类来加载,相关代码如下所示:(代码中的lpszType为“PNG”)
<span style="font-family:SimSun;font-size:14px;">CImage* CImageUtility::LoadCImage( UINT nID, LPCTSTR lpszType, HINSTANCE hInstance ) { CImage* pImage = NULL; // 兼容bmp的加载 if( RT_BITMAP == lpszType ) { pImage = new CImage(); pImage->LoadFromResource( hInstance, nID ); if ( !pImage->IsNull() ) { return pImage; } else { delete pImage; pImage = NULL; return pImage; } } CString strLog; HRSRC hRsrc = ::FindResource ( hInstance, MAKEINTRESOURCE(nID), lpszType ); ASSERT( hRsrc != NULL ); if ( NULL == hRsrc ) { return NULL; } DWORD dwSize = ::SizeofResource( hInstance, hRsrc); LPBYTE lpRsrc = (LPBYTE)::LoadResource( hInstance, hRsrc); ASSERT( lpRsrc != NULL ); if ( NULL == hRsrc ) { return NULL; } // 后面采用流加载的方式使用到了CreateStreamOnHGlobal,它需要使用HGLOBAL内存 HGLOBAL hMem = ::GlobalAlloc( GMEM_FIXED, dwSize ); if ( NULL == hMem ) { ::FreeResource( lpRsrc ); return NULL; } LPBYTE pMem = (LPBYTE)::GlobalLock( hMem ); if ( NULL == pMem ) { ::GlobalUnlock( hMem ); ::GlobalFree( hMem ); ::FreeResource( lpRsrc ); return NULL; } memcpy( pMem, lpRsrc, dwSize ); IStream * pStream = NULL; HRESULT hr = ::CreateStreamOnHGlobal( hMem, FALSE, &pStream); if ( pStream != NULL && hr == S_OK) { pImage = new CImage(); HRESULT hrs = pImage->Load( pStream ); pStream->Release(); // 释放资源 ::GlobalUnlock( hMem ); ::GlobalFree( hMem ); ::FreeResource( lpRsrc ); if ( hrs == S_OK ) { // 处理图片中的透明效果 if ( pImage->GetBPP() == 32 ) { for(int i = 0; i < pImage->GetWidth(); i++) { for(int j = 0; j < pImage->GetHeight(); j++) { unsigned char* pucColor = reinterpret_cast<unsigned char *>(pImage->GetPixelAddress(i , j)); pucColor[0] = pucColor[0] * pucColor[3] / 255; pucColor[1] = pucColor[1] * pucColor[3] / 255; pucColor[2] = pucColor[2] * pucColor[3] / 255; } } } return pImage; } else { delete pImage; pImage = NULL; return pImage; } } else { <pre name="code" class="cpp"> // 释放资源</span>::GlobalUnlock( hMem );::GlobalFree( hMem );::FreeResource( lpRsrc );return NULL;}}
2、将zip压缩文件导出到磁盘上
对于程序安装包来说,安装到目标安装路径的文件是要放到exe安装包中的,那怎样才能塞到安装包中呢?将相关的文件打包成zip文件,作为资源添加到资源列表中,启动安装的时候再从资源中取出来,释放到磁盘上在解压,然后执行文件的拷贝操作。从资源中导出文件的相关代码如下所示:
<span style="font-family:SimSun;font-size:14px;">void CProcessLogic::ExportResFile( CString strExportPath ) { // 导出system.zip CString strSysDir = strExportPath + _T("system.zip"); HRSRC hrSrcSys = FindResource( AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_ZIP_SYSDIR), _T("ZIP") ); HGLOBAL hGlobalSys = LoadResource( AfxGetResourceHandle(), hrSrcSys ); LPVOID lpGlobalSys = LockResource( hGlobalSys ); ret = 0; if( ret = file.Open( strSysDir, CFile::modeCreate | CFile::modeWrite) ) { file.Write( lpGlobalSys, (UINT)SizeofResource(AfxGetResourceHandle(), hrSrcSys) ); file.Close(); } ::UnlockResource(hGlobalSys); ::FreeResource( hGlobalSys ); }</span>
至于怎么解压zip包,使用网上常用的unzip.cpp文件即可。