IcoModule.cpp
上传用户:yatsl7111
上传日期:2007-01-08
资源大小:1433k
文件大小:31k
源码类别:

图形图象

开发平台:

Visual C++

  1. // IcoModule.cpp : Defines the initialization routines for the DLL.
  2. //
  3. #include "stdafx.h"
  4. #include "IcoModule.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #undef THIS_FILE
  8. static char THIS_FILE[] = __FILE__;
  9. #endif
  10. static char ModuleProcessImgType[]="ICO"; // 本模块能处理的图像类型
  11. static char WriterList[]="YZ"; // 本模块的作者列表
  12. static char WriterMess[]="HE HE ..."; // 作者留言
  13. //
  14. // Note!
  15. //
  16. // If this DLL is dynamically linked against the MFC
  17. // DLLs, any functions exported from this DLL which
  18. // call into MFC must have the AFX_MANAGE_STATE macro
  19. // added at the very beginning of the function.
  20. //
  21. // For example:
  22. //
  23. // extern "C" BOOL PASCAL EXPORT ExportedFunction()
  24. // {
  25. // AFX_MANAGE_STATE(AfxGetStaticModuleState());
  26. // // normal function body here
  27. // }
  28. //
  29. // It is very important that this macro appear in each
  30. // function, prior to any calls into MFC.  This means that
  31. // it must appear as the first statement within the 
  32. // function, even before any object variable declarations
  33. // as their constructors may generate calls into the MFC
  34. // DLL.
  35. //
  36. // Please see MFC Technical Notes 33 and 58 for additional
  37. // details.
  38. //
  39. // 在图像读写模块中,如果想分配内存,请使用API函数GlobalAlloc()
  40. // ,如果想释放内存请使用GlobalFree()函数。不要使用诸如:new
  41. // 、malloc()等函数。这是为了使各模块之间可以异地释放内存。
  42. //
  43. //
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CIcoModuleApp
  46. BEGIN_MESSAGE_MAP(CIcoModuleApp, CWinApp)
  47. //{{AFX_MSG_MAP(CIcoModuleApp)
  48. // NOTE - the ClassWizard will add and remove mapping macros here.
  49. //    DO NOT EDIT what you see in these blocks of generated code!
  50. //}}AFX_MSG_MAP
  51. END_MESSAGE_MAP()
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CIcoModuleApp construction
  54. CIcoModuleApp::CIcoModuleApp()
  55. {
  56. // TODO: add construction code here,
  57. // Place all significant initialization in InitInstance
  58. }
  59. /////////////////////////////////////////////////////////////////////////////
  60. // The one and only CIcoModuleApp object
  61. CIcoModuleApp theApp;
  62. // 接口函数声明 — 第一层,唯一与外界联系的接口
  63. int WINAPI AccessICOModule(INFOSTR *pInfo)
  64. {
  65. // 这个函数可以不作修改的使用,除非你的返回值多于两种。
  66. switch(pInfo->comm)
  67. {
  68. case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
  69. _fnCMD_GETPROCTYPE(pInfo);
  70. break;
  71. case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
  72. _fnCMD_GETWRITERS(pInfo);
  73. break;
  74. case CMD_GETWRITERMESS: // 获取作者们的留言
  75. _fnCMD_GETWRITERMESS(pInfo);
  76. break;
  77. case CMD_GETBUILDID: // 获取图像模块内部版本号
  78. _fnCMD_GETBUILDID(pInfo);
  79. break;
  80. case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的WMF文件
  81. _fnCMD_IS_VALID_FILE(pInfo);
  82. break;
  83. case CMD_GET_FILE_INFO: // 获取指定文件的信息
  84. _fnCMD_GET_FILE_INFO(pInfo);
  85. break;
  86. case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
  87. _fnCMD_LOAD_FROM_FILE(pInfo);
  88. break;
  89. case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
  90. _fnCMD_SAVE_TO_FILE(pInfo);
  91. break;
  92. case CMD_IS_SUPPORT: // 查询某个命令是否被支持
  93. _fnCMD_IS_SUPPORT(pInfo);
  94. break;
  95. case CMD_RESIZE: // 从新获取指定尺寸的图像位数据(只适用于矢量图像)
  96. _fnCMD_RESIZE(pInfo);
  97. break;
  98. default:
  99. pInfo->result = ER_ILLCOMM; // 非法命令
  100. ASSERT(FALSE); // 调用者的程序设计有问题 :-)
  101. break;
  102. }
  103. // 执行命令成功返回1, 失败返回0
  104. return (pInfo->result==ER_SUCCESS)? 1:0;
  105. }
  106. // 命令解释函数 — 第二层解释函数
  107. //********************************************************************//
  108. // 操作命令解释函数---解释:CMD_IS_SUPPORT命令
  109. // 查询某个命令是否被支持
  110. void _fnCMD_IS_SUPPORT(INFOSTR *pInfo)
  111. {
  112. // 这个函数是为客户程序查询时使用,如果你实现了对某个命令的
  113. // 解释,可修改相应的case中的设置,使其返回ER_SUCCESS,这就
  114. // 表示你的模块已经支持该命令了。同时,现在的这个文件中已包
  115. // 含了对前四个命令的解释,你只需向还未支持的命令函数中添加
  116. // 代码即可。
  117. ASSERT(pInfo->result == ER_EMPTY);
  118. switch(pInfo->annexdata.cmAnnData)  
  119. {
  120. case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
  121. pInfo->result = ER_SUCCESS;
  122. break;
  123. case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
  124. pInfo->result = ER_SUCCESS;
  125. break;
  126. case CMD_GETWRITERMESS: // 获取作者们的留言
  127. pInfo->result = ER_SUCCESS;
  128. break;
  129. case CMD_GETBUILDID: // 获取图像模块内部版本号
  130. pInfo->result = ER_SUCCESS;
  131. break;
  132. case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的ICO文件
  133. pInfo->result = ER_SUCCESS;
  134. break;
  135. case CMD_GET_FILE_INFO: // 获取指定文件的信息
  136. pInfo->result = ER_SUCCESS;
  137. break;
  138. case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
  139. pInfo->result = ER_SUCCESS;
  140. break;
  141. case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
  142. pInfo->result = ER_NOTSUPPORT;
  143. break;
  144. case CMD_IS_SUPPORT: // 查询某个命令是否被支持
  145. pInfo->result = ER_SUCCESS;
  146. break;
  147. case CMD_RESIZE: // 获取指定尺寸的图像(只适用于矢量图像)
  148. pInfo->result = ER_NOTSUPPORT;
  149. break;
  150. default:
  151. pInfo->result = ER_NOTSUPPORT;
  152. break;
  153. }
  154. }
  155. // 操作命令解释函数---解释:CMD_GETPROCTYPE命令
  156. // 获取本模块能处理的图像类型,如:BMP,PCX等等
  157. void _fnCMD_GETPROCTYPE(INFOSTR *pInfo)
  158. {
  159. // 这是预定义的函数代码,你可以不必修改的使用。
  160. // 根据接口定义,此时附加数据应被清空为0,所以下此断言
  161. ASSERT(pInfo->annexdata.scAnnData[0] == 0);
  162. ASSERT(pInfo->result == ER_EMPTY);
  163. // 复制能处理的类型字符串
  164. ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)ModuleProcessImgType, 
  165. sizeof(ModuleProcessImgType));
  166. pInfo->result = ER_SUCCESS;
  167. }
  168. // 操作命令解释函数---解释:CMD_GETWRITER命令
  169. // 获取本模块的作者列表,多人时用逗号分隔
  170. void _fnCMD_GETWRITERS(INFOSTR *pInfo)
  171. {
  172. // 这是预定义的函数代码,你可以不必修改的使用。
  173. // 根据接口定义,此时附加数据应被清空为0,所以下此断言
  174. ASSERT(pInfo->annexdata.scAnnData[0] == 0);
  175. ASSERT(pInfo->result == ER_EMPTY);
  176. // 复制开发者名单串
  177. ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterList, 
  178. sizeof(WriterList));
  179. pInfo->result = ER_SUCCESS;
  180. }
  181. // 操作命令解释函数---解释:CMD_GETWRITERMESS命令
  182. // 获取作者们的留言
  183. void _fnCMD_GETWRITERMESS(INFOSTR *pInfo)
  184. {
  185. // 这是预定义的函数代码,你可以不必修改的使用。
  186. // 根据接口定义,此时附加数据应被清空为0,所以下此断言
  187. ASSERT(pInfo->annexdata.scAnnData[0] == 0);
  188. ASSERT(pInfo->result == ER_EMPTY);
  189. // 复制开发者们的留言字符串
  190. ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterMess, 
  191. sizeof(WriterMess));
  192. pInfo->result = ER_SUCCESS;
  193. }
  194. // 操作命令解释函数---解释:CMD_GETBUILDID命令
  195. // 获取图像模块内部版本号
  196. void _fnCMD_GETBUILDID(INFOSTR *pInfo)
  197. {
  198. // 这是预定义的函数代码,你可以不必修改的使用。
  199. // 根据接口定义,此时annexdata.dwAnnData应被设为0,所以下此断言
  200. ASSERT(pInfo->annexdata.dwAnnData == 0);
  201. ASSERT(pInfo->result == ER_EMPTY);
  202. // 填写内部版本号码
  203. pInfo->annexdata.dwAnnData = MODULE_BUILDID;
  204. pInfo->result = ER_SUCCESS;
  205. }
  206. // 操作命令解释函数---解释:CMD_IS_VALID_FILE命令
  207. // 判断指定文件是否是有效的ICO文件
  208. void _fnCMD_IS_VALID_FILE(INFOSTR *pInfo)
  209. {
  210. CFile file;
  211. ICONDIR icondir;
  212. DWORD dwSize;
  213. UINT uRet;
  214. // 检验入口参数是否符合接口定义
  215. ASSERT(pInfo->result == ER_EMPTY);
  216. ASSERT(pInfo->annexdata.iAnnData == 0);
  217. ASSERT(::strlen(pInfo->filename));
  218. ASSERT(pInfo->state == PKST_NOTVER);
  219. ASSERT(pInfo);
  220. // 设初值
  221. pInfo->result = ER_SUCCESS;
  222. pInfo->annexdata.iAnnData = 0;
  223. // 先判断指定的文件是否存在
  224. if (!IsFileExist(pInfo->filename))
  225. pInfo->result = ER_COMMINFOERR;
  226. else
  227. {
  228. // 打开指定文件
  229. if (!file.Open(pInfo->filename, CFile::modeRead))
  230. {
  231. pInfo->result = ER_FILERWERR; // 打开文件时出错
  232. return;
  233. }
  234. // 获取文件的长度(以字节为单位)
  235. dwSize = file.GetLength();
  236. // 用长度判断
  237. if (dwSize < sizeof(ICONDIR))
  238. {
  239. // 这不是一个ICON文件,图标文件的长度起码大于图标目录
  240. // 结构的长度
  241. file.Close();
  242. return;
  243. }
  244. // 读取图标文件信息头结构,并检查它的有效性
  245. file.SeekToBegin();
  246. uRet  = file.Read((LPSTR)&icondir, sizeof(ICONDIR));
  247. if (uRet != sizeof(ICONDIR))
  248. {
  249. // 读文件时出错
  250. pInfo->result = ER_FILERWERR;
  251. file.Close();
  252. return;
  253. }
  254. // 判断文件标志
  255. if ((icondir.idReserved != 0)||(icondir.idType != ICONTYPE))
  256. {
  257. file.Close();
  258. return;
  259. }
  260. // 起码应该有一幅图像
  261. if (icondir.idCount < 1)
  262. {
  263. file.Close();
  264. return;
  265. }
  266. // 到此,大致可以表明该文件是一个有效的ICO文件,iAnnData变量设为1
  267. pInfo->annexdata.iAnnData = 1;
  268. // 表示通过校验
  269. pInfo->state = PKST_PASSVER;
  270. file.Close();
  271. }
  272. }
  273. // 操作命令解释函数---解释:CMD_GET_FILE_INFO命令
  274. // 获取指定文件的信息
  275. void _fnCMD_GET_FILE_INFO(INFOSTR *pInfo)
  276. {
  277. CFile file;
  278. CFileStatus status;
  279. LPICONDIR lpIR;
  280. LPIMGINFO lpII;
  281. UINT i;
  282. SIZE size;
  283. // 检验入口参数是否符合接口定义
  284. ASSERT(pInfo->result == ER_EMPTY);
  285. ASSERT(::strlen(pInfo->filename));
  286. // 此时,该文件必需是一个已存在的、并且是有效的ICO文件
  287. ASSERT(pInfo->state == PKST_PASSVER);
  288. // 客户模块必需要先将imginfo清空为0
  289. ASSERT(pInfo->imginfo.imgtype == IMT_NULL);
  290. // 打开指定文件
  291. if (!file.Open(pInfo->filename, CFile::modeRead))
  292. {
  293. pInfo->result = ER_FILERWERR;
  294. return;
  295. }
  296. // 读取ICO文件的信息
  297. if ((lpIR = ReadIconInfo(file)) == NULL)
  298. {
  299. // 因读文件时出错或内存不足而调用失败
  300. file.Close();
  301. // 此处只能写一种错误原因,因为读盘失败的
  302. // 可能性比较大,所以写了读写文件错的代码
  303. pInfo->result = ER_FILERWERR;
  304. return;
  305. }
  306. // 分配图像信息结构所需空间
  307. lpII = (LPIMGINFO)::GlobalAlloc(GPTR, lpIR->idCount*sizeof(IMGINFO));
  308. if (!lpII)
  309. {
  310. ::GlobalFree((void*)lpIR);
  311. file.Close();
  312. pInfo->result = ER_MEMORYERR;
  313. return;
  314. }
  315. // 获取图标中每一副图像的尺寸数据
  316. for (i=0;i<lpIR->idCount;i++)
  317. {
  318. lpII[i].index = i;
  319. _get_image_info(lpIR, i, (LPSIZE)&(lpII[i].imgsize), (int*)&(lpII[i].colnum));
  320. _get_string_info((LPSIZE)&(lpII[i].imgsize), lpII[i].colnum, lpII[i].string, (LPSIZE)&(lpII[i].txtsize));
  321. }
  322. // 对图像结构数组进行排序(以图像宽度从小到大,:-)
  323. _do_sort(lpIR->idCount, lpII);
  324. // 获得图标综合图像尺寸
  325. _get_synthesis_imgsize(lpIR->idCount, lpII, &size);
  326. LPIMAGEINFOSTR lpImgInfoStr = &pInfo->imginfo;
  327. // 获取文件的长度、图像的宽度、高度等信息
  328. lpImgInfoStr->imgtype = IMT_RESSTATIC;
  329. lpImgInfoStr->imgformat = IMF_ICO;
  330. lpImgInfoStr->filesize = file.GetLength();
  331. // 以下的宽度、高度是指综合图像的宽、高
  332. lpImgInfoStr->width = size.cx;
  333. lpImgInfoStr->height = size.cy;
  334. // 因为这是综合图像的位深,所以锁定为32位
  335. lpImgInfoStr->bitcount = 32;
  336. lpImgInfoStr->compression = ICS_RGB;
  337. // 每一图像行所占的字节数(DWORD对齐,并且只对非压缩位图有效)
  338. lpImgInfoStr->linesize = WIDTHBYTES(size.cx*32);
  339. lpImgInfoStr->imgnumbers = 1;
  340. // 表示不可编辑
  341. lpImgInfoStr->imgchang = 1;
  342. // 获取文件最后的修改日期(月在高字节,日在低字节)
  343. file.GetStatus(status);
  344. lpImgInfoStr->year = (WORD)status.m_mtime.GetYear();
  345. lpImgInfoStr->monday = (WORD)status.m_mtime.GetMonth();
  346. lpImgInfoStr->monday <<= 8;
  347. lpImgInfoStr->monday |= (WORD)status.m_mtime.GetDay();
  348. // 获取文件最后的修改时间(字序:最高—0, 2—时,1—分,0—秒)
  349. lpImgInfoStr->time = status.m_mtime.GetHour();
  350. lpImgInfoStr->time <<= 8;
  351. lpImgInfoStr->time |= status.m_mtime.GetMinute();
  352. lpImgInfoStr->time <<= 8;
  353. lpImgInfoStr->time |= status.m_mtime.GetSecond();
  354. lpImgInfoStr->time &= 0xffffff;
  355. ::GlobalFree((void*)lpII);
  356. ::GlobalFree((void*)lpIR);
  357. file.Close();
  358. // 设置出口数据
  359. pInfo->state = PKST_PASSINFO;
  360. pInfo->result = ER_SUCCESS;
  361. return;
  362. }
  363. // 操作命令解释函数---解释:CMD_LOAD_FROM_FILE命令
  364. // 从指定图像文件中读取数据
  365. void _fnCMD_LOAD_FROM_FILE(INFOSTR *pInfo)
  366. {
  367. // 检验入口参数是否符合接口定义
  368. ASSERT(pInfo->result == ER_EMPTY);
  369. ASSERT(::strlen(pInfo->filename));
  370. // 此时,该文件必需是一个已存在的、有效的ICO文件,并且数据包中
  371. // 含有该文件的信息(imginfo结构中)
  372. ASSERT(pInfo->state == PKST_PASSINFO);
  373. ASSERT(pInfo->imginfo.imgformat == IMF_ICO);
  374. ASSERT(pInfo->pImgInfo == NULL);
  375. // 必需设置标准图像格式信息
  376. ASSERT(pInfo->sDIBInfo.bmi.biSize == sizeof(BITMAPINFOHEADER));
  377. ASSERT(pInfo->pLineAddr != NULL);
  378. ASSERT(pInfo->_pbdata != NULL);
  379. CFile file;
  380. LPICONDIR lpIR;
  381. LPIMGINFO lpII;
  382. UINT i;
  383. if (pInfo->fpProgress)
  384. {
  385. if ((*pInfo->fpProgress)(RWPROGRESSSIZE, 6))
  386. { // 如果进度函数返回1,则说明用户想中断操作,返回。
  387. pInfo->result = ER_USERBREAK;
  388. return;
  389. }
  390. }
  391. // 打开指定文件
  392. if (!file.Open(pInfo->filename, CFile::modeRead))
  393. {
  394. pInfo->result = ER_FILERWERR;
  395. return;
  396. }
  397. file.Seek(0, CFile::begin);
  398. // 读取ICO文件的信息
  399. if ((lpIR = ReadIconInfo(file)) == NULL)
  400. {
  401. // 因读文件时出错或内存不足而调用失败
  402. file.Close();
  403. // 此处只能写一种错误原因,因为读盘失败的
  404. // 可能性比较大,所以写了读写文件错的代码
  405. pInfo->result = ER_FILERWERR;
  406. return;
  407. }
  408. // 分配图像信息结构所需空间
  409. lpII = (LPIMGINFO)::GlobalAlloc(GPTR, lpIR->idCount*sizeof(IMGINFO));
  410. if (!lpII)
  411. {
  412. ::GlobalFree((void*)lpIR);
  413. file.Close();
  414. pInfo->result = ER_MEMORYERR;
  415. return;
  416. }
  417. // 获取图标中每一副图像的尺寸数据
  418. for (i=0;i<lpIR->idCount;i++)
  419. {
  420. lpII[i].index = i;
  421. _get_image_info(lpIR, i, (LPSIZE)&(lpII[i].imgsize), (int*)&(lpII[i].colnum));
  422. _get_string_info((LPSIZE)&(lpII[i].imgsize), lpII[i].colnum, lpII[i].string, (LPSIZE)&(lpII[i].txtsize));
  423. }
  424. // 对图像结构数组进行排序(以图像宽度从小到大,:-)
  425. _do_sort(lpIR->idCount, lpII);
  426. PBYTE lpBits;
  427. HBITMAP hBmp;
  428. HBITMAP hCurBmp;
  429. RECT rect;
  430. HWND hWnd = ::GetDesktopWindow();
  431. HDC hDC = ::GetDC(hWnd);
  432. hBmp = CreateDIBSection(hDC, (LPBITMAPINFO)&(pInfo->sDIBInfo), 
  433. DIB_RGB_COLORS, (void**)&lpBits, NULL, 0);
  434. if (hBmp == NULL)
  435. {
  436. ::GlobalFree((void*)lpIR);
  437. ::GlobalFree((void*)lpII);
  438. file.Close();
  439. ::ReleaseDC(hWnd, hDC);
  440. pInfo->result = ER_SYSERR;
  441. return; // 操作系统不稳定
  442. }
  443. // 将图像的背景色设置为白
  444. HDC hMemDC = ::CreateCompatibleDC(hDC);
  445. HDC hSouDC = ::CreateCompatibleDC(hDC);
  446. HBITMAP hOldSouBmp;
  447. HBITMAP hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBmp);
  448. rect.left = 0; rect.top = 0; rect.right = pInfo->imginfo.width;
  449. rect.bottom = pInfo->imginfo.height;
  450. // 将图像的背景填充为系统定义的白色
  451. ::FillRect(hMemDC, (CONST RECT*)&rect, (HBRUSH)::GetStockObject(WHITE_BRUSH));
  452. int currentimg; // 当前待处理的图像
  453. int currentheight = BORDERSPEC; // 当前高度行坐标
  454. int mp = pInfo->imginfo.width/2;// 中点X坐标
  455. int ul, ut, dr, db;
  456. for (i=0;i<lpIR->idCount;i++)
  457. {
  458. currentimg = lpII[i].index;
  459. ul = mp-lpII[i].imgsize.cx/2;
  460. ut = currentheight;
  461. dr = ul+lpII[i].imgsize.cx;
  462. db = ut+lpII[i].imgsize.cy;
  463. // 获得图标文件中的指定图像
  464. hCurBmp = _get_hbmp(file, lpIR, lpII, i);
  465. if (!hCurBmp)
  466. {
  467. ::SelectObject(hMemDC, hOldBmp);
  468. ::DeleteDC(hSouDC);
  469. ::DeleteDC(hMemDC);
  470. ::ReleaseDC(hWnd, hDC);
  471. ::GlobalFree((void*)lpIR);
  472. ::GlobalFree((void*)lpII);
  473. ::DeleteObject(hBmp);
  474. file.Close();
  475. pInfo->result = ER_SYSERR; // 操作系统不稳定
  476. return;
  477. }
  478. // 将图像复制到主位图中
  479. hOldSouBmp = (HBITMAP)::SelectObject(hSouDC, hCurBmp);
  480. ::BitBlt(hMemDC, ul, ut, dr-ul, db-ut, hSouDC, 0, 0, SRCCOPY);
  481. ::SelectObject(hSouDC, hOldSouBmp);
  482. ::DeleteObject(hCurBmp);
  483. currentheight += lpII[i].imgsize.cy;
  484. currentheight += IMGTXTSPEC;
  485. // 计算字符串的显示位置
  486. ul = mp-lpII[i].txtsize.cx/2;
  487. ut = currentheight;
  488. dr = ul+lpII[i].txtsize.cx;
  489. db = ut+lpII[i].txtsize.cy;
  490. rect.left = ul; rect.top = ut; rect.right = dr; rect.bottom = db;
  491. // 绘制图标的描述字符串
  492. ::DrawText(hMemDC, lpII[i].string, lstrlen(lpII[i].string), 
  493. (RECT*)&rect, DT_SINGLELINE|DT_CENTER|DT_NOCLIP);
  494. currentheight += lpII[i].txtsize.cy;
  495. currentheight += TXTIMGSPEC;
  496. }
  497. ::SelectObject(hMemDC, hOldBmp);
  498. ::DeleteDC(hSouDC);
  499. ::DeleteDC(hMemDC);
  500. ::ReleaseDC(hWnd, hDC);
  501. // 将图像复制到数据包中
  502. ::memmove((void*)pInfo->_pbdata, (const void*)lpBits, 
  503. WIDTHBYTES(pInfo->sDIBInfo.bmi.biWidth*pInfo->sDIBInfo.bmi.biBitCount)*pInfo->imginfo.height);
  504. ::DeleteObject(hBmp);
  505. ::GlobalFree((void*)lpII);
  506. ::GlobalFree((void*)lpIR);
  507. file.Close();
  508. // 执行成功
  509. pInfo->state = PKST_INFOANDBITS;
  510. pInfo->modify = 0;
  511. pInfo->result = ER_SUCCESS;
  512. if (pInfo->fpProgress) // 结束进度条,此调用不再支持用户中断
  513. (*pInfo->fpProgress)(RWPROGRESSSIZE, RWPROGRESSSIZE);
  514. }
  515. // 操作命令解释函数---解释:CMD_SAVE_TO_FILE命令
  516. // 将数据保存到指定文件中
  517. void _fnCMD_SAVE_TO_FILE(INFOSTR *pInfo)
  518. {
  519. // 这个命令不一定要解释,你可以参考本图像格式的具体境况来决定
  520. // 是否解释该命令。
  521. // 如果你想解释该命令,请在下面加入代码,并修改pInfo->result的返回值:
  522. // ----------------------------------------------------------------->
  523. pInfo->result = ER_NOTSUPPORT;
  524. }
  525. // 操作命令解释函数---解释:CMD_RESIZE命令
  526. // 重新获取指定尺寸的图像位数据(只适用于矢量图像)
  527. void _fnCMD_RESIZE(INFOSTR *pInfo)
  528. {
  529. // 这个命令一般的图像读写模块不需要支持,它只适用于矢量图像,
  530. // 比如WMF、EMF之类。
  531. // 如果你想解释该命令,请在下面加入代码,并修改pInfo->result的返回值:
  532. // ----------------------------------------------------------------->
  533. pInfo->result = ER_NOTSUPPORT;
  534. }
  535. /*************************************************************************
  536.  *
  537.  * IsFileExist()
  538.  * 
  539.  * 参数说明:
  540.  *
  541.  * char *lpFileName - 待判断的文件路径和名称(文件名)
  542.  *
  543.  * 返回值:
  544.  *
  545.  * BOOL - 如果指定的文件存在返回TRUE,否则返回FALSE。
  546.  * 
  547.  * 描述:
  548.  *
  549.  * 判断指定的文件是否存在
  550.  * 
  551.  * 该文件必需可以被读和写
  552.  *
  553.  ************************************************************************/
  554. BOOL IsFileExist(char *lpFileName)
  555. {
  556. CFile file;
  557. BOOL bExist = FALSE; // 文件存在是TRUE,不存在是FALSE
  558. CFileException e;
  559. // 确定指定的文件是否存在
  560. if (file.Open(lpFileName, CFile::modeReadWrite|CFile::shareDenyNone, &e))
  561. {
  562. bExist = TRUE;
  563. file.Close();
  564. }
  565. else
  566. {
  567. // 可能有其他程序正在处理此文件
  568. switch(e.m_cause)
  569. {
  570. case CFileException::tooManyOpenFiles:
  571. case CFileException::accessDenied:
  572. case CFileException::sharingViolation:
  573. case CFileException::lockViolation:
  574. return TRUE;
  575. case CFileException::fileNotFound:
  576. case CFileException::badPath:
  577. case CFileException::invalidFile:
  578. case CFileException::hardIO:
  579. default:
  580. return FALSE;
  581. }
  582. }
  583. return bExist;
  584. }
  585. /****************************************************************************
  586. *
  587. *     FUNCTION: ReadIconInfo
  588. *
  589. *     PURPOSE:  获取指定ICO文件的信息(包括图像个数、图像尺寸、位深等)
  590. *
  591. *     PARAMS:   CFile& file - 图标文件类引用
  592. *
  593. *     RETURNS:  LPICONDIR - NULL 失败(由读文件或内存不足引起),非NULL
  594. *                           表示成功,返回值是一个指向ICONDIR的指针
  595. *
  596. ****************************************************************************/
  597. LPICONDIR ReadIconInfo(CFile& file)
  598. {
  599. ICONDIR icondir;
  600. int uRet, infosize;
  601. // 读取图标文件信息头结构
  602. file.SeekToBegin();
  603. uRet  = file.Read((LPSTR)&icondir, sizeof(ICONDIR));
  604. if (uRet != sizeof(ICONDIR))
  605. return NULL;
  606. ASSERT(icondir.idCount >= 1);
  607. // 计算图标信息块的尺寸
  608. infosize = sizeof(ICONDIR)+(icondir.idCount-1)*sizeof(ICONDIRENTRY);
  609. // 分配用于存放图标信息的缓冲区内存块
  610. LPICONDIR lpIR = (LPICONDIR)::GlobalAlloc(GPTR, infosize);
  611. if (!lpIR)
  612. return NULL;
  613. // 读取图标信息
  614. file.SeekToBegin();
  615. uRet  = file.Read((LPSTR)lpIR, infosize);
  616. if (uRet != infosize)
  617. {
  618. ::GlobalFree(lpIR);
  619. return NULL;
  620. }
  621. return lpIR;
  622. }
  623. /****************************************************************************
  624. *
  625. *     FUNCTION: ReadICOHeader
  626. *
  627. *     PURPOSE:  读取ICO文件的头结构中的图像个数
  628. *
  629. *     PARAMS:   CFile& file - CFile类目标的引用
  630. *
  631. *     RETURNS:  UINT - 文件中图标图像的个数,-1表示失败
  632. *
  633. ****************************************************************************/
  634. UINT ReadICOHeader(CFile& file)
  635. {
  636. ICONDIR dir;
  637. TRY
  638. {
  639. file.SeekToBegin();
  640. file.Read((void*)&dir, sizeof(ICONDIR));
  641. }
  642. CATCH(CFileException, e)
  643. {
  644. return (UINT)-1; // 读文件时出错
  645. }
  646. END_CATCH
  647.     
  648.     return (UINT)dir.idCount;
  649. }
  650. /****************************************************************************
  651. *
  652. *     FUNCTION: FindDIBits
  653. *
  654. *     PURPOSE:  定位在CF_DIB格式的DIB图像数据中位数据的地址
  655. *
  656. *     PARAMS:   LPSTR lpbi - 指向CF_DIB内存块的指针
  657. *
  658. *     RETURNS:  LPSTR - 指向位数据的指针
  659. *
  660. ****************************************************************************/
  661. LPSTR FindDIBBits(LPSTR lpbi)
  662. {
  663.    return (lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ));
  664. }
  665. /****************************************************************************
  666. *
  667. *     FUNCTION: DIBNumColors
  668. *
  669. *     PURPOSE:  计算指定DIB的调色板中颜色的个数
  670. *
  671. *     PARAMS:   LPSTR lpbi - 指向CF_DIB内存块
  672. *
  673. *     RETURNS:  WORD - 调色板中颜色项的个数
  674. *
  675. ****************************************************************************/
  676. WORD DIBNumColors(LPSTR lpbi)
  677. {
  678.     WORD wBitCount;
  679.     DWORD dwClrUsed;
  680.     dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
  681. // 如果文件指定了实际使用的颜色个数,则直接使用这个值
  682.     if (dwClrUsed)
  683.         return (WORD)dwClrUsed;
  684. // 否则通过位深度值进行相应的计算
  685.     wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
  686.     switch (wBitCount)
  687.     {
  688.         case 1: return 2;
  689.         case 4: return 16;
  690.         case 8: return 256;
  691.         default:return 0;
  692.     }
  693.     return 0;
  694. }
  695. /****************************************************************************
  696. *
  697. *     FUNCTION: PaletteSize
  698. *
  699. *     PURPOSE:  计算调色板的尺寸
  700. *
  701. *     PARAMS:   LPSTR lpbi - 指向CF_DIB内存块
  702. *
  703. *     RETURNS:  WORD - 调色板的尺寸(以字节为单位)
  704. *
  705. ****************************************************************************/
  706. WORD PaletteSize(LPSTR lpbi)
  707. {
  708.     return (DIBNumColors(lpbi) * sizeof(RGBQUAD));
  709. }
  710. /****************************************************************************
  711. *
  712. *     FUNCTION: BytesPerLine
  713. *
  714. *     PURPOSE:  计算扫描行的宽度(以字节为单位)
  715. *
  716. *     PARAMS:   LPBITMAPINFOHEADER lpBMIH - 指向CF_DIB内存块中BITMAPINFOHEADER
  717. *                                           的指针
  718. *
  719. *     RETURNS:  DWORD - 扫描行的宽度。(注:DIB扫描行的宽度是DWORD对齐的)
  720. *
  721. ****************************************************************************/
  722. DWORD BytesPerLine(LPBITMAPINFOHEADER lpBMIH)
  723. {
  724.     return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
  725. }
  726. /****************************************************************************
  727. *
  728. *     FUNCTION: _get_image_info
  729. *
  730. *     PURPOSE:  获得指定图像的宽、高尺寸及颜色数目
  731. *
  732. *     PARAMS:   LPICONDIR lpIR - 图标原始数组数组
  733. * int index - 得获取尺寸的图像之索引
  734. * LPSIZE lpSize - 接收尺寸的变量
  735. * int *pColnum - 接收颜色数目的变量
  736. *
  737. *     RETURNS:   - 
  738. *
  739. ****************************************************************************/
  740. void _get_image_info(LPICONDIR lpIR, int index, LPSIZE lpSize, int *pColnum)
  741. {
  742. ASSERT(index <= lpIR->idCount);
  743. lpSize->cx = lpIR->idEntries[index].bWidth;
  744. lpSize->cy = lpIR->idEntries[index].bHeight;
  745. *pColnum = lpIR->idEntries[index].bColorCount;
  746. }
  747. /****************************************************************************
  748. *
  749. *     FUNCTION: _get_string_info
  750. *
  751. *     PURPOSE:  获得指定图像宽、高字符串的尺寸及字符串
  752. *
  753. *     PARAMS:   LPSIZE lpImgSize - 图像尺寸数据
  754. * int colnum - 图像的颜色数目
  755. * LPTSTR lpString - 接收字符串的变量
  756. * LPSIZE lpTxtSize - 接收文本尺寸的变量
  757. *
  758. *     RETURNS:   - 
  759. *
  760. ****************************************************************************/
  761. void _get_string_info(LPSIZE lpImgSize, int colnum, LPTSTR lpString, LPSIZE lpTxtSize)
  762. {
  763. ASSERT(lpImgSize);
  764. // 获取图像尺寸字符串
  765. sprintf((char*)lpString, "%d*%d*%d", lpImgSize->cx, lpImgSize->cy, colnum);
  766. HWND hWnd = ::GetDesktopWindow();
  767. HDC  hDC  = ::GetDC(hWnd);
  768. // 获取字符串的长度
  769. ::GetTextExtentPoint32(hDC, lpString, lstrlen((LPCTSTR)lpString), lpTxtSize); 
  770. ::ReleaseDC(hWnd, hDC);
  771. return;
  772. }
  773. /****************************************************************************
  774. *
  775. *     FUNCTION: _get_synthesis_imgsize
  776. *
  777. *     PURPOSE:  计算综合图像的尺寸(就是将所有格式的图像
  778. * 拼接在一起的总尺寸)
  779. *
  780. *     PARAMS:   int imgcount - 有多少副图像
  781. * LPIMGINFO lpImgInfo - 图像数据数组首指针
  782. * (注:此时的数组必需已被排序)
  783. * LPSIZE lpSize - 接收综合尺寸的变量
  784. *
  785. *     RETURNS:   - 
  786. *
  787. ****************************************************************************/
  788. void _get_synthesis_imgsize(int imgcount, LPIMGINFO lpImgInfo, LPSIZE lpSize)
  789. {
  790. SIZE size;
  791. ASSERT(imgcount >= 1);
  792. ASSERT(lpImgInfo);
  793. ASSERT(lpSize);
  794. // imgcount-1 就是结构数组中最后一个项,因为该数组
  795. // 已经经过了排序,所以最后一个就是最宽的一个
  796. size.cx = lpImgInfo[imgcount-1].imgsize.cx;
  797. // 如果字串的宽度超出了图像的宽度,则取字串宽度
  798. if (lpImgInfo[imgcount-1].txtsize.cx > size.cx)
  799. size.cx = lpImgInfo[imgcount-1].txtsize.cx;
  800. // 加上边界宽度
  801. size.cx += BORDERSPEC*2;
  802. // 计算综合图像高度
  803. size.cy = BORDERSPEC;
  804. // 综合图像高度的计算方法是:
  805. // 上边界+图像高度+图像到文本间隔+文本高度+
  806. // 文本到图像间隔+第二副图像高度+图像到文本间
  807. // 隔+ ..... +底边界
  808. for (int i=0;i<imgcount;i++)
  809. {
  810. size.cy += lpImgInfo[i].imgsize.cy;
  811. size.cy += IMGTXTSPEC;
  812. size.cy += lpImgInfo[i].txtsize.cy;
  813. size.cy += TXTIMGSPEC;
  814. }
  815. // 加底边界高度
  816. size.cy += BORDERSPEC-TXTIMGSPEC;
  817. lpSize->cx = size.cx;
  818. lpSize->cy = size.cy;
  819. }
  820. /****************************************************************************
  821. *
  822. *     FUNCTION: _do_sort
  823. *
  824. *     PURPOSE:  将图标图像信息数组根据图像的宽度进行排序
  825. *
  826. *     PARAMS:   int imgcount - 有多少副图像
  827. * LPIMGINFO lpImgInfo - 图像数据数组首指针
  828. *
  829. *     RETURNS:   - 返回后,数组中的数据将从小到大的被排序
  830. *
  831. ****************************************************************************/
  832. void _do_sort(int imgcount, LPIMGINFO lpImgInfo)
  833. {
  834. int i, j, sortcount;
  835. IMGINFO imgtmp;
  836. // 初始化起始值
  837. sortcount = imgcount-1;
  838. // 起泡排序法
  839. for (i=0;i<sortcount;i++)
  840. {
  841. for (j=0;j<(sortcount-i);j++)
  842. {
  843. // 以图像宽度为判别标准
  844. if (lpImgInfo[j].imgsize.cx > lpImgInfo[j+1].imgsize.cx)
  845. {
  846. // 交换数据
  847. ::memcpy((void*)&imgtmp, (const void*)&lpImgInfo[j], sizeof(IMGINFO));
  848. ::memcpy((void*)&lpImgInfo[j], (const void*)&lpImgInfo[j+1], sizeof(IMGINFO));
  849. ::memcpy((void*)&lpImgInfo[j+1], (const void*)&imgtmp, sizeof(IMGINFO));
  850. }
  851. }
  852. }
  853. }
  854. /****************************************************************************
  855. *
  856. *     FUNCTION: _get_hbmp
  857. *
  858. *     PURPOSE:  获取指定图像的句柄
  859. *
  860. *     PARAMS:   CFile& file - 图标文件目标
  861. * LPICONDIR lpIR - 原始图像数据数组
  862. * LPIMGINFO lpImgInfo - 图像数据数组首指针
  863. * int index - 指定获取句柄的图像索引(排序后的索引)
  864. *
  865. *     RETURNS:  HBITMAP - 图像的句柄,失败返回NULL
  866. *
  867. ****************************************************************************/
  868. HBITMAP _get_hbmp(CFile& file, LPICONDIR lpIR, LPIMGINFO lpImgInfo, int index)
  869. {
  870. HBITMAP hBmp, hXORBmp, hANDBmp;
  871. HBITMAP hOldBmp, hOldBmp2;
  872. // 图像所占字节数
  873. DWORD imgsize = lpIR->idEntries[lpImgInfo[index].index].dwBytesInRes;
  874. // 图像数据偏移
  875. DWORD imgoffset = lpIR->idEntries[lpImgInfo[index].index].dwImageOffset;
  876. // 分配用于存放指定DF_DIB数据的内存块
  877. PBYTE lpDIB = (PBYTE)::GlobalAlloc(GPTR, imgsize);
  878. if (!lpDIB)
  879. return NULL;
  880. // 读取图像的DF_DIB数据
  881. file.Seek(imgoffset, CFile::begin);
  882. if (file.ReadHuge((void*)lpDIB, imgsize) != imgsize)
  883. {
  884. ::GlobalFree(lpDIB);
  885. return NULL;
  886. }
  887. // 该高度值是XOR图与AND图高度的和,所以得除2
  888. ((LPBITMAPINFOHEADER)lpDIB)->biHeight /= 2;
  889. RECT rect;
  890. HWND hWnd = ::GetDesktopWindow();
  891. HDC  hDC  = ::GetDC(hWnd);
  892. HDC  hMemDC = ::CreateCompatibleDC(hDC);
  893. // 创建目标图像
  894. hBmp = ::CreateCompatibleBitmap(hDC, lpImgInfo[index].imgsize.cx,lpImgInfo[index].imgsize.cy);
  895. if (!hBmp)
  896. {
  897. ::GlobalFree(lpDIB);
  898. ::ReleaseDC(hWnd, hDC);
  899. ::DeleteDC(hMemDC);
  900. return NULL;
  901. }
  902. hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBmp);
  903. rect.left = rect.top = 0;
  904. rect.right = lpImgInfo[index].imgsize.cx;
  905. rect.bottom = lpImgInfo[index].imgsize.cy;
  906. // 将图像填充为白色
  907. ::FillRect(hMemDC, (CONST RECT*)&rect, (HBRUSH)::GetStockObject(WHITE_BRUSH));
  908. ::SelectObject(hMemDC, hOldBmp);
  909. // 创建XOR图像
  910. hXORBmp = ::CreateCompatibleBitmap(hDC, lpImgInfo[index].imgsize.cx,lpImgInfo[index].imgsize.cy);
  911. if (!hXORBmp)
  912. {
  913. ::DeleteObject(hBmp);
  914. ::GlobalFree(lpDIB);
  915. ::ReleaseDC(hWnd, hDC);
  916. ::DeleteDC(hMemDC);
  917. return NULL;
  918. }
  919. ::SetDIBits(hDC, hXORBmp, 0, lpImgInfo[index].imgsize.cy, 
  920. (const void*)::FindDIBBits((LPSTR)lpDIB), (CONST BITMAPINFO *)lpDIB, DIB_RGB_COLORS);
  921. // 创建AND图像
  922. hANDBmp = ::CreateBitmap(lpImgInfo[index].imgsize.cx, 
  923. lpImgInfo[index].imgsize.cy, 1, 1, NULL);
  924. if (!hANDBmp)
  925. {
  926. ::DeleteObject(hXORBmp);
  927. ::DeleteObject(hBmp);
  928. ::GlobalFree(lpDIB);
  929. ::ReleaseDC(hWnd, hDC);
  930. ::DeleteDC(hMemDC);
  931. return NULL;
  932. }
  933. LPBITMAPINFO lpbmi;
  934. lpbmi = (LPBITMAPINFO)::GlobalAlloc(GPTR, sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2);
  935. if (!lpbmi)
  936. {
  937. ::DeleteObject(hANDBmp);
  938. ::DeleteObject(hXORBmp);
  939. ::DeleteObject(hBmp);
  940. ::GlobalFree(lpDIB);
  941. ::ReleaseDC(hWnd, hDC);
  942. ::DeleteDC(hMemDC);
  943. return NULL;
  944. }
  945. lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  946. lpbmi->bmiHeader.biBitCount = 1;
  947. lpbmi->bmiHeader.biClrImportant = 0;
  948. lpbmi->bmiHeader.biClrUsed = 0;
  949. lpbmi->bmiHeader.biCompression = BI_RGB;
  950. lpbmi->bmiHeader.biHeight = ((LPBITMAPINFOHEADER)lpDIB)->biHeight;
  951. lpbmi->bmiHeader.biPlanes = 1;
  952. lpbmi->bmiHeader.biSizeImage = 0;
  953. lpbmi->bmiHeader.biWidth = ((LPBITMAPINFOHEADER)lpDIB)->biWidth;
  954. lpbmi->bmiHeader.biXPelsPerMeter = 0;
  955. lpbmi->bmiHeader.biYPelsPerMeter = 0;
  956.     lpbmi->bmiColors[0].rgbRed = 0;
  957.     lpbmi->bmiColors[0].rgbGreen = 0;
  958.     lpbmi->bmiColors[0].rgbBlue = 0;
  959.     lpbmi->bmiColors[0].rgbReserved = 0;
  960.     lpbmi->bmiColors[1].rgbRed = 255;
  961.     lpbmi->bmiColors[1].rgbGreen = 255;
  962.     lpbmi->bmiColors[1].rgbBlue = 255;
  963.     lpbmi->bmiColors[1].rgbReserved = 0;
  964. ::SetDIBits(hMemDC, hANDBmp, 0, lpImgInfo[index].imgsize.cy, 
  965. (const void*)((PBYTE)::FindDIBBits((LPSTR)lpDIB) + 
  966. WIDTHBYTES(lpImgInfo[index].imgsize.cx*((LPBITMAPINFOHEADER)lpDIB)->biBitCount) * 
  967. lpImgInfo[index].imgsize.cy), 
  968. lpbmi, DIB_RGB_COLORS);
  969. ::GlobalFree(lpbmi);
  970. // 合成图像
  971. HDC  hMemDC2 = ::CreateCompatibleDC(hDC);
  972. hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBmp);
  973. hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, hANDBmp);
  974. ::BitBlt(hMemDC, 0, 0, lpImgInfo[index].imgsize.cx, lpImgInfo[index].imgsize.cy, hMemDC2, 0, 0, SRCAND);
  975. ::SelectObject(hMemDC2, hXORBmp);
  976. ::BitBlt(hMemDC, 0, 0, lpImgInfo[index].imgsize.cx, lpImgInfo[index].imgsize.cy, hMemDC2, 0, 0, SRCINVERT);
  977. ::SelectObject(hMemDC2, hOldBmp2);
  978. ::SelectObject(hMemDC, hOldBmp);
  979. // 释放无关资源
  980. ::DeleteDC(hMemDC2);
  981. ::DeleteDC(hMemDC);
  982. ::ReleaseDC(hWnd, hDC);
  983. ::GlobalFree(lpDIB);
  984. ::DeleteObject(hANDBmp);
  985. ::DeleteObject(hXORBmp);
  986. // 返回合成位图
  987. return hBmp;
  988. }