写应用程序,如果想使用Windows下的图标,可以使用Visual Studio中的图标,比如VS2008的 ImageLibrary(笔者已经打包上传到CSDN),也可以使用Windows系统自带的图标。

Windows系统自带了不少高质量的图标资源,只需要将其提取出来即可使用。

在Windows 95到Windows 10 1903之前的版本,都可以直接在dll中提取系统图标,比如最常用的图标都在shell32.dll中。

一、使用IconsExtract提取

可以使用 IconsExtract,它是 nirsoft开发的软件,该公司开发了许多工具软件,可以去官网查看, http://launcher.nirsoft.net/utilities_list.html有一个列表。

下图是Win10下使用IconsExtract列出的shell32.dll中的图标:

如果想要提取(导出)图标,选中要导出的图标,可以多选,在右键弹出菜单中选择“Save Selected Icons”。

二、使用ResourceHacker提取

ResourceHacker也可以提取图标,它的功能强大之处在于可以替换资源和编译资源。对于提取图标,但它一次只能提取一个图标,如果要提取大量图标,很繁琐。同时它只能操作dll文件本身嵌入的资源,对Win10 1903及之后版本中的shell32.dll查看不了图标资源。

三、使用7zip解压缩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桌面程序读取并显示图标。

  1#include <map>
  2#include <vector>
  3
  4std::map<HICON,int> mapIcon;
  5std::vector<HICON> vctIcon;
  6HMODULE hShell32;
  7
  8void DebugError(DWORD errorCode)
  9{
 10    LPVOID lpMsgBuf;
 11    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
 12                NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 13                (LPTSTR)&lpMsgBuf, 0, NULL);
 14    OutputDebugString((LPTSTR)lpMsgBuf);
 15    LocalFree(lpMsgBuf);
 16}
 17
 18int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
 19                     _In_opt_ HINSTANCE hPrevInstance,
 20                     _In_ LPWSTR    lpCmdLine,
 21                     _In_ int       nCmdShow)
 22{
 23    UNREFERENCED_PARAMETER(hPrevInstance);
 24    UNREFERENCED_PARAMETER(lpCmdLine);
 25
 26    // TODO: 在此处放置代码。
 27    DWORD errorCode = 0;
 28    HMODULE hShell32 = LoadLibrary(_T("shell32.dll"));
 29    if (hShell32 == nullptr)
 30    {
 31        errorCode = GetLastError();
 32        DebugError(errorCode);
 33        return FALSE;
 34    }
 35    // 由于资源号达到80000+,所以取100000
 36    for (int i = 1; i < 100000; ++i)
 37    {
 38        HICON hIcon = (HICON)LoadImage(hShell32, MAKEINTRESOURCE(i), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
 39        if (hIcon != nullptr)
 40        {
 41          mapIcon[hIcon] = i;
 42          vctIcon.push_back(hIcon);
 43        }
 44    }
 45
 46    // 初始化全局字符串
 47    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
 48    LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
 49    MyRegisterClass(hInstance);
 50
 51    // 执行应用程序初始化:
 52    if (!InitInstance (hInstance, SW_SHOWMAXIMIZED))
 53    {
 54        FreeLibrary(hShell32);
 55        return FALSE;
 56    }
 57
 58    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
 59
 60    MSG msg;
 61
 62    // 主消息循环:
 63    while (GetMessage(&msg, nullptr, 0, 0))
 64    {
 65        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
 66        {
 67            TranslateMessage(&msg);
 68            DispatchMessage(&msg);
 69        }
 70    }
 71
 72    return (int) msg.wParam;
 73}
 74
 75void draw(HDC hdc)
 76{
 77   TCHAR buf[16];
 78   int x = 0, y = 0;
 79   DWORD maxY = 0;
 80   ICONINFOEX info;
 81   info.cbSize = sizeof(info);
 82   for (int i = 0; i < vctIcon.size(); ++i)
 83   {
 84      if (GetIconInfoEx(vctIcon[i], &info))
 85      {
 86            if (!info.fIcon)
 87              continue;
 88
 89            DrawIcon(hdc, x, y, vctIcon[i]);
 90            int n = _stprintf_s(buf, ARRAYSIZE(buf), _T("%d"), mapIcon[vctIcon[i]]);
 91            TextOut(hdc, x, y + info.yHotspot * 2 + 2, buf, n);
 92            x += info.xHotspot * 3 + 2;
 93            if (info.yHotspot > maxY)
 94              maxY = info.yHotspot;
 95            if (x >= 1900) {
 96              y += maxY * 3 + 4;
 97              x = 0;
 98            }
 99      }
100   }
101}
102
103LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
104{
105    switch (message)
106    {
107    case WM_COMMAND:
108        {
109            int wmId = LOWORD(wParam);
110            // 分析菜单选择:
111            switch (wmId)
112            {
113            case IDM_ABOUT:
114                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
115                break;
116            case IDM_EXIT:
117                DestroyWindow(hWnd);
118                break;
119            default:
120                return DefWindowProc(hWnd, message, wParam, lParam);
121            }
122        }
123        break;
124    case WM_PAINT:
125        {
126            PAINTSTRUCT ps;
127            HDC hdc = BeginPaint(hWnd, &ps);
128            // TODO: 在此处添加使用 hdc 的任何绘图代码...
129            draw(hdc);            
130            EndPaint(hWnd, &ps);
131        }
132        break;
133    case WM_DESTROY:
134        for (int i = 0; i < vctIcon.size(); ++i)
135        {
136            DestroyIcon(vctIcon[i]);
137        }
138        FreeLibrary(hShell32);
139        PostQuitMessage(0);
140        break;
141    default:
142        return DefWindowProc(hWnd, message, wParam, lParam);
143    }
144    return 0;
145}

执行结果: