VC++从工程的rc资源中将资源文件取出来或读出来(附源码)

       VisualStudio的rc资源中常见的类型有BITMAP、CURSOR和ICON,这些图片资源可以用LoadBitmap、LoadCursor和LoadIcon等API函数将它们加载到内存中,或者统一使用LoadImage API函数也可以。但对于自定义类型的PNG、XML、ZIP等类型的资源(在添加文件到资源中时会提示设定资源类型),则没有专门的API函数可供使用。因为LoadImage仅仅是支持BITMAP、CURSOR和ICON三种类型。

1、使用场景分析

       在我们自己写代码制作程序安装包(一个独立的setup.exe)时,我们需要将要打包的文件压缩到一个zip包,添加到安装包工程的资源中。在双击执行安装包程序时,则要先将资源中的zip读取出来解压到磁盘上,然后将程序的文件拷贝到安装目录中。这种场景就需要从rc资源中将zip包读取出来。

2、从rc资源中导出资源的流程

        那应该如何将自定义类型的资源文件从rc资源加载到内存中或者导出呢?对于自定义类型的对象,可以使用FindResource、LoadResource、LockResource和SizeofResource等API函数来处理。大致的处理流程如下: 

       1)先调用FindResource,根据资源ID和资源类型(注意:这个资源类型就是在资源中添加文件时提示输入的资源类型标识串,比如下面代码中的“PNG”和“ZIP”),找到资源信息块句柄;然后将句柄传给LoadResource去加载资源,将资源加载到全局内存中,注意此时不能直接操作返回的内存句柄;调用LockResource将资源数据锁住后再使用内存中的数据,进而可以进行资源的数据的拷贝或导出操作了;可以调用SizeofResource得到资源文件的大小。

       2)当然在事务处理完之后,要调用UnlockResource解锁,最后调用FreeResource将调用LoadResource申请的内存释放掉。

        上述相关函数的使用,在接下来的例子中会有详细的展现。

3、从rc资源中导出zip文件的示例代码

void ExportResFile( CString strExportPath )
{   
    // 将rc资源中的zip包导出到磁盘上
    CString strDstPath = strExportPath + _T("setup.zip");
    HRSRC hrSrcSys = FindResource( AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_ZIP_SETUP), _T("ZIP") );
    HGLOBAL hGlobalSys = LoadResource( AfxGetResourceHandle(), hrSrcSys );
    LPVOID lpGlobalSys = LockResource( hGlobalSys );
 
    ret = 0;
    if( ret = file.Open( strDstPath, CFile::modeCreate | CFile::modeWrite) )
    {
        file.Write( lpGlobalSys, (UINT)SizeofResource(AfxGetResourceHandle(), hrSrcSys) );
        file.Close();
    }

    ::UnlockResource(hGlobalSys);
    ::FreeResource( hGlobalSys );
}

4、从rc资源中将png图片读到CImage对象中

       下面我们再来展现一下如何将png图片从rc资源中读取出来,其实和zip包的读取是类似的。      由于PNG图片可以做到很多透明效果,界面用PNG后效果非常好,所以现在很多软件都会使用到。PNG图片在高版本的VS中都使用CImage类来加载,相关代码如下所示:(代码中的lpszType为“PNG”)

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(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
	{       
        ::GlobalUnlock( hMem );
        ::GlobalFree( hMem );
        ::FreeResource( lpRsrc );
        return NULL;
    }
}

你可能感兴趣的:(VC++常用功能代码封装,C++,VC++,资源,zip,png)