写应用程序,如果想使用Windows下的图标,可以使用Visual Studio中的图标,比如VS2008的ImageLibrary(笔者已经打包上传到CSDN),也可以使用Windows系统自带的图标。
Windows系统自带了不少高质量的图标资源,只需要将其提取出来即可使用。
在Windows 95到Windows 10 1903之前的版本,都可以直接在dll中提取系统图标,比如最常用的图标都在shell32.dll中。
可以使用IconsExtract,它是nirsoft开发的软件,该公司开发了许多工具软件,可以去官网查看,http://launcher.nirsoft.net/utilities_list.html有一个列表。
下图是Win10下使用IconsExtract
列出的shell32.dll中的图标:
如果想要提取(导出)图标,选中要导出的图标,可以多选,在右键弹出菜单中选择“Save Selected Icons”。
ResourceHacker也可以提取图标,它的功能强大之处在于可以替换资源和编译资源。对于提取图标,但它一次只能提取一个图标,如果要提取大量图标,很繁琐。同时它只能操作dll文件本身嵌入的资源,对Win10 1903及之后版本中的shell32.dll查看不了图标资源。
其实,Windows下不管是EXE文件,还是DLL文件它都是一个ZIP压缩文件,都可以使用ZIP解压缩来查看内容。比如使用7zip来查看ResourceHacker.exe中的内容:
查看shell32.dll的内容:
其中的.rsrc
就是内嵌的资源文件所在目录。ICON图标文件就在其中:
但是在Win10 1903及之后版本,shell32.dll中并不包括图标资源了,它被分离到了C:\Windows\SystemResources\
下的同名mun文件中,即shell32.dll.mun
中
所以直接解压shell32.dll是无法提取图标文件的,需要使用7zip解压C:\Windows\SystemResources\shell32.dll.mun
下图是解压出来的文件:
使用VC++创建Windows桌面程序读取并显示图标。
#include
#include
std::map<HICON,int> mapIcon;
std::vector<HICON> vctIcon;
HMODULE hShell32;
void DebugError(DWORD errorCode)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
OutputDebugString((LPTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此处放置代码。
DWORD errorCode = 0;
HMODULE hShell32 = LoadLibrary(_T("shell32.dll"));
if (hShell32 == nullptr)
{
errorCode = GetLastError();
DebugError(errorCode);
return FALSE;
}
// 由于资源号达到80000+,所以取100000
for (int i = 1; i < 100000; ++i)
{
HICON hIcon = (HICON)LoadImage(hShell32, MAKEINTRESOURCE(i), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
if (hIcon != nullptr)
{
mapIcon[hIcon] = i;
vctIcon.push_back(hIcon);
}
}
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, SW_SHOWMAXIMIZED))
{
FreeLibrary(hShell32);
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
MSG msg;
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
void draw(HDC hdc)
{
TCHAR buf[16];
int x = 0, y = 0;
DWORD maxY = 0;
ICONINFOEX info;
info.cbSize = sizeof(info);
for (int i = 0; i < vctIcon.size(); ++i)
{
if (GetIconInfoEx(vctIcon[i], &info))
{
if (!info.fIcon)
continue;
DrawIcon(hdc, x, y, vctIcon[i]);
int n = _stprintf_s(buf, ARRAYSIZE(buf), _T("%d"), mapIcon[vctIcon[i]]);
TextOut(hdc, x, y + info.yHotspot * 2 + 2, buf, n);
x += info.xHotspot * 3 + 2;
if (info.yHotspot > maxY)
maxY = info.yHotspot;
if (x >= 1900) {
y += maxY * 3 + 4;
x = 0;
}
}
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
draw(hdc);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
for (int i = 0; i < vctIcon.size(); ++i)
{
DestroyIcon(vctIcon[i]);
}
FreeLibrary(hShell32);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
执行结果: