www.pudn.com > isee_code01231.zip > CurModule.cpp
// CurModule.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include "CurModule.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static char ModuleProcessImgType[]="CUR"; // 本模块能处理的图像类型
static char WriterList[]="YZ"; // 本模块的作者列表
static char WriterMess[]="Hello!!! 这里光标的给^_^";// 作者留言
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
// 在图像读写模块中,如果想分配内存,请使用API函数GlobalAlloc()
// ,如果想释放内存请使用GlobalFree()函数。不要使用诸如:new
// 、malloc()等函数。这是为了使各模块之间可以异地释放内存。
//
//
/////////////////////////////////////////////////////////////////////////////
// CIcoModuleApp
BEGIN_MESSAGE_MAP(CCurModuleApp, CWinApp)
//{{AFX_MSG_MAP(CIcoModuleApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CIcoModuleApp construction
CCurModuleApp::CCurModuleApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CIcoModuleApp object
CCurModuleApp theApp;
// 接口函数声明 — 第一层,唯一与外界联系的接口
int WINAPI AccessCURModule(INFOSTR *pInfo)
{
// 这个函数可以不作修改的使用,除非你的返回值多于两种。
switch(pInfo->comm)
{
case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
_fnCMD_GETPROCTYPE(pInfo);
break;
case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
_fnCMD_GETWRITERS(pInfo);
break;
case CMD_GETWRITERMESS: // 获取作者们的留言
_fnCMD_GETWRITERMESS(pInfo);
break;
case CMD_GETBUILDID: // 获取图像模块内部版本号
_fnCMD_GETBUILDID(pInfo);
break;
case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的WMF文件
_fnCMD_IS_VALID_FILE(pInfo);
break;
case CMD_GET_FILE_INFO: // 获取指定文件的信息
_fnCMD_GET_FILE_INFO(pInfo);
break;
case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
_fnCMD_LOAD_FROM_FILE(pInfo);
break;
case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
_fnCMD_SAVE_TO_FILE(pInfo);
break;
case CMD_IS_SUPPORT: // 查询某个命令是否被支持
_fnCMD_IS_SUPPORT(pInfo);
break;
case CMD_RESIZE: // 从新获取指定尺寸的图像位数据(只适用于矢量图像)
_fnCMD_RESIZE(pInfo);
break;
default:
pInfo->result = ER_ILLCOMM; // 非法命令
ASSERT(FALSE); // 调用者的程序设计有问题 :-)
break;
}
// 执行命令成功返回1, 失败返回0
return (pInfo->result==ER_SUCCESS)? 1:0;
}
// 命令解释函数 — 第二层解释函数
//********************************************************************//
// 操作命令解释函数---解释:CMD_IS_SUPPORT命令
// 查询某个命令是否被支持
void _fnCMD_IS_SUPPORT(INFOSTR *pInfo)
{
// 这个函数是为客户程序查询时使用,如果你实现了对某个命令的
// 解释,可修改相应的case中的设置,使其返回ER_SUCCESS,这就
// 表示你的模块已经支持该命令了。同时,现在的这个文件中已包
// 含了对前四个命令的解释,你只需向还未支持的命令函数中添加
// 代码即可。
ASSERT(pInfo->result == ER_EMPTY);
switch(pInfo->annexdata.cmAnnData)
{
case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
pInfo->result = ER_SUCCESS;
break;
case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
pInfo->result = ER_SUCCESS;
break;
case CMD_GETWRITERMESS: // 获取作者们的留言
pInfo->result = ER_SUCCESS;
break;
case CMD_GETBUILDID: // 获取图像模块内部版本号
pInfo->result = ER_SUCCESS;
break;
case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的CUR文件
pInfo->result = ER_SUCCESS;
break;
case CMD_GET_FILE_INFO: // 获取指定文件的信息
pInfo->result = ER_SUCCESS;
break;
case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
pInfo->result = ER_SUCCESS;
break;
case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
pInfo->result = ER_NOTSUPPORT;
break;
case CMD_IS_SUPPORT: // 查询某个命令是否被支持
pInfo->result = ER_SUCCESS;
break;
case CMD_RESIZE: // 获取指定尺寸的图像(只适用于矢量图像)
pInfo->result = ER_NOTSUPPORT;
break;
default:
pInfo->result = ER_NOTSUPPORT;
break;
}
}
// 操作命令解释函数---解释:CMD_GETPROCTYPE命令
// 获取本模块能处理的图像类型,如:BMP,PCX等等
void _fnCMD_GETPROCTYPE(INFOSTR *pInfo)
{
// 这是预定义的函数代码,你可以不必修改的使用。
// 根据接口定义,此时附加数据应被清空为0,所以下此断言
ASSERT(pInfo->annexdata.scAnnData[0] == 0);
ASSERT(pInfo->result == ER_EMPTY);
// 复制能处理的类型字符串
::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)ModuleProcessImgType,
sizeof(ModuleProcessImgType));
pInfo->result = ER_SUCCESS;
}
// 操作命令解释函数---解释:CMD_GETWRITER命令
// 获取本模块的作者列表,多人时用逗号分隔
void _fnCMD_GETWRITERS(INFOSTR *pInfo)
{
// 这是预定义的函数代码,你可以不必修改的使用。
// 根据接口定义,此时附加数据应被清空为0,所以下此断言
ASSERT(pInfo->annexdata.scAnnData[0] == 0);
ASSERT(pInfo->result == ER_EMPTY);
// 复制开发者名单串
::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterList,
sizeof(WriterList));
pInfo->result = ER_SUCCESS;
}
// 操作命令解释函数---解释:CMD_GETWRITERMESS命令
// 获取作者们的留言
void _fnCMD_GETWRITERMESS(INFOSTR *pInfo)
{
// 这是预定义的函数代码,你可以不必修改的使用。
// 根据接口定义,此时附加数据应被清空为0,所以下此断言
ASSERT(pInfo->annexdata.scAnnData[0] == 0);
ASSERT(pInfo->result == ER_EMPTY);
// 复制开发者们的留言字符串
::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterMess,
sizeof(WriterMess));
pInfo->result = ER_SUCCESS;
}
// 操作命令解释函数---解释:CMD_GETBUILDID命令
// 获取图像模块内部版本号
void _fnCMD_GETBUILDID(INFOSTR *pInfo)
{
// 这是预定义的函数代码,你可以不必修改的使用。
// 根据接口定义,此时annexdata.dwAnnData应被设为0,所以下此断言
ASSERT(pInfo->annexdata.dwAnnData == 0);
ASSERT(pInfo->result == ER_EMPTY);
// 填写内部版本号码
pInfo->annexdata.dwAnnData = MODULE_BUILDID;
pInfo->result = ER_SUCCESS;
}
// 操作命令解释函数---解释:CMD_IS_VALID_FILE命令
// 判断指定文件是否是有效的CUR文件
void _fnCMD_IS_VALID_FILE(INFOSTR *pInfo)
{
CFile file;
ICONDIR icondir;
DWORD dwSize;
UINT uRet;
// 检验入口参数是否符合接口定义
ASSERT(pInfo->result == ER_EMPTY);
ASSERT(pInfo->annexdata.iAnnData == 0);
ASSERT(::strlen(pInfo->filename));
ASSERT(pInfo->state == PKST_NOTVER);
ASSERT(pInfo);
// 设初值
pInfo->result = ER_SUCCESS;
pInfo->annexdata.iAnnData = 0;
// 先判断指定的文件是否存在
if (!IsFileExist(pInfo->filename))
pInfo->result = ER_COMMINFOERR;
else
{
// 打开指定文件
if (!file.Open(pInfo->filename, CFile::modeRead))
{
pInfo->result = ER_FILERWERR; // 打开文件时出错
return;
}
// 获取文件的长度(以字节为单位)
dwSize = file.GetLength();
// 用长度判断
if (dwSize < sizeof(ICONDIR))
{
// 这不是一个光标文件,光标文件的长度起码大于图标目录
// 结构的长度
file.Close();
return;
}
// 读取光标文件信息头结构,并检查它的有效性
file.SeekToBegin();
uRet = file.Read((LPSTR)&icondir, sizeof(ICONDIR));
if (uRet != sizeof(ICONDIR))
{
// 读文件时出错
pInfo->result = ER_FILERWERR;
file.Close();
return;
}
// 判断文件标志
if ((icondir.idReserved != 0)||(icondir.idType != CURTYPE))
{
file.Close();
return;
}
// 起码应该有一幅图像
if (icondir.idCount < 1)
{
file.Close();
return;
}
// 到此,大致可以表明该文件是一个有效的ICO文件,iAnnData变量设为1
pInfo->annexdata.iAnnData = 1;
// 表示通过校验
pInfo->state = PKST_PASSVER;
file.Close();
}
}
// 操作命令解释函数---解释:CMD_GET_FILE_INFO命令
// 获取指定文件的信息
void _fnCMD_GET_FILE_INFO(INFOSTR *pInfo)
{
CFile file;
CFileStatus status;
LPICONDIR lpIR;
LPIMGINFO lpII;
UINT i;
SIZE size;
// 检验入口参数是否符合接口定义
ASSERT(pInfo->result == ER_EMPTY);
ASSERT(::strlen(pInfo->filename));
// 此时,该文件必需是一个已存在的、并且是有效的ICO文件
ASSERT(pInfo->state == PKST_PASSVER);
// 客户模块必需要先将imginfo清空为0
ASSERT(pInfo->imginfo.imgtype == IMT_NULL);
// 打开指定文件
if (!file.Open(pInfo->filename, CFile::modeRead))
{
pInfo->result = ER_FILERWERR;
return;
}
// 读取ICO文件的信息
if ((lpIR = ReadIconInfo(file)) == NULL)
{
// 因读文件时出错或内存不足而调用失败
file.Close();
// 此处只能写一种错误原因,因为读盘失败的
// 可能性比较大,所以写了读写文件错的代码
pInfo->result = ER_FILERWERR;
return;
}
// 分配图像信息结构所需空间
lpII = (LPIMGINFO)::GlobalAlloc(GPTR, lpIR->idCount*sizeof(IMGINFO));
if (!lpII)
{
::GlobalFree((void*)lpIR);
file.Close();
pInfo->result = ER_MEMORYERR;
return;
}
// 获取图标中每一副图像的尺寸数据
for (i=0;iidCount;i++)
{
lpII[i].index = i;
_get_image_info(lpIR, i, (LPSIZE)&(lpII[i].imgsize), (int*)&(lpII[i].colnum));
_get_string_info((LPSIZE)&(lpII[i].imgsize), lpII[i].colnum, lpII[i].string, (LPSIZE)&(lpII[i].txtsize));
}
// 对图像结构数组进行排序(以图像宽度从小到大,:-)
_do_sort(lpIR->idCount, lpII);
// 获得图标综合图像尺寸
_get_synthesis_imgsize(lpIR->idCount, lpII, &size);
LPIMAGEINFOSTR lpImgInfoStr = &pInfo->imginfo;
// 获取文件的长度、图像的宽度、高度等信息
lpImgInfoStr->imgtype = IMT_RESSTATIC;
lpImgInfoStr->imgformat = IMF_ICO;
lpImgInfoStr->filesize = file.GetLength();
// 以下的宽度、高度是指综合图像的宽、高
lpImgInfoStr->width = size.cx;
lpImgInfoStr->height = size.cy;
// 因为这是综合图像的位深,所以锁定为32位
lpImgInfoStr->bitcount = 32;
lpImgInfoStr->compression = ICS_RGB;
// 每一图像行所占的字节数(DWORD对齐,并且只对非压缩位图有效)
lpImgInfoStr->linesize = WIDTHBYTES(size.cx*32);
lpImgInfoStr->imgnumbers = 1;
// 表示不可编辑
lpImgInfoStr->imgchang = 1;
// 获取文件最后的修改日期(月在高字节,日在低字节)
file.GetStatus(status);
lpImgInfoStr->year = (WORD)status.m_mtime.GetYear();
lpImgInfoStr->monday = (WORD)status.m_mtime.GetMonth();
lpImgInfoStr->monday <<= 8;
lpImgInfoStr->monday |= (WORD)status.m_mtime.GetDay();
// 获取文件最后的修改时间(字序:最高—0, 2—时,1—分,0—秒)
lpImgInfoStr->time = status.m_mtime.GetHour();
lpImgInfoStr->time <<= 8;
lpImgInfoStr->time |= status.m_mtime.GetMinute();
lpImgInfoStr->time <<= 8;
lpImgInfoStr->time |= status.m_mtime.GetSecond();
lpImgInfoStr->time &= 0xffffff;
::GlobalFree((void*)lpII);
::GlobalFree((void*)lpIR);
file.Close();
// 设置出口数据
pInfo->state = PKST_PASSINFO;
pInfo->result = ER_SUCCESS;
return;
}
// 操作命令解释函数---解释:CMD_LOAD_FROM_FILE命令
// 从指定图像文件中读取数据
void _fnCMD_LOAD_FROM_FILE(INFOSTR *pInfo)
{
// 检验入口参数是否符合接口定义
ASSERT(pInfo->result == ER_EMPTY);
ASSERT(::strlen(pInfo->filename));
// 此时,该文件必需是一个已存在的、有效的ICO文件,并且数据包中
// 含有该文件的信息(imginfo结构中)
ASSERT(pInfo->state == PKST_PASSINFO);
ASSERT(pInfo->imginfo.imgformat == IMF_ICO);
ASSERT(pInfo->pImgInfo == NULL);
// 必需设置标准图像格式信息
ASSERT(pInfo->sDIBInfo.bmi.biSize == sizeof(BITMAPINFOHEADER));
ASSERT(pInfo->pLineAddr != NULL);
ASSERT(pInfo->_pbdata != NULL);
CFile file;
LPICONDIR lpIR;
LPIMGINFO lpII;
UINT i;
if (pInfo->fpProgress)
{
if ((*pInfo->fpProgress)(RWPROGRESSSIZE, 6))
{ // 如果进度函数返回1,则说明用户想中断操作,返回。
pInfo->result = ER_USERBREAK;
return;
}
}
// 打开指定文件
if (!file.Open(pInfo->filename, CFile::modeRead))
{
pInfo->result = ER_FILERWERR;
return;
}
file.Seek(0, CFile::begin);
// 读取ICO文件的信息
if ((lpIR = ReadIconInfo(file)) == NULL)
{
// 因读文件时出错或内存不足而调用失败
file.Close();
// 此处只能写一种错误原因,因为读盘失败的
// 可能性比较大,所以写了读写文件错的代码
pInfo->result = ER_FILERWERR;
return;
}
// 分配图像信息结构所需空间
lpII = (LPIMGINFO)::GlobalAlloc(GPTR, lpIR->idCount*sizeof(IMGINFO));
if (!lpII)
{
::GlobalFree((void*)lpIR);
file.Close();
pInfo->result = ER_MEMORYERR;
return;
}
// 获取图标中每一副图像的尺寸数据
for (i=0;iidCount;i++)
{
lpII[i].index = i;
_get_image_info(lpIR, i, (LPSIZE)&(lpII[i].imgsize), (int*)&(lpII[i].colnum));
_get_string_info((LPSIZE)&(lpII[i].imgsize), lpII[i].colnum, lpII[i].string, (LPSIZE)&(lpII[i].txtsize));
}
// 对图像结构数组进行排序(以图像宽度从小到大,:-)
_do_sort(lpIR->idCount, lpII);
PBYTE lpBits;
HBITMAP hBmp;
HBITMAP hCurBmp;
RECT rect;
HWND hWnd = ::GetDesktopWindow();
HDC hDC = ::GetDC(hWnd);
hBmp = CreateDIBSection(hDC, (LPBITMAPINFO)&(pInfo->sDIBInfo),
DIB_RGB_COLORS, (void**)&lpBits, NULL, 0);
if (hBmp == NULL)
{
::GlobalFree((void*)lpIR);
::GlobalFree((void*)lpII);
file.Close();
::ReleaseDC(hWnd, hDC);
pInfo->result = ER_SYSERR;
return; // 操作系统不稳定
}
// 将图像的背景色设置为白
HDC hMemDC = ::CreateCompatibleDC(hDC);
HDC hSouDC = ::CreateCompatibleDC(hDC);
HBITMAP hOldSouBmp;
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBmp);
rect.left = 0; rect.top = 0; rect.right = pInfo->imginfo.width;
rect.bottom = pInfo->imginfo.height;
// 将图像的背景填充为系统定义的白色
::FillRect(hMemDC, (CONST RECT*)&rect, (HBRUSH)::GetStockObject(WHITE_BRUSH));
int currentimg; // 当前待处理的图像
int currentheight = BORDERSPEC; // 当前高度行坐标
int mp = pInfo->imginfo.width/2;// 中点X坐标
int ul, ut, dr, db;
for (i=0;iidCount;i++)
{
currentimg = lpII[i].index;
ul = mp-lpII[i].imgsize.cx/2;
ut = currentheight;
dr = ul+lpII[i].imgsize.cx;
db = ut+lpII[i].imgsize.cy;
// 获得图标文件中的指定图像
hCurBmp = _get_hbmp(file, lpIR, lpII, i);
if (!hCurBmp)
{
::SelectObject(hMemDC, hOldBmp);
::DeleteDC(hSouDC);
::DeleteDC(hMemDC);
::ReleaseDC(hWnd, hDC);
::GlobalFree((void*)lpIR);
::GlobalFree((void*)lpII);
::DeleteObject(hBmp);
file.Close();
pInfo->result = ER_SYSERR; // 操作系统不稳定
return;
}
// 将图像复制到主位图中
hOldSouBmp = (HBITMAP)::SelectObject(hSouDC, hCurBmp);
::BitBlt(hMemDC, ul, ut, dr-ul, db-ut, hSouDC, 0, 0, SRCCOPY);
::SelectObject(hSouDC, hOldSouBmp);
::DeleteObject(hCurBmp);
currentheight += lpII[i].imgsize.cy;
currentheight += IMGTXTSPEC;
// 计算字符串的显示位置
ul = mp-lpII[i].txtsize.cx/2;
ut = currentheight;
dr = ul+lpII[i].txtsize.cx;
db = ut+lpII[i].txtsize.cy;
rect.left = ul; rect.top = ut; rect.right = dr; rect.bottom = db;
// 绘制图标的描述字符串
::DrawText(hMemDC, lpII[i].string, lstrlen(lpII[i].string),
(RECT*)&rect, DT_SINGLELINE|DT_CENTER|DT_NOCLIP);
currentheight += lpII[i].txtsize.cy;
currentheight += TXTIMGSPEC;
}
::SelectObject(hMemDC, hOldBmp);
::DeleteDC(hSouDC);
::DeleteDC(hMemDC);
::ReleaseDC(hWnd, hDC);
// 将图像复制到数据包中
::memmove((void*)pInfo->_pbdata, (const void*)lpBits,
WIDTHBYTES(pInfo->sDIBInfo.bmi.biWidth*pInfo->sDIBInfo.bmi.biBitCount)*pInfo->imginfo.height);
::DeleteObject(hBmp);
::GlobalFree((void*)lpII);
::GlobalFree((void*)lpIR);
file.Close();
// 执行成功
pInfo->state = PKST_INFOANDBITS;
pInfo->modify = 0;
pInfo->result = ER_SUCCESS;
if (pInfo->fpProgress) // 结束进度条,此调用不再支持用户中断
(*pInfo->fpProgress)(RWPROGRESSSIZE, RWPROGRESSSIZE);
}
// 操作命令解释函数---解释:CMD_SAVE_TO_FILE命令
// 将数据保存到指定文件中
void _fnCMD_SAVE_TO_FILE(INFOSTR *pInfo)
{
// 这个命令不一定要解释,你可以参考本图像格式的具体境况来决定
// 是否解释该命令。
// 如果你想解释该命令,请在下面加入代码,并修改pInfo->result的返回值:
// ----------------------------------------------------------------->
pInfo->result = ER_NOTSUPPORT;
}
// 操作命令解释函数---解释:CMD_RESIZE命令
// 重新获取指定尺寸的图像位数据(只适用于矢量图像)
void _fnCMD_RESIZE(INFOSTR *pInfo)
{
// 这个命令一般的图像读写模块不需要支持,它只适用于矢量图像,
// 比如WMF、EMF之类。
// 如果你想解释该命令,请在下面加入代码,并修改pInfo->result的返回值:
// ----------------------------------------------------------------->
pInfo->result = ER_NOTSUPPORT;
}
/*************************************************************************
*
* IsFileExist()
*
* 参数说明:
*
* char *lpFileName - 待判断的文件路径和名称(文件名)
*
* 返回值:
*
* BOOL - 如果指定的文件存在返回TRUE,否则返回FALSE。
*
* 描述:
*
* 判断指定的文件是否存在
*
* 该文件必需可以被读和写
*
************************************************************************/
BOOL IsFileExist(char *lpFileName)
{
CFile file;
BOOL bExist = FALSE; // 文件存在是TRUE,不存在是FALSE
CFileException e;
// 确定指定的文件是否存在
if (file.Open(lpFileName, CFile::modeReadWrite|CFile::shareDenyNone, &e))
{
bExist = TRUE;
file.Close();
}
else
{
// 可能有其他程序正在处理此文件
switch(e.m_cause)
{
case CFileException::tooManyOpenFiles:
case CFileException::accessDenied:
case CFileException::sharingViolation:
case CFileException::lockViolation:
return TRUE;
case CFileException::fileNotFound:
case CFileException::badPath:
case CFileException::invalidFile:
case CFileException::hardIO:
default:
return FALSE;
}
}
return bExist;
}
/****************************************************************************
*
* FUNCTION: ReadIconInfo
*
* PURPOSE: 获取指定ICO文件的信息(包括图像个数、图像尺寸、位深等)
*
* PARAMS: CFile& file - 图标文件类引用
*
* RETURNS: LPICONDIR - NULL 失败(由读文件或内存不足引起),非NULL
* 表示成功,返回值是一个指向ICONDIR的指针
*
\****************************************************************************/
LPICONDIR ReadIconInfo(CFile& file)
{
ICONDIR icondir;
int uRet, infosize;
// 读取图标文件信息头结构
file.SeekToBegin();
uRet = file.Read((LPSTR)&icondir, sizeof(ICONDIR));
if (uRet != sizeof(ICONDIR))
return NULL;
ASSERT(icondir.idCount >= 1);
// 计算图标信息块的尺寸
infosize = sizeof(ICONDIR)+(icondir.idCount-1)*sizeof(ICONDIRENTRY);
// 分配用于存放图标信息的缓冲区内存块
LPICONDIR lpIR = (LPICONDIR)::GlobalAlloc(GPTR, infosize);
if (!lpIR)
return NULL;
// 读取图标信息
file.SeekToBegin();
uRet = file.Read((LPSTR)lpIR, infosize);
if (uRet != infosize)
{
::GlobalFree(lpIR);
return NULL;
}
return lpIR;
}
/****************************************************************************
*
* FUNCTION: ReadICOHeader
*
* PURPOSE: 读取ICO文件的头结构中的图像个数
*
* PARAMS: CFile& file - CFile类目标的引用
*
* RETURNS: UINT - 文件中图标图像的个数,-1表示失败
*
\****************************************************************************/
UINT ReadICOHeader(CFile& file)
{
ICONDIR dir;
TRY
{
file.SeekToBegin();
file.Read((void*)&dir, sizeof(ICONDIR));
}
CATCH(CFileException, e)
{
return (UINT)-1; // 读文件时出错
}
END_CATCH
return (UINT)dir.idCount;
}
/****************************************************************************
*
* FUNCTION: FindDIBits
*
* PURPOSE: 定位在CF_DIB格式的DIB图像数据中位数据的地址
*
* PARAMS: LPSTR lpbi - 指向CF_DIB内存块的指针
*
* RETURNS: LPSTR - 指向位数据的指针
*
\****************************************************************************/
LPSTR FindDIBBits(LPSTR lpbi)
{
return (lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ));
}
/****************************************************************************
*
* FUNCTION: DIBNumColors
*
* PURPOSE: 计算指定DIB的调色板中颜色的个数
*
* PARAMS: LPSTR lpbi - 指向CF_DIB内存块
*
* RETURNS: WORD - 调色板中颜色项的个数
*
\****************************************************************************/
WORD DIBNumColors(LPSTR lpbi)
{
WORD wBitCount;
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
// 如果文件指定了实际使用的颜色个数,则直接使用这个值
if (dwClrUsed)
return (WORD)dwClrUsed;
// 否则通过位深度值进行相应的计算
wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
switch (wBitCount)
{
case 1: return 2;
case 4: return 16;
case 8: return 256;
default:return 0;
}
return 0;
}
/****************************************************************************
*
* FUNCTION: PaletteSize
*
* PURPOSE: 计算调色板的尺寸
*
* PARAMS: LPSTR lpbi - 指向CF_DIB内存块
*
* RETURNS: WORD - 调色板的尺寸(以字节为单位)
*
\****************************************************************************/
WORD PaletteSize(LPSTR lpbi)
{
return (DIBNumColors(lpbi) * sizeof(RGBQUAD));
}
/****************************************************************************
*
* FUNCTION: BytesPerLine
*
* PURPOSE: 计算扫描行的宽度(以字节为单位)
*
* PARAMS: LPBITMAPINFOHEADER lpBMIH - 指向CF_DIB内存块中BITMAPINFOHEADER
* 的指针
*
* RETURNS: DWORD - 扫描行的宽度。(注:DIB扫描行的宽度是DWORD对齐的)
*
\****************************************************************************/
DWORD BytesPerLine(LPBITMAPINFOHEADER lpBMIH)
{
return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
}
/****************************************************************************
*
* FUNCTION: _get_image_info
*
* PURPOSE: 获得指定图像的宽、高尺寸及颜色数目
*
* PARAMS: LPICONDIR lpIR - 图标原始数组数组
* int index - 得获取尺寸的图像之索引
* LPSIZE lpSize - 接收尺寸的变量
* int *pColnum - 接收颜色数目的变量
*
* RETURNS: -
*
\****************************************************************************/
void _get_image_info(LPICONDIR lpIR, int index, LPSIZE lpSize, int *pColnum)
{
ASSERT(index <= lpIR->idCount);
lpSize->cx = lpIR->idEntries[index].bWidth;
lpSize->cy = lpIR->idEntries[index].bHeight;
*pColnum = lpIR->idEntries[index].bColorCount;
}
/****************************************************************************
*
* FUNCTION: _get_string_info
*
* PURPOSE: 获得指定图像宽、高字符串的尺寸及字符串
*
* PARAMS: LPSIZE lpImgSize - 图像尺寸数据
* int colnum - 图像的颜色数目
* LPTSTR lpString - 接收字符串的变量
* LPSIZE lpTxtSize - 接收文本尺寸的变量
*
* RETURNS: -
*
\****************************************************************************/
void _get_string_info(LPSIZE lpImgSize, int colnum, LPTSTR lpString, LPSIZE lpTxtSize)
{
ASSERT(lpImgSize);
// 获取图像尺寸字符串
sprintf((char*)lpString, "%d*%d*%d", lpImgSize->cx, lpImgSize->cy, colnum);
HWND hWnd = ::GetDesktopWindow();
HDC hDC = ::GetDC(hWnd);
// 获取字符串的长度
::GetTextExtentPoint32(hDC, lpString, lstrlen((LPCTSTR)lpString), lpTxtSize);
::ReleaseDC(hWnd, hDC);
return;
}
/****************************************************************************
*
* FUNCTION: _get_synthesis_imgsize
*
* PURPOSE: 计算综合图像的尺寸(就是将所有格式的图像
* 拼接在一起的总尺寸)
*
* PARAMS: int imgcount - 有多少副图像
* LPIMGINFO lpImgInfo - 图像数据数组首指针
* (注:此时的数组必需已被排序)
* LPSIZE lpSize - 接收综合尺寸的变量
*
* RETURNS: -
*
\****************************************************************************/
void _get_synthesis_imgsize(int imgcount, LPIMGINFO lpImgInfo, LPSIZE lpSize)
{
SIZE size;
ASSERT(imgcount >= 1);
ASSERT(lpImgInfo);
ASSERT(lpSize);
// imgcount-1 就是结构数组中最后一个项,因为该数组
// 已经经过了排序,所以最后一个就是最宽的一个
size.cx = lpImgInfo[imgcount-1].imgsize.cx;
// 如果字串的宽度超出了图像的宽度,则取字串宽度
if (lpImgInfo[imgcount-1].txtsize.cx > size.cx)
size.cx = lpImgInfo[imgcount-1].txtsize.cx;
// 加上边界宽度
size.cx += BORDERSPEC*2;
// 计算综合图像高度
size.cy = BORDERSPEC;
// 综合图像高度的计算方法是:
// 上边界+图像高度+图像到文本间隔+文本高度+
// 文本到图像间隔+第二副图像高度+图像到文本间
// 隔+ ..... +底边界
for (int i=0;icx = size.cx;
lpSize->cy = size.cy;
}
/****************************************************************************
*
* FUNCTION: _do_sort
*
* PURPOSE: 将图标图像信息数组根据图像的宽度进行排序
*
* PARAMS: int imgcount - 有多少副图像
* LPIMGINFO lpImgInfo - 图像数据数组首指针
*
* RETURNS: - 返回后,数组中的数据将从小到大的被排序
*
\****************************************************************************/
void _do_sort(int imgcount, LPIMGINFO lpImgInfo)
{
int i, j, sortcount;
IMGINFO imgtmp;
// 初始化起始值
sortcount = imgcount-1;
// 起泡排序法
for (i=0;i lpImgInfo[j+1].imgsize.cx)
{
// 交换数据
::memcpy((void*)&imgtmp, (const void*)&lpImgInfo[j], sizeof(IMGINFO));
::memcpy((void*)&lpImgInfo[j], (const void*)&lpImgInfo[j+1], sizeof(IMGINFO));
::memcpy((void*)&lpImgInfo[j+1], (const void*)&imgtmp, sizeof(IMGINFO));
}
}
}
}
/****************************************************************************
*
* FUNCTION: _get_hbmp
*
* PURPOSE: 获取指定图像的句柄
*
* PARAMS: CFile& file - 图标文件目标
* LPICONDIR lpIR - 原始图像数据数组
* LPIMGINFO lpImgInfo - 图像数据数组首指针
* int index - 指定获取句柄的图像索引(排序后的索引)
*
* RETURNS: HBITMAP - 图像的句柄,失败返回NULL
*
\****************************************************************************/
HBITMAP _get_hbmp(CFile& file, LPICONDIR lpIR, LPIMGINFO lpImgInfo, int index)
{
HBITMAP hBmp, hXORBmp, hANDBmp;
HBITMAP hOldBmp, hOldBmp2;
// 图像所占字节数
DWORD imgsize = lpIR->idEntries[lpImgInfo[index].index].dwBytesInRes;
// 图像数据偏移
DWORD imgoffset = lpIR->idEntries[lpImgInfo[index].index].dwImageOffset;
// 分配用于存放指定DF_DIB数据的内存块
PBYTE lpDIB = (PBYTE)::GlobalAlloc(GPTR, imgsize);
if (!lpDIB)
return NULL;
// 读取图像的DF_DIB数据
file.Seek(imgoffset, CFile::begin);
if (file.ReadHuge((void*)lpDIB, imgsize) != imgsize)
{
::GlobalFree(lpDIB);
return NULL;
}
// 该高度值是XOR图与AND图高度的和,所以得除2
((LPBITMAPINFOHEADER)lpDIB)->biHeight /= 2;
RECT rect;
HWND hWnd = ::GetDesktopWindow();
HDC hDC = ::GetDC(hWnd);
HDC hMemDC = ::CreateCompatibleDC(hDC);
// 创建目标图像
hBmp = ::CreateCompatibleBitmap(hDC, lpImgInfo[index].imgsize.cx,lpImgInfo[index].imgsize.cy);
if (!hBmp)
{
::GlobalFree(lpDIB);
::ReleaseDC(hWnd, hDC);
::DeleteDC(hMemDC);
return NULL;
}
hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBmp);
rect.left = rect.top = 0;
rect.right = lpImgInfo[index].imgsize.cx;
rect.bottom = lpImgInfo[index].imgsize.cy;
// 将图像填充为白色
::FillRect(hMemDC, (CONST RECT*)&rect, (HBRUSH)::GetStockObject(WHITE_BRUSH));
::SelectObject(hMemDC, hOldBmp);
// 创建XOR图像
hXORBmp = ::CreateCompatibleBitmap(hDC, lpImgInfo[index].imgsize.cx,lpImgInfo[index].imgsize.cy);
if (!hXORBmp)
{
::DeleteObject(hBmp);
::GlobalFree(lpDIB);
::ReleaseDC(hWnd, hDC);
::DeleteDC(hMemDC);
return NULL;
}
::SetDIBits(hDC, hXORBmp, 0, lpImgInfo[index].imgsize.cy,
(const void*)::FindDIBBits((LPSTR)lpDIB), (CONST BITMAPINFO *)lpDIB, DIB_RGB_COLORS);
// 创建AND图像
hANDBmp = ::CreateBitmap(lpImgInfo[index].imgsize.cx,
lpImgInfo[index].imgsize.cy, 1, 1, NULL);
if (!hANDBmp)
{
::DeleteObject(hXORBmp);
::DeleteObject(hBmp);
::GlobalFree(lpDIB);
::ReleaseDC(hWnd, hDC);
::DeleteDC(hMemDC);
return NULL;
}
LPBITMAPINFO lpbmi;
lpbmi = (LPBITMAPINFO)::GlobalAlloc(GPTR, sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
if (!lpbmi)
{
::DeleteObject(hANDBmp);
::DeleteObject(hXORBmp);
::DeleteObject(hBmp);
::GlobalFree(lpDIB);
::ReleaseDC(hWnd, hDC);
::DeleteDC(hMemDC);
return NULL;
}
lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbmi->bmiHeader.biBitCount = 1;
lpbmi->bmiHeader.biClrImportant = 0;
lpbmi->bmiHeader.biClrUsed = 0;
lpbmi->bmiHeader.biCompression = BI_RGB;
lpbmi->bmiHeader.biHeight = ((LPBITMAPINFOHEADER)lpDIB)->biHeight;
lpbmi->bmiHeader.biPlanes = 1;
lpbmi->bmiHeader.biSizeImage = 0;
lpbmi->bmiHeader.biWidth = ((LPBITMAPINFOHEADER)lpDIB)->biWidth;
lpbmi->bmiHeader.biXPelsPerMeter = 0;
lpbmi->bmiHeader.biYPelsPerMeter = 0;
lpbmi->bmiColors[0].rgbRed = 0;
lpbmi->bmiColors[0].rgbGreen = 0;
lpbmi->bmiColors[0].rgbBlue = 0;
lpbmi->bmiColors[0].rgbReserved = 0;
lpbmi->bmiColors[1].rgbRed = 255;
lpbmi->bmiColors[1].rgbGreen = 255;
lpbmi->bmiColors[1].rgbBlue = 255;
lpbmi->bmiColors[1].rgbReserved = 0;
::SetDIBits(hMemDC, hANDBmp, 0, lpImgInfo[index].imgsize.cy,
(const void*)((PBYTE)::FindDIBBits((LPSTR)lpDIB) + \
WIDTHBYTES(lpImgInfo[index].imgsize.cx*((LPBITMAPINFOHEADER)lpDIB)->biBitCount) * \
lpImgInfo[index].imgsize.cy),
lpbmi, DIB_RGB_COLORS);
::GlobalFree(lpbmi);
// 合成图像
HDC hMemDC2 = ::CreateCompatibleDC(hDC);
hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBmp);
hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, hANDBmp);
::BitBlt(hMemDC, 0, 0, lpImgInfo[index].imgsize.cx, lpImgInfo[index].imgsize.cy, hMemDC2, 0, 0, SRCAND);
::SelectObject(hMemDC2, hXORBmp);
::BitBlt(hMemDC, 0, 0, lpImgInfo[index].imgsize.cx, lpImgInfo[index].imgsize.cy, hMemDC2, 0, 0, SRCINVERT);
::SelectObject(hMemDC2, hOldBmp2);
::SelectObject(hMemDC, hOldBmp);
// 释放无关资源
::DeleteDC(hMemDC2);
::DeleteDC(hMemDC);
::ReleaseDC(hWnd, hDC);
::GlobalFree(lpDIB);
::DeleteObject(hANDBmp);
::DeleteObject(hXORBmp);
// 返回合成位图
return hBmp;
}