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_CURSORWORD ResCount;                  //资源组中的图标或游标组件数
} ICON_GROUP_HEADER, * LPICON_GROUP_HEADER;typedef struct
{BYTE Width;                     //图标的宽度(以像素为单位)。 可接受的值为 16、32 和 64BYTE Height;                    //图标的高度(以像素为单位)。 可接受的值为 16、32 和 64BYTE 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 和 64BYTE Height;                    //图标的高度(以像素为单位)。 可接受的值为 16、32 和 64BYTE ColorCount;                //图标中的颜色数。 可接受的值为 2、8 和 16BYTE 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 和 16BYTE 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];          //数据块类型, 应该为IHDRIHDR 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, 否则为字符串资源IDstd::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

 

 

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

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

相关文章

[设计模式Java实现附plantuml源码~结构型]树形结构的处理——组合模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

网络会话管理

文章目录 一 什么是会话1 生活中会话2 Web中会话3 会话技术 二 Cookie1 原理2 使用2.1 添加cookie2.2 遍历cookie2.3 设置cookie的过期时间 3 特点 三 Session1 原理2 使用2.1 创建session对象2.2 不同的servlet间共享session对象中数据2.3 web.xml中设置session的超时时间 3 禁…

Keil软件某些汉字输出乱码,0xFD问题,51单片机

1. 问题 keil软件输入某些汉字的时候会输出乱码&#xff0c;例如&#xff1a;升、 数 2. 原因 keil软件会忽略0xFD。 升的GB2312编码为 0xc9fd&#xff0c;keil解析为0xc9数的GB2312编码为 0xcafd&#xff0c;keil解析为0xca 关于Keil软件中0xFD问题的说明 3. 解决方案1 …

E5071C 是德科技网络分析仪

181/2461/8938产品概述&#xff1a; E5071C ENA 矢量网络分析仪&#xff0c;9 kHz 至 20 GHz&#xff0c;配有增强型 TDR 测量选件。 E5071C 是大规模无源元器件测试的理想解决方案。 它具有出色的测量性能&#xff0c;有助于提高测试吞吐量&#xff0c;尤其是与 E5092A 多端…

力扣题目训练(3)

2024年1月27日力扣题目训练 2024年1月27日力扣题目训练290. 单词规律292. Nim 游戏303. 区域和检索 - 数组不可变91. 解码方法92. 反转链表 II41. 缺失的第一个正数 2024年1月27日力扣题目训练 2024年1月27日第三天编程训练&#xff0c;今天主要是进行一些题训练&#xff0c;包…

SQL注入:盲注

SQL注入系列文章&#xff1a; 初识SQL注入-CSDN博客 SQL注入&#xff1a;联合查询的三个绕过技巧-CSDN博客 SQL注入&#xff1a;报错注入-CSDN博客 目录 什么是盲注&#xff1f; 布尔盲注 手工注入 使用python脚本 使用sqlmap 时间盲注 手工注入 使用python脚本 使…

聊聊鸿蒙HarmonyOS NEXT 的技术细节

上周&#xff0c;华为在深圳举办了“鸿蒙生态千帆启航仪式”&#xff0c;这也是华为鸿蒙开启生态进阶的信号。在政策的叠加下&#xff0c;鸿蒙未来必定是势不可挡的。我们这些程序员也得与时俱进&#xff0c;熟悉鸿蒙的技术和细节&#xff0c;别在经济寒冬里被淘汰了。 官方称…

scrapy框架核心知识Spider,Middleware,Item Pipeline,scrapy项目创建与启动,Scrapy-redis与分布式

scrapy项目创建与启动 创建项目 在你的工作目录下直接使用命令: scrapy startproject scrapytutorial运行后创建了一个名为scrapytutorial的爬虫工程 创建spider 在爬虫工程文件内&#xff0c;运行以下命令&#xff1a; scrapy genspider quotes创建了名为quotes的爬虫 …

【分治专题】详解快排类型4道题

本文讲解分治下的快排类型的4道题&#xff0c;在讲解题目的同时提供AC代码&#xff0c;点击题目即可打开对应链接 目录 1、颜色分类 2、排序数组 3、数组中的第K个最大元素 4、库存管理 III 1、颜色分类 解法&#xff08;快排思想--三指针法使数组分三块&#xff09;&…

专业建设数字平台

专业建设数字平台&#xff0c;遵循以学生发展为中心、以产出为导向的OBE理念&#xff0c;大数据赋能人才培养全过程管理&#xff0c;支撑专业数字化建设与专业认证等专项工作&#xff0c;平台围绕学院与专业建设中人才培养方案制定的顶层设计工作及全流程、全场景业务&#xff…

ARM常用汇编指令

文章目录 前言一、处理器内部数据传输指令MOV&#xff1a; 将数据从一个寄存器复制到另一个寄存器。MRS&#xff1a; 将特殊寄存器(CPSR,SPSR)中的数据传给通用寄存器。MSR&#xff1a; 将通用寄存器中的数据传给特殊寄存器(CPSR,SPSR)。 二、存储器访问指令LDR:用于从内存中加…

力扣面试题 16.06. 最小差

Problem: 面试题 16.06. 最小差 文章目录 题目描述思路即解法复杂度Code 题目描述 思路即解法 注意本题目的数据范围!!! 1.对数组a与数组b进行排序;获取a与b的数组长度aLen,bLen&#xff0c;定义一个long类型的变量min&#xff1b; 2.分别让两个指针i&#xff0c;j指向数组的开…

56. 合并区间 - 力扣(LeetCode)

题目描述 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 题目示例 输入&#xff1a;intervals [[1,3…

LeNet跟LeNet5详解

1 LeNet结构 主要是为了手写数字识别 具体结构讲解&#xff1a;从图中例子可得 1 先传入一个灰度图像尺寸为1x28x28&#xff0c;通道数为1&#xff0c;尺寸为28x28的灰度图像 2 第一层5x5卷积&#xff0c;经过公式 输入图像尺寸-卷积核尺寸2padding/步长1&#xff0c;&#…

༺༽༾ཊ—设计-抽象-05-工厂-模式—ཏ༿༼༻

名称&#xff1a;抽象工厂 类型&#xff1a;创建型 目的&#xff1a;当有多个抽象角色时使用的一种工厂模式。 抽象工厂模式可以向客户端提供一个接口&#xff0c;使 客户端在不必指定产品的具体情况下&#xff0c;创建多个产品族中的产品对象。 优点&#xf…

Linux第38步_编译“正点原子移植好的uboot”

uboot的全称是Universal Boot Loader&#xff0c;uboot是一个遵循GPL协议的开源软件&#xff0c;uboot是一个裸机代码&#xff0c;可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB等高级功能。 uboot官方的uboot源码是给所有的半导体厂商准备的。ST公司会…

v38.恒星金字塔

1.循环嵌套 1.1矩阵&#xff08;i&#xff0c;j&#xff09; i行 j列 将矩阵与循环嵌套结合起来: 2.2.于是&#xff0c;金字塔就是

基于QC-LDPC编码的循环移位网络的FPGA实现

一、桶式移位寄存器(barrel shifter) 八位桶式移位寄存器的VHDL实现如下&#xff0c;由于每一层结构相似&#xff0c;于是采用生成语句for_generate实现&#xff0c;使用该代码实现的RTL级分析和理论的结构一致&#xff0c;仿真结果也符合预期。 entity barrel_shift isGENE…

从关键新闻和最新技术看AI行业发展(2024.1.15-1.28第十五期) |【WeThinkIn老实人报】

Rocky Ding 公众号&#xff1a;WeThinkIn 写在前面 【WeThinkIn老实人报】旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的优化建议&#xff0c;一起交流学习&…

GEE数据集——MOD13A1.006Terra星搭载的中分辨率成像光谱仪获取的L3级植被指数产品

数据名称&#xff1a; MOD13A1.006 Modis 16天 Terra 500m 数据来源&#xff1a; NASA 时空范围&#xff1a; 2000-2022年 空间范围&#xff1a; 全国 波段 名称波段单位最小值最大值比例因子波长描述NDVIB1NDVI-2000100000.0001Normalized Difference Vegetation…