Win32 PE图标资源提取(ICO图标提取)

news2024/11/15 17:32:26

最近需要写一个提取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;
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot+Netty搭建基于TCP协议的服务端

文章目录 概要pom依赖Netty的server服务端类Netty通道初始化I/O数据读写处理测试发送消息 并 接收服务端回复异步启动Netty运行截图 概要 Netty是业界最流行的nio框架之一&#xff0c;它具有功能强大、性能优异、可定制性和可扩展性的优点 Netty的优点&#xff1a; 1.API使用简…

深度强化学习(王树森)笔记03

深度强化学习&#xff08;DRL&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接&#xff1a;https://github.com/wangshusen/DRL 源代码链接&#xff1a;https://github.c…

分布式id-雪花算法

一、雪花算法介绍 Snowflake&#xff0c;雪花算法是有Twitter开源的分布式ID生成算法&#xff0c;以划分命名空间的方式将64bit位分割成了多个部分&#xff0c;每个部分都有具体的不同含义&#xff0c;在Java中64Bit位的整数是Long类型&#xff0c;所以在Java中Snowflake算法生…

Linux 文件和文件夹的创建与删除

目录 一. 新建1.1 mkdir 新建文件夹1.2 touch 新建空文件1.3 vi命令创建文件1.4 > 和 >> 新建文件 二. 删除 一. 新建 1.1 mkdir 新建文件夹 -p&#xff1a;递归的创建文件夹&#xff0c;当父目录不存在的时候&#xff0c;会自动创建 mkdir -p test1/test2/test31.…

stable-diffusion-webui 汉化(中文界面)

大家好&#xff0c;我是水滴~~ 本文主要介绍 Stable Diffusion WebUI 是如何汉化的&#xff0c;文章详细的介绍汉化过程&#xff0c;并加上配图能够清晰的展示该过程。 Stable Diffusion WebUI 官方并没有出中文界面&#xff0c;需要通过安装插件来汉化&#xff0c;下面是详细…

工业空调转IEC104协议转换网关BE108

随着电力系统信息化建设和数字化转型的进程不断加速&#xff0c;对电力能源的智能化需求也日趋增强。健全稳定的智慧电力系统能够为工业生产、基础设施建设以及国防建设提供稳定的能源支持。在此背景下&#xff0c;高性能的工业电力数据传输解决方案——协议转换网关应运而生&a…

如何免费注册一个二级域名

目录 1.sitelutions账号注册 2.添加域名 3.做A记录或者cname解析步骤 1.sitelutions账号注册 注册网址:Sitelutions - Solutions for your site. All in one place. 打开首页点击右上角的红色 free sign up 来注册。注册只需邮箱即可。 首先填写注册信息,然后提交。提交之后…

Tortoise-tts Better speech synthesis through scaling——TTS论文阅读

笔记地址&#xff1a;https://flowus.cn/share/a79f6286-b48f-42be-8425-2b5d0880c648 【FlowUs 息流】tortoise 论文地址&#xff1a; Better speech synthesis through scaling Abstract: 自回归变换器和DDPM&#xff1a;自回归变换器&#xff08;autoregressive transfo…

算法38:子数组的最小值之和(力扣907题)----单调栈

题目&#xff1a; 给定一个整数数组 arr&#xff0c;找到 min(b) 的总和&#xff0c;其中 b 的范围为 arr 的每个&#xff08;连续&#xff09;子数组。 示例 1&#xff1a; 输入&#xff1a;arr [3,1,2,4] 输出&#xff1a;17 解释&#xff1a; 子数组为 [3]&#xff0c;[…

设计模式:工厂方法模式

工厂模式属于创建型模式&#xff0c;也被称为多态工厂模式&#xff0c;它在创建对象时提供了一种封装机制&#xff0c;将实际创建对象的代码与使用代码分离&#xff0c;有子类决定要实例化的产品是哪一个&#xff0c;把产品的实例化推迟到子类。 使用场景 重复代码 : 创建对象…

机器学习---可能近似正确(PAC)、出错界限框架

1. 计算学习理论概述 从理论上刻画了若干类型的机器学习问题中的困难和若干类型的机器学习算法的能力 这个理论要回答的问题是&#xff1a; 在什么样的条件下成功的学习是可能的&#xff1f; 在什么条件下某个特定的学习算法可保证成功运行&#xff1f; 这里考虑两种框架&…

【开源】基于JAVA+Vue+SpringBoot的固始鹅块销售系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固始鹅块模块2.4 鹅块订单模块2.5 评论管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 鹅块类型表3.2.2 鹅块表3.2.3 鹅块订单表3.2.4 鹅块评论表 四、系统展示五、核心代码5.…

基于C语言的趣味游戏之五子棋

目录 趣味五子棋游戏 第一步 text.c文件 第二步 game.h文件 第三步 初始化 打印棋盘 玩家输入 电脑输入 判断输赢 game.c 趣味五子棋游戏 第一步 先写菜单&#xff0c;然后在主函数里调用&#xff0c;由于这是一个可以重复的游戏所以将do while循环里调用menu函数。…

C/C++ - 类的封装特性

目录 类的封装 语法格式 声明定义 分文件 访问权限 类作用域 对象模型 构造函数 默认构造函数 带参构造函数 拷贝构造函数 构造函数重载 委托构造函数 初始数据列表 构造默认参数 构造函数删除 析构函数 析构函数概念 析构函数特性 析构函数示例 析构调用…

【Unity】【游戏开发】Pico打包后项目出现运行时错误如何Debug

【背景】 开发过程中的报错可以通过控制台查看&#xff0c;但是PICO项目这类依赖特定设备环境的应用往往存在打包后在设备端发生运行时错误。这时如何能查看到Debug信息呢&#xff1f; 【分析】 Pico也是安卓系统&#xff0c;所以这个问题就可以泛化为Unity有哪些在安卓端运…

dnSpy调试工具二次开发2-输出日志到控制台

本文在上一篇文章的基础上继续操作&#xff1a; dnSpy调试工具二次开发1-新增菜单-CSDN博客 经过阅读dnSpy的源码&#xff0c;发现dnSpy使用到的依赖注入用了MEF框架&#xff0c;所以在源码中可以看到接口服务类的上面都打上了Export的特性或在构造方法上面打上ImportingConst…

力扣hot100 最小栈 变种栈

Problem: 155. 最小栈 文章目录 思路&#x1f496; Stack 自定义 Node&#x1f37b; Code 思路 &#x1f469;‍&#x1f3eb; 甜姨 &#x1f496; Stack 自定义 Node 时间复杂度: O ( 1 ) O(1) O(1) 空间复杂度: O ( n ) O(n) O(n) &#x1f37b; Code class MinS…

数据结构-顺序表的实现 [王道]

本博客记录个人寒假学习内容。此篇博客内容为 顺序表的定义。 博客中截图来自王道数据结构公开课 目录 顺序表的定义 顺序表的特点 顺序表的实现--静态分配 顺序表的实现--动态分配 顺序表的定义--知识结构框架 顺序表的定义 >线性表是具有相同(每个数据元素所占的空间…

Spring Boot使用AOP

一、为什么需要面向切面编程&#xff1f; 面向对象编程&#xff08;OOP&#xff09;的好处是显而易见的&#xff0c;缺点也同样明显。当需要为多个不具有继承关系的对象添加一个公共的方法的时候&#xff0c;例如日志记录、性能监控等&#xff0c;如果采用面向对象编程的方法&…

CSS优先级内容

定义CSS样式时&#xff0c;经常出现两个或多个样式规则应用在同一元素的情况&#xff0c;这时就会出现优先级的情况&#xff0c;那么应用的元素应该显示哪一个样式呢&#xff1f; 一.下面举例对优先级进行具体讲解。 p{color:red;} .blue{color:orange;} #header{color:blu…