-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsystemicon.go
More file actions
110 lines (98 loc) · 2.59 KB
/
Copy pathsystemicon.go
File metadata and controls
110 lines (98 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package main
import (
"path/filepath"
"strings"
"sync"
"syscall"
"unsafe"
)
// ---------------- 系统文件图标(SHGetFileInfo → HICON → PNG data URI) ----------------
// 按扩展名缓存(exe/lnk/ico/dll 按路径缓存),设置 useSystemIcons 关闭时返回空。
var (
procSHGetFileInfoW = syscall.NewLazyDLL("shell32.dll").NewProc("SHGetFileInfoW")
procGetIconInfo = syscall.NewLazyDLL("user32.dll").NewProc("GetIconInfo")
procDestroyIcon = syscall.NewLazyDLL("user32.dll").NewProc("DestroyIcon")
)
type SHFILEINFOW struct {
HIcon uintptr
IIcon int32
DwAttributes uint32
SzDisplayName [260]uint16
SzTypeName [80]uint16
}
type ICONINFO struct {
FIcon uint32
XHotspot uint32
YHotspot uint32
HbmMask uintptr
HbmColor uintptr
}
const (
shgfiIcon = 0x00000100
shgfiSmallIcon = 0x00000001
shgfiUseFileAttrs = 0x00000010
fileAttrDirectory = 0x00000010
fileAttrNormal = 0x00000080
)
var (
iconCacheMu sync.Mutex
iconCache = map[string]string{}
)
// sysIconsEnabled 由 startup/UpdateSettings 维护(避免频繁读文件)
var sysIconsEnabled = true
// getSystemIcon 返回路径的系统图标(PNG data URI),空串表示无图标
func getSystemIcon(path string, isDir bool) string {
if !sysIconsEnabled {
return ""
}
key := "dir"
if !isDir {
ext := strings.ToLower(filepath.Ext(path))
switch ext {
case ".exe", ".lnk", ".ico", ".cur", ".dll":
key = path // 图标因文件而异,按路径缓存
default:
key = ext
}
}
iconCacheMu.Lock()
if v, ok := iconCache[key]; ok {
iconCacheMu.Unlock()
return v
}
iconCacheMu.Unlock()
uri := extractSystemIcon(path, isDir)
iconCacheMu.Lock()
iconCache[key] = uri
iconCacheMu.Unlock()
return uri
}
// extractSystemIcon 用 SHGetFileInfoW 提取 16x16 图标并转 PNG data URI
func extractSystemIcon(path string, isDir bool) string {
p, _ := syscall.UTF16PtrFromString(path)
var sfi SHFILEINFOW
attrs := uintptr(fileAttrNormal)
if isDir {
attrs = fileAttrDirectory
}
r, _, _ := procSHGetFileInfoW.Call(
uintptr(unsafe.Pointer(p)), attrs, uintptr(unsafe.Pointer(&sfi)),
uintptr(unsafe.Sizeof(sfi)), shgfiIcon|shgfiSmallIcon|shgfiUseFileAttrs)
if r == 0 || sfi.HIcon == 0 {
return ""
}
defer procDestroyIcon.Call(sfi.HIcon)
var ii ICONINFO
rr, _, _ := procGetIconInfo.Call(sfi.HIcon, uintptr(unsafe.Pointer(&ii)))
if rr == 0 {
return ""
}
if ii.HbmMask != 0 {
shellDeleteObject.Call(ii.HbmMask)
}
if ii.HbmColor == 0 {
return ""
}
defer shellDeleteObject.Call(ii.HbmColor)
return shellMenuIcon(ii.HbmColor) // 复用 HBITMAP → PNG data URI
}