最近需要写一个提取EXE或者DLL图标资源的功能, 网上找了很久, 要么功能不好用, 最后结果如下:
1.很多是加载为HICON句柄后转换为图片保存, 全损画质...,
2.后来找了个还能用的, 详见
https://github.com/TortoiseGit/TortoiseGit/blob/master/src/Utils/IconExtractor.cpp
但是这个有Bug, 提取的资源是有误的, 与Resource Hacker(Resource Hacker (angusj.com))或者ResourcesExtract(ResourcesExtract - Extract files (bitmaps, icons, html files, and more) from dll files (nirsoft.net))提取的数据不一样, 放在浏览器上也加载有误综上所述, 于是决定自己写一个, 翻阅多方资料后, 总算完成了协助这个资源提取类, 目前主要功能就是提取PE文件的ICO图标资源, 功能要点如下:
1.获取PE的所有ICON组信息, 图标组数量, 宽高信息等
2.提取图标组另存到文件
3.提取图标组中的单张图标另存到文件
备注:
1.暂且称多张图片组成的ICO图标为图标组
2.只有一张图片的ICO暂且称之为单个图标
CResourceExtractor.h
#pragma once
//
// @brief: PE文件资源提取器
// @copyright: Copyright 2024 FlameCyclone
// @license:
// @birth: Created by Visual Studio 2022 on 2024-01-27
// @version: V1.0.0
// @revision: last revised by FlameCyclone on 2024-01-27
//
#include
#include
#include
#include
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
//相关参考文档
//ICO格式百科 https://en.wikipedia.org/wiki/ICO_(file_format)
//NEWHEADER 结构 https://learn.microsoft.com/zh-cn/windows/win32/menurc/newheader
//RESDIR 结构 https://learn.microsoft.com/zh-cn/windows/win32/menurc/resdir
//ICONRESDIR 结构 https://learn.microsoft.com/zh-cn/windows/win32/menurc/iconresdir
#pragma pack(push)
#pragma pack(1)
typedef struct
{
WORD Reserved; //保留;必须为零
WORD ResType; //资源类型 1: RES_ICON 2: RES_CURSOR
WORD ResCount; //资源组中的图标或游标组件数
} ICON_GROUP_HEADER, * LPICON_GROUP_HEADER;
typedef struct
{
BYTE Width; //图标的宽度(以像素为单位)。 可接受的值为 16、32 和 64
BYTE Height; //图标的高度(以像素为单位)。 可接受的值为 16、32 和 64
BYTE ColorCount; //图标中的颜色数。 可接受的值为 2、8 和 16。
BYTE reserved; //保留;必须设置为与图标文件标头中保留字段的值相同的值
WORD Planes; //图标或光标位图中的颜色平面数
WORD BitCount; //图标或光标位图中每像素的位数
DWORD BytesInRes; //资源的大小(以字节为单位)
WORD IconId; //具有唯一序号标识符的图标或光标
} ICON_ENTRY, * LPICON_ENTRY;
typedef struct {
ICON_GROUP_HEADER Header; //图标组头部
ICON_ENTRY IconEntry[1]; //单个图标信息
}ICON_GROUP_DIR, * LPICON_GROUP_DIR;
typedef struct
{
BYTE Width; //图标的宽度(以像素为单位)。 可接受的值为 16、32 和 64
BYTE Height; //图标的高度(以像素为单位)。 可接受的值为 16、32 和 64
BYTE ColorCount; //图标中的颜色数。 可接受的值为 2、8 和 16
BYTE reserved; //保留;必须设置为与图标文件标头中保留字段的值相同的值
WORD Planes; //图标或光标位图中的颜色平面数
WORD BitCount; //图标或光标位图中每像素的位数
DWORD BytesInRes; //资源的大小(以字节为单位)
DWORD Offset; //图标文件偏移
} ICON_FILE_ENTRY, * LPICON_FILE_ENTRY;
typedef struct {
ICON_GROUP_HEADER Header; //图标组头部
ICON_FILE_ENTRY IconEntry[1]; //单个图标信息
}ICON_FILE_DIR, * LPICON_FILE_DIR;
// IHDR数据头
// http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.Additional-chunk-types
typedef struct
{
DWORD Width; //图片宽度(大头序存放)
DWORD Height; //图片高度(大头序存放)
BYTE BitDepth; //每像素的位数, 有效值为 1、2、4、8 和 16
BYTE ColorType; //颜色类型
//0: BitDepth为 1,2,4,8,16 每个像素都是一个灰度样本
//2: BitDepth为 8,16 每个像素是一个 R、G、B 三元组
//3: BitDepth为 1,2,4,8 每个像素为调色板索引, 必须出现 PLTE 块
//4: BitDepth为 8,16 每个像素都是一个灰度样本, 后跟 alpha 样本。
//6: BitDepth为 8,16 每个像素是一个 R、G、B 三元组, 后跟 alpha 样本
BYTE CompressionMethod; //压缩方法
BYTE FilterMethod; //滤波器方法
BYTE InterlaceMethod; //隔行扫描方法: 0:非隔行扫描 1: Adam7(由Adam M.Costello开发的7遍隔行扫描方法)
}IHDR, * LPIHDR;
// PNG图像文件头信息
// https://en.wikipedia.org/wiki/PNG
typedef struct
{
BYTE Signature[8]; //PNG固定签名标识
DWORD ChunkLength; //数据块长度
CHAR ChunkType[4]; //数据块类型, 应该为IHDR
IHDR Ihdr; //IHDR图像头
DWORD Crc32; //块数据校验码(包括块类型与块数据
}PNG_HEADER, * LPPNG_HEADER;
// https://learn.microsoft.com/zh-cn/windows/win32/gdi/bitmap-header-types
typedef union
{
BITMAPCOREHEADER BitmapCore; //Windows 2.0 or later 12 字节
BITMAPINFOHEADER BitmapInfo; //Windows NT, 3.1x or later 40 字节
BITMAPV4HEADER BitmapV4; //Windows NT 4.0, 95 or later 108 字节
BITMAPV5HEADER BitmapV5; //Windows NT 5.0, 98 or later 124 字节
}BITMAPHEADER, *LPBITMAPHEADER;
// BMP位图文件头信息
// https://en.wikipedia.org/wiki/BMP_file_format
typedef struct
{
BYTE Signature[2]; //BMP固定签名标识
DWORD Size; //图像文件大小(整个文件的大小)
WORD Reserved[2]; //保留字段
DWORD Offset; //图像数据偏移
BITMAPHEADER BitmapInfo; //位图信息
}BMP_HEADER, * LPBMP_HEADER;
#pragma pack(pop)
enum eIconFileFormat
{
eFormatBmp, //位图格式
eFormatPng //PNG图片
};
typedef struct
{
WORD wID; //ID值
DWORD Width; //图片宽度
DWORD Height; //图片高度
eIconFileFormat FileFormat; //文件格式
}ICON_INFO;
typedef struct
{
_tstring strIDName; //ID字符串
WORD wID; //ID值
bool bIntResource; //是否为整数资源ID, 否则为字符串资源ID
std::vector Icons; //图标信息列表
}ICON_GROUP_INFO;
// 资源提取工具类
class CResourceExtractor
{
public:
CResourceExtractor();
~CResourceExtractor();
bool Load(const _tstring& strPeFile);
//
// @brief: 获取图标组总数
// @param: strModule 模块路径
// @ret: size_t 图标数量
size_t GetGroupIconCount() const;
//
// @brief: 获取图标组信息列表
// @ret: std::vector 图标信息列表
std::vector GetGroupIconInfos() const;
//
// @brief: 提取图标组保存到文件
// @param: nIconIndex 图标索引
// @param: strFile 保存文件路径
// @ret: bool 操作是否成功
bool ExtractGroupIconToFile(WORD nIconIndex, const _tstring& strOutFile);
//
// @brief: 提取图标组保存到文件
// @param: iconGroupInfo 图标组信息
// @param: strFile 保存文件路径
// @ret: bool 操作是否成功
bool ExtractGroupIconToFile(const ICON_GROUP_INFO& iconGroupInfo, const _tstring& strOutFile);
//
// @brief: 提取单个图标保存到文件
// @param: nGroupIndex 图标组索引
// @param: nIconIndex 图标索引
// @param: strFile 保存文件路径
// @ret: bool 操作是否成功
bool ExtractIconToFile(WORD nGroupIndex, WORD nIconIndex, const _tstring& strOutFile);
//
// @brief: 提取单个图标保存到文件
// @param: iconGroupInfo 图标组信息
// @param: nIconIndex 图标索引
// @param: strFile 保存文件路径
// @ret: bool 操作是否成功
bool ExtractIconToFile(const ICON_GROUP_INFO& iconGroupInfo, WORD nIconIndex, const _tstring& strOutFile);
private:
LPICON_GROUP_DIR GetGroupDir(const ICON_GROUP_INFO& iconGroupInfo);
bool WriteGroupIconToFile(HMODULE hModule, LPICON_GROUP_DIR lpIconGroupDir, const _tstring& strOutFile);
bool WriteIconToFile(HMODULE hModule, LPICON_GROUP_DIR lpIconGroupDir, WORD wID, const _tstring& strOutFile);
static std::vector GetIconGroupInfo(HMODULE hModule, LPCTSTR lpIdName);
static bool IsPngSignature(LPVOID lpData);
private:
HMODULE m_hModule; //PE模块句柄
std::vector m_listIcons; //图标ID列表
};
CResourceExtractor.cpp
#include "CResourceExtractor.h"
#define BIG_LITTLE_SWAP32(_data) ( (((DWORD)_data & 0x000000FF) << 24) | \
(((DWORD)_data & 0x0000FF00) << 8) | \
(((DWORD)_data & 0x00FF0000) >> 8) | \
(((DWORD)_data & 0xFF000000) >> 24) )
CResourceExtractor::CResourceExtractor()
:
m_hModule(nullptr)
{
}
CResourceExtractor::~CResourceExtractor()
{
if (m_hModule)
{
::FreeLibrary(m_hModule);
m_hModule = nullptr;
}
}
size_t CResourceExtractor::GetGroupIconCount() const
{
return m_listIcons.size();
}
bool CResourceExtractor::Load(const _tstring& strPeFile)
{
if (m_hModule)
{
::FreeLibrary(m_hModule);
}
m_listIcons.clear();
// 以数据资源方式加载PE文件
m_hModule = ::LoadLibraryEx(strPeFile.c_str(), 0, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (!m_hModule)
{
return false;
}
// 枚举指定索引的资源
::EnumResourceNames(m_hModule, RT_GROUP_ICON, [](
_In_opt_ HMODULE hModule,
_In_ LPCTSTR lpType,
_In_ LPTSTR lpName,
_In_ LONG_PTR lParam
)->BOOL {
UNREFERENCED_PARAMETER(hModule);
UNREFERENCED_PARAMETER(lpType);
std::vector* pInfos = reinterpret_cast*>(lParam);
ICON_GROUP_INFO info;
info.bIntResource = IS_INTRESOURCE(lpName);
if (info.bIntResource)
{
info.wID = reinterpret_cast(lpName);
}
else
{
info.strIDName = lpName;
}
info.Icons = GetIconGroupInfo(hModule, lpName);
pInfos->push_back(info);
return TRUE;
}, reinterpret_cast(&m_listIcons));
return true;
}
std::vector CResourceExtractor::GetIconGroupInfo(HMODULE hModule, LPCTSTR lpIdName)
{
std::vector infos;
HRSRC hResource = nullptr;
HGLOBAL hGlobal = nullptr;
LPICON_GROUP_DIR lpIconGroupDir = nullptr;
do
{
//查找资源
hResource = ::FindResource(hModule, lpIdName, RT_GROUP_ICON);
if (!hResource)
{
break;
}
//加载资源数据
hGlobal = ::LoadResource(hModule, hResource);
if (!hGlobal)
{
break;
}
//检索指向内存中指定资源的指针
lpIconGroupDir = (LPICON_GROUP_DIR)::LockResource(hGlobal);
if (!lpIconGroupDir)
{
break;
}
//写入数据
for (int i = 0; i < lpIconGroupDir->Header.ResCount; i++)
{
HRSRC hIcoResource = nullptr;
HGLOBAL hIcoGlobal = nullptr;
LPBYTE lpIconData = nullptr;
//查找资源
hIcoResource = ::FindResource(hModule, MAKEINTRESOURCE(lpIconGroupDir->IconEntry[i].IconId), RT_ICON);
if (!hIcoResource)
{
break;
}
//检查数据大小
if (lpIconGroupDir->IconEntry[i].BytesInRes != ::SizeofResource(hModule, hIcoResource))
{
break;
}
//加载资源数据
hIcoGlobal = ::LoadResource(hModule, hIcoResource);
if (!hIcoGlobal)
{
break;
}
//锁定数据
lpIconData = (LPBYTE)::LockResource(hIcoGlobal);
if (!lpIconData)
{
break;
}
LPPNG_HEADER lpPngHeader = (LPPNG_HEADER)lpIconData;
LPBITMAPHEADER lpBmpHeader = (LPBITMAPHEADER)lpIconData;
ICON_INFO info = { 0 };
info.wID = lpIconGroupDir->IconEntry[i].IconId;
info.FileFormat = eIconFileFormat::eFormatBmp;
if (IsPngSignature(lpPngHeader))
{
info.FileFormat = eIconFileFormat::eFormatPng;
info.Width = BIG_LITTLE_SWAP32(lpPngHeader->Ihdr.Width);
info.Height = BIG_LITTLE_SWAP32(lpPngHeader->Ihdr.Height);
}
else
{
info.FileFormat = eIconFileFormat::eFormatBmp;
info.Width = lpIconGroupDir->IconEntry[i].Width;
info.Height = lpIconGroupDir->IconEntry[i].Height;
}
infos.push_back(info);
}
} while (false);
return infos;
}
bool CResourceExtractor::IsPngSignature(LPVOID lpData)
{
const BYTE PngSignature[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
return 0 == memcmp(lpData, PngSignature, sizeof(PngSignature));
}
std::vector CResourceExtractor::GetGroupIconInfos() const
{
return m_listIcons;
}
bool CResourceExtractor::ExtractGroupIconToFile(WORD nIconIndex, const _tstring& strOutFile)
{
if (nullptr == m_hModule)
{
return false;
}
if (m_listIcons.size() <= nIconIndex)
{
return false;
}
return WriteGroupIconToFile(m_hModule, GetGroupDir(m_listIcons[nIconIndex]), strOutFile);
}
bool CResourceExtractor::ExtractGroupIconToFile(const ICON_GROUP_INFO& iconGroupInfo, const _tstring& strOutFile)
{
if (nullptr == m_hModule)
{
return false;
}
return WriteGroupIconToFile(m_hModule, GetGroupDir(iconGroupInfo), strOutFile);
}
bool CResourceExtractor::ExtractIconToFile(WORD nGroupIndex, WORD nIconIndex, const _tstring& strOutFile)
{
if (nullptr == m_hModule)
{
return false;
}
if (nGroupIndex >= m_listIcons.size())
{
return false;
}
if (nIconIndex >= m_listIcons[nGroupIndex].Icons.size())
{
return false;
}
const ICON_GROUP_INFO& iconGroupInfo = m_listIcons[nGroupIndex];
return WriteIconToFile(m_hModule, GetGroupDir(iconGroupInfo), iconGroupInfo.Icons[nIconIndex].wID, strOutFile);
}
bool CResourceExtractor::ExtractIconToFile(const ICON_GROUP_INFO& iconGroupInfo, WORD nIconIndex, const _tstring& strOutFile)
{
if (nullptr == m_hModule)
{
return false;
}
if (nIconIndex >= iconGroupInfo.Icons.size())
{
return false;
}
return WriteIconToFile(m_hModule, GetGroupDir(iconGroupInfo), iconGroupInfo.Icons[nIconIndex].wID, strOutFile);
}
LPICON_GROUP_DIR CResourceExtractor::GetGroupDir(const ICON_GROUP_INFO& iconGroupInfo)
{
if (nullptr == m_hModule)
{
return nullptr;
}
HRSRC hResource = nullptr;
HGLOBAL hGlobal = nullptr;
LPICON_GROUP_DIR lpIconGroupDir = nullptr;
bool fResult = false;
do
{
//查找资源
if (iconGroupInfo.bIntResource)
{
hResource = ::FindResource(m_hModule, (LPCTSTR)iconGroupInfo.wID, RT_GROUP_ICON);
}
else
{
hResource = ::FindResource(m_hModule, iconGroupInfo.strIDName.c_str(), RT_GROUP_ICON);
}
if (!hResource)
{
break;
}
//加载资源数据
hGlobal = ::LoadResource(m_hModule, hResource);
if (!hGlobal)
{
break;
}
//检索指向内存中指定资源的指针
lpIconGroupDir = (LPICON_GROUP_DIR)::LockResource(hGlobal);
if (!lpIconGroupDir)
{
break;
}
//检查数据大小
DWORD dwIconDirSize = sizeof(ICON_GROUP_HEADER) + ((lpIconGroupDir->Header.ResCount) * sizeof(ICON_ENTRY));
if (dwIconDirSize != ::SizeofResource(m_hModule, hResource))
{
break;
}
fResult = true;
} while (false);
if (!fResult)
{
lpIconGroupDir = nullptr;
}
return lpIconGroupDir;
}
bool CResourceExtractor::WriteGroupIconToFile(HMODULE hModule, LPICON_GROUP_DIR lpIconGroupDir, const _tstring& strOutFile)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwNumberOfBytesWritten = 0;
bool fWriteResult = true;
bool fResult = false;
hFile = ::CreateFile(strOutFile.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (INVALID_HANDLE_VALUE == hFile)
{
return false;
}
do
{
//写入文件头
::WriteFile(hFile, &lpIconGroupDir->Header, sizeof(ICON_GROUP_HEADER), &dwNumberOfBytesWritten, nullptr);
if (sizeof(ICON_GROUP_HEADER) != dwNumberOfBytesWritten)
{
break;
}
//写入图标头信息
DWORD dwOffset = sizeof(ICON_GROUP_HEADER) + (lpIconGroupDir->Header.ResCount * sizeof(ICON_FILE_ENTRY));
fWriteResult = true;
for (int i = 0; i < lpIconGroupDir->Header.ResCount; i++)
{
ICON_FILE_ENTRY iconFileEntry = { 0 };
memcpy_s(&iconFileEntry, sizeof(ICON_ENTRY), &lpIconGroupDir->IconEntry[i], sizeof(ICON_ENTRY));
iconFileEntry.Offset = dwOffset;
//写入单个图标信息
::WriteFile(hFile, &iconFileEntry, sizeof(ICON_FILE_ENTRY), &dwNumberOfBytesWritten, nullptr);
if (sizeof(ICON_FILE_ENTRY) != dwNumberOfBytesWritten)
{
fWriteResult = false;
break;
}
dwOffset += lpIconGroupDir->IconEntry[i].BytesInRes;
}
if (!fWriteResult)
{
break;
}
//写入数据
for (int i = 0; i < lpIconGroupDir->Header.ResCount; i++)
{
HRSRC hIcoResource = nullptr;
HGLOBAL hIcoGlobal = nullptr;
LPBYTE lpIconData = nullptr;
fWriteResult = false;
//查找资源
hIcoResource = ::FindResource(hModule, MAKEINTRESOURCE(lpIconGroupDir->IconEntry[i].IconId), RT_ICON);
if (!hIcoResource)
{
break;
}
//检查数据大小
if (lpIconGroupDir->IconEntry[i].BytesInRes != ::SizeofResource(hModule, hIcoResource))
{
break;
}
//加载资源数据
hIcoGlobal = ::LoadResource(hModule, hIcoResource);
if (!hIcoGlobal)
{
break;
}
//锁定数据
lpIconData = (LPBYTE)::LockResource(hIcoGlobal);
if (!lpIconData)
{
break;
}
//写入图标数据
::WriteFile(hFile, lpIconData, lpIconGroupDir->IconEntry[i].BytesInRes, &dwNumberOfBytesWritten, nullptr);
if (dwNumberOfBytesWritten != lpIconGroupDir->IconEntry[i].BytesInRes)
{
break;
}
fWriteResult = true;
}
if (!fWriteResult)
{
break;
}
fResult = true;
} while (false);
if (INVALID_HANDLE_VALUE != hFile)
{
::CloseHandle(hFile);
}
return fResult;
}
bool CResourceExtractor::WriteIconToFile(HMODULE hModule, LPICON_GROUP_DIR lpIconGroupDir, WORD wID, const _tstring& strOutFile)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwNumberOfBytesWritten = 0;
bool fWriteResult = true;
bool fResult = false;
if (!lpIconGroupDir)
{
return false;
}
hFile = ::CreateFile(strOutFile.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (INVALID_HANDLE_VALUE == hFile)
{
return false;
}
do
{
//写入文件头
ICON_GROUP_HEADER iconGroupHeader = lpIconGroupDir->Header;
iconGroupHeader.ResCount = 1;
::WriteFile(hFile, &iconGroupHeader, sizeof(ICON_GROUP_HEADER), &dwNumberOfBytesWritten, nullptr);
if (sizeof(ICON_GROUP_HEADER) != dwNumberOfBytesWritten)
{
break;
}
//写入图标头信息
DWORD dwOffset = sizeof(ICON_GROUP_HEADER) + (iconGroupHeader.ResCount * sizeof(ICON_FILE_ENTRY));
fWriteResult = false;
for (int i = 0; i < lpIconGroupDir->Header.ResCount; i++)
{
if (wID != lpIconGroupDir->IconEntry[i].IconId)
{
continue;
}
ICON_FILE_ENTRY iconFileEntry = { 0 };
memcpy_s(&iconFileEntry, sizeof(ICON_ENTRY), &lpIconGroupDir->IconEntry[i], sizeof(ICON_ENTRY));
iconFileEntry.Offset = dwOffset;
//写入单个图标信息
::WriteFile(hFile, &iconFileEntry, sizeof(ICON_FILE_ENTRY), &dwNumberOfBytesWritten, nullptr);
if (sizeof(ICON_FILE_ENTRY) != dwNumberOfBytesWritten)
{
break;
}
fWriteResult = true;
}
if (!fWriteResult)
{
break;
}
//写入数据
fWriteResult = false;
for (int i = 0; i < lpIconGroupDir->Header.ResCount; i++)
{
if (wID != lpIconGroupDir->IconEntry[i].IconId)
{
continue;
}
HRSRC hIcoResource = nullptr;
HGLOBAL hIcoGlobal = nullptr;
LPBYTE lpIconData = nullptr;
//查找资源
hIcoResource = ::FindResource(hModule, MAKEINTRESOURCE(lpIconGroupDir->IconEntry[i].IconId), RT_ICON);
if (!hIcoResource)
{
break;
}
//检查数据大小
if (lpIconGroupDir->IconEntry[i].BytesInRes != ::SizeofResource(hModule, hIcoResource))
{
break;
}
//加载资源数据
hIcoGlobal = ::LoadResource(hModule, hIcoResource);
if (!hIcoGlobal)
{
break;
}
//锁定数据
lpIconData = (LPBYTE)::LockResource(hIcoGlobal);
if (!lpIconData)
{
break;
}
//写入图标数据
::WriteFile(hFile, lpIconData, lpIconGroupDir->IconEntry[i].BytesInRes, &dwNumberOfBytesWritten, nullptr);
if (dwNumberOfBytesWritten != lpIconGroupDir->IconEntry[i].BytesInRes)
{
break;
}
fWriteResult = true;
}
if (!fWriteResult)
{
break;
}
fResult = true;
} while (false);
if (INVALID_HANDLE_VALUE != hFile)
{
::CloseHandle(hFile);
}
return fResult;
}
main.cpp
#include
#include "CResourceExtractor.h"
#include
int main()
{
CResourceExtractor obj;
obj.Load(_T(R"(wps.exe)"));
std::vector vInfos = obj.GetGroupIconInfos();
obj.ExtractGroupIconToFile(0, _T("2.ico"));
obj.ExtractIconToFile(0, 0, _T("wps_0.ico"));
obj.ExtractIconToFile(0, 1, _T("wps_1.ico"));
obj.ExtractIconToFile(0, 2, _T("wps_2.ico"));
obj.ExtractIconToFile(0, 3, _T("wps_3.ico"));
obj.ExtractIconToFile(0, 4, _T("wps_4.ico"));
obj.ExtractIconToFile(0, 5, _T("wps_5.ico"));
obj.ExtractIconToFile(0, 6, _T("wps_6.ico"));
obj.ExtractIconToFile(0, 7, _T("wps_7.ico"));
obj.ExtractIconToFile(0, 8, _T("wps_8.ico"));
obj.ExtractIconToFile(0, 9, _T("wps_9.ico"));
obj.ExtractIconToFile(0, 10, _T("wps_10.ico"));
return 0;
}