C++提取ICO图标(PE文件资源提取)

最近需要写一个提取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 <wtypesbase.h>
#include <windows.h>
#include <string>
#include <vector>

#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<ICON_INFO> 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<ICON_GROUP_INFO>      图标信息列表
    std::vector<ICON_GROUP_INFO> 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<ICON_INFO> GetIconGroupInfo(HMODULE hModule, LPCTSTR lpIdName);
    static bool IsPngSignature(LPVOID lpData);

private:

    HMODULE m_hModule;                          //PE模块句柄
    std::vector<ICON_GROUP_INFO> 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<ICON_GROUP_INFO>* pInfos = reinterpret_cast<std::vector<ICON_GROUP_INFO>*>(lParam);
            ICON_GROUP_INFO info;
            info.bIntResource = IS_INTRESOURCE(lpName);

            if (info.bIntResource)
            {
                info.wID = reinterpret_cast<WORD>(lpName);
            }
            else
            {
                info.strIDName = lpName;
            }

            info.Icons = GetIconGroupInfo(hModule, lpName);
            pInfos->push_back(info);

            return TRUE;
        }, reinterpret_cast<LONG_PTR>(&m_listIcons));

    return true;
}

std::vector<ICON_INFO> CResourceExtractor::GetIconGroupInfo(HMODULE hModule, LPCTSTR lpIdName)
{
    std::vector<ICON_INFO> 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<ICON_GROUP_INFO> 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 <iostream>
#include "CResourceExtractor.h"
#include <tchar.h>

int main()
{
    CResourceExtractor obj;
    obj.Load(_T(R"(wps.exe)"));
    std::vector<ICON_GROUP_INFO> 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;
}

24f95ce5eb7a49a5a766b5e7695eba67.png

 a688c0eae0304cdaa3df1990d104d4e0.png

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/360590.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git远程仓库基本操作

目录 gitremote &#xff08;查看远程仓库&#xff09; git remote add [仓库名] [url] git clone [url]&#xff08;克隆远程仓库到本地&#xff09; git push [名][分支名]&#xff08;提交到远程仓库&#xff09;​编辑 git pull [名][分支名]从远程仓库拉取​编辑 注意操作…

opencv学习 特征提取

内容来源于《opencv4应用开发入门、进阶与工程化实践》 图像金字塔 略 拉普拉斯金字塔 对输入图像进行reduce操作会生成不同分辨率的图像&#xff0c;对这些图像进行expand操作&#xff0c;然后使用reduce减去expand之后的结果&#xff0c;就会得到拉普拉斯金字塔图像。 …

Java 代理详解

Java 代理详解 文章目录 Java 代理详解1. 代理模式2. 静态代理3. 动态代理3.1. JDK 动态代理机制3.1.1. 介绍3.1.2. JDK 动态代理类使用步骤3.1.3. 代码示例 3.2. CGLIB 动态代理机制3.2.1. 介绍3.2.2. CGLIB 动态代理类使用步骤3.2.3. 代码示例 3.3. JDK 动态代理和 CGLIB 动态…

SD-WAN和专线混合组网:企业出海网络解决方案

目前&#xff0c;有很多国内企业涉足海外业务&#xff0c;如跨境电商、游戏、社交网络、区块链等。都会使用海外服务器。同时&#xff0c;这些企业在国内还有自己的机房&#xff0c;IDC或者使用国内其他云厂商的机房。如果他们想要相互通信或传输数据该怎么办&#xff1f;在成本…

最小步数模型

AcWing 1107. 魔板 #include <bits/stdc.h> using namespace std;char g[2][4]; const int N 10; unordered_map<string, pair<char, string> > pre; unordered_map<string, int> d;void Set(string s) {for(int i0; i<4; i) g[0][i] s[i];for(in…

骨传导如何使用,跟传统耳机有什么不同吗?

骨传导耳机的使用方法跟传统耳机是一样的&#xff0c;都是通过蓝牙连接来使用&#xff0c;不同的是&#xff0c;有些骨传导耳机自带内存&#xff0c;可以当做MP3来使用&#xff01; 此外&#xff0c;骨传导耳机的佩戴方式和传声方式跟传统耳机也有所不同&#xff0c;首先骨传导…

2024年美赛赛前复习大纲

CC数模-优质解答 引言 数学建模是一个将数学理论和方法应用于解决现实世界问题的过程。在数学建模比赛中&#xff0c;学生需要运用自己的数学知识和技能&#xff0c;解决给定的复杂问题。这不仅是一次展示自己能力的机会&#xff0c;也是一次学习和成长的过程。随着比赛的临近…

网络安全03---Nginx 解析漏洞复现

目录 一、准备环境 二、实验开始 2.1上传压缩包并解压 2.2进入目录&#xff0c;开始制作镜像 2.3可能会受之前环境影响&#xff0c;删除即可 ​编辑 2.4制作成功结果 2.5我们的环境一个nginx一个php 2.6访问漏洞 2.7漏洞触发结果 2.8上传代码不存在漏洞 2.9补充&#…

elementUI中表单校验的清空校验以及手动校验

this.$refs.表单.clearValidate(),这个可以传入字符串或者字符串数组&#xff0c;字符串对应的是我们自定义的rule里面的属性名&#xff0c;rule的属性名对应的是el-form-item的prop。这个api目前遇到的场景是el-radio切换时v-if展示不同的表单内容&#xff0c;但是当有校验提示…

力扣931. 下降路径最小和

动态规划 思路&#xff1a; 假设 dp[i][j] 为坐标 (i, j) 的路径最小和&#xff1b;则 dp[i][j] 上一状态&#xff1a; dp[i - 1][j] &#xff08;上一行正上方&#xff09;dp[i - 1][j - 1]&#xff08;上一行的左侧&#xff09;dp[i - 1][j 1]&#xff08;上一行的右侧&…

9.SELinux

目录 1. 概述 1.1. 概念 1.2. 作用&#xff1a; 1.3. SELinux与传统的权限区别 2. SELinux工作原理 2.1. 名词解释 2.1.1. 主体&#xff08;Subject&#xff09; 2.1.2. 目标&#xff08;Object&#xff09; 2.1.3. 策略&#xff08;Policy&#xff09; 2.1.4. 安全上…

纯静态微信小程序水果商城

首页代码 <view class"container"><!-- 轮播图 --><view class"swiper-container"><swiper class"screen-swiper" indicator-dots"true" circular"true" autoplay"true" interval"300…

穷游网酒店数据采集与可视化分析与实现

摘 要 穷游网酒店数据采集与可视化分析大屏的背景是为了满足用户对酒店数据的需求以及提供数据洞察和决策支持。随着旅游业的快速发展&#xff0c;人们对酒店信息的需求日益增加&#xff0c;而穷游网作为一家专注于旅游信息的网站&#xff0c;拥有丰富的酒店数据资源。 这个大…

计算机缺失duilib.dll的5种解决方法,轻松解决dll报错问题

计算机系统中丢失duilib.dll这个特定的动态链接库文件可能会引发一系列运行问题&#xff0c;具体表现和影响范围会根据该dll文件在系统或应用程序中的功能角色而有所不同。通常情况下&#xff0c;duilib.dll是一个与用户界面设计和渲染相关的库文件&#xff0c;它的缺失可能导致…

openGaussdb5.0单点企业版部署_KylinV10SP1

本文档环境&#xff1a;Kylin-Server-10-SP1 python2.7.16 交互式初始化环境方式 介绍 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内核深度融合华为在数据库领域多年的经验&#xff0c;结合企业级场景需求&#xff0c;持续构建…

MySQL 数据库表的增删改查(进阶版)

目录 1 数据库约束1.1 NOT NULL 约束1.2 UNIQUE 约束1.3 DEFAULT 约束1.4 PRIMARY KEY 约束1.5 FOREIGN KEY 约束1.6 CHECK 约束 2 表的关系2.1 三大范式2.2 表的设计2.2.1 一对一 (1:1)2.2.2 一对多 (1:n)2.2.3 多对多 (m:n) 3 进阶版CRUD操作3.1 新增(Create)3.2 查询(Retrie…

科技感十足的Pencil平替,功能全面手感丝滑,西圣Pencil 2上手

搭配Apple Pencil的iPad的确实可以大大提升工作效率&#xff0c;但是原厂的Apple Pencil价格实在偏高&#xff0c;而且容易遗失&#xff0c;所以很多人都会选择一些Apple Pencil的平替。最近我在用一款西圣Pencil 2&#xff0c;这款电容笔设计很有特点&#xff0c;看起来科技感…

《【Python】如何设置现代 Python 日志记录 | Python 基础教程 | Python 冷知识 | 十分钟高手系列》学习笔记

《【Python】如何设置现代 Python 日志记录 | Python 基础》 2 PUT ALL HANDLERS/FILTERS ON THE ROOT&#xff1a;扁平化的设计有助于简化维护成本 5 STORE CONFIG IN JSON OR YAML FILE&#xff1a;使用配置文件可以将配置和代码解耦&#xff0c;减少代码量 日志设置示例 7 …

LLM面面观之RLHF平替算法DPO

1. 背景 最近本qiang~老看到一些关于大语言模型的DPO、RLHF算法&#xff0c;但都有些云里雾里&#xff0c;因此静下心来收集资料、研读论文&#xff0c;并执行了下开源代码&#xff0c;以便加深印象。 此文是本qiang~针对大语言模型的DPO算法的整理&#xff0c;包括原理、流程…

python使用Schedule

目录 一&#xff1a;使用场景&#xff1a; 二&#xff1a;参数 三&#xff1a;实例 "Schedule"在Python中通常指的是时间调度或任务计划。Python中有多个库可以用来处理时间调度和任务计划&#xff0c;其中最流行的是schedule库。 一&#x…