1 // SysIconUtils.cpp
2
3 #include "StdAfx.h"
4
5 #ifndef _UNICODE
6 #include "../../../Common/StringConvert.h"
7 #endif
8
9 #include "../../../Windows/FileDir.h"
10
11 #include "SysIconUtils.h"
12
13 #if defined(__MINGW32__) || defined(__MINGW64__)
14 #include <shlobj.h>
15 #else
16 #include <ShlObj.h>
17 #endif
18
19 #ifndef _UNICODE
20 extern bool g_IsNT;
21 #endif
22
GetIconIndexForCSIDL(int csidl)23 int GetIconIndexForCSIDL(int csidl)
24 {
25 LPITEMIDLIST pidl = NULL;
26 SHGetSpecialFolderLocation(NULL, csidl, &pidl);
27 if (pidl)
28 {
29 SHFILEINFO shellInfo;
30 shellInfo.iIcon = 0;
31 const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), FILE_ATTRIBUTE_NORMAL,
32 &shellInfo, sizeof(shellInfo),
33 SHGFI_PIDL | SHGFI_SYSICONINDEX);
34 /*
35 IMalloc *pMalloc;
36 SHGetMalloc(&pMalloc);
37 if (pMalloc)
38 {
39 pMalloc->Free(pidl);
40 pMalloc->Release();
41 }
42 */
43 // we use OLE2.dll function here
44 CoTaskMemFree(pidl);
45 if (res)
46 return shellInfo.iIcon;
47 }
48 return 0;
49 }
50
51 #ifndef _UNICODE
52 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
53 typedef DWORD_PTR (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
54
55 static struct C_SHGetFileInfo_Init
56 {
57 Func_SHGetFileInfoW f_SHGetFileInfoW;
C_SHGetFileInfo_InitC_SHGetFileInfo_Init58 C_SHGetFileInfo_Init()
59 {
60 f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS(
61 Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"),
62 "SHGetFileInfoW");
63 }
64 } g_SHGetFileInfo_Init;
65 #endif
66
My_SHGetFileInfoW(LPCWSTR pszPath,DWORD attrib,SHFILEINFOW * psfi,UINT cbFileInfo,UINT uFlags)67 static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)
68 {
69 #ifdef _UNICODE
70 return SHGetFileInfo
71 #else
72 if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW)
73 return 0;
74 return g_SHGetFileInfo_Init.f_SHGetFileInfoW
75 #endif
76 (pszPath, attrib, psfi, cbFileInfo, uFlags);
77 }
78
GetRealIconIndex(CFSTR path,DWORD attrib,int & iconIndex)79 DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex)
80 {
81 #ifndef _UNICODE
82 if (!g_IsNT)
83 {
84 SHFILEINFO shellInfo;
85 const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
86 sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
87 iconIndex = shellInfo.iIcon;
88 return res;
89 }
90 else
91 #endif
92 {
93 SHFILEINFOW shellInfo;
94 const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
95 sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
96 iconIndex = shellInfo.iIcon;
97 return res;
98 }
99 }
100
101 /*
102 DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)
103 {
104 #ifndef _UNICODE
105 if (!g_IsNT)
106 {
107 SHFILEINFO shellInfo;
108 shellInfo.szTypeName[0] = 0;
109 DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
110 sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
111 if (typeName)
112 *typeName = GetUnicodeString(shellInfo.szTypeName);
113 iconIndex = shellInfo.iIcon;
114 return res;
115 }
116 else
117 #endif
118 {
119 SHFILEINFOW shellInfo;
120 shellInfo.szTypeName[0] = 0;
121 DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
122 sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
123 if (typeName)
124 *typeName = shellInfo.szTypeName;
125 iconIndex = shellInfo.iIcon;
126 return res;
127 }
128 }
129 */
130
FindInSorted_Attrib(const CRecordVector<CAttribIconPair> & vect,DWORD attrib,unsigned & insertPos)131 static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &vect, DWORD attrib, unsigned &insertPos)
132 {
133 unsigned left = 0, right = vect.Size();
134 while (left != right)
135 {
136 const unsigned mid = (left + right) / 2;
137 const DWORD midAttrib = vect[mid].Attrib;
138 if (attrib == midAttrib)
139 return (int)mid;
140 if (attrib < midAttrib)
141 right = mid;
142 else
143 left = mid + 1;
144 }
145 insertPos = left;
146 return -1;
147 }
148
FindInSorted_Ext(const CObjectVector<CExtIconPair> & vect,const wchar_t * ext,unsigned & insertPos)149 static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar_t *ext, unsigned &insertPos)
150 {
151 unsigned left = 0, right = vect.Size();
152 while (left != right)
153 {
154 const unsigned mid = (left + right) / 2;
155 const int compare = MyStringCompareNoCase(ext, vect[mid].Ext);
156 if (compare == 0)
157 return (int)mid;
158 if (compare < 0)
159 right = mid;
160 else
161 left = mid + 1;
162 }
163 insertPos = left;
164 return -1;
165 }
166
GetIconIndex(DWORD attrib,const wchar_t * fileName)167 int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)
168 {
169 int dotPos = -1;
170 unsigned i;
171 for (i = 0;; i++)
172 {
173 const wchar_t c = fileName[i];
174 if (c == 0)
175 break;
176 if (c == '.')
177 dotPos = (int)i;
178 }
179
180 /*
181 if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0)
182 {
183 char s[256];
184 sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib);
185 OutputDebugStringA(s);
186 OutputDebugStringW(fileName);
187 }
188 */
189
190 if ((attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 || dotPos < 0)
191 {
192 unsigned insertPos = 0;
193 const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);
194 if (index >= 0)
195 {
196 // if (typeName) *typeName = _attribMap[index].TypeName;
197 return _attribMap[(unsigned)index].IconIndex;
198 }
199 CAttribIconPair pair;
200 GetRealIconIndex(
201 #ifdef UNDER_CE
202 FTEXT("\\")
203 #endif
204 FTEXT("__DIR__")
205 , attrib, pair.IconIndex
206 // , pair.TypeName
207 );
208
209 /*
210 char s[256];
211 sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib);
212 OutputDebugStringA(s);
213 */
214
215 pair.Attrib = attrib;
216 _attribMap.Insert(insertPos, pair);
217 // if (typeName) *typeName = pair.TypeName;
218 return pair.IconIndex;
219 }
220
221 const wchar_t *ext = fileName + dotPos + 1;
222 unsigned insertPos = 0;
223 const int index = FindInSorted_Ext(_extMap, ext, insertPos);
224 if (index >= 0)
225 {
226 const CExtIconPair &pa = _extMap[index];
227 // if (typeName) *typeName = pa.TypeName;
228 return pa.IconIndex;
229 }
230
231 for (i = 0;; i++)
232 {
233 const wchar_t c = ext[i];
234 if (c == 0)
235 break;
236 if (c < L'0' || c > L'9')
237 break;
238 }
239 if (i != 0 && ext[i] == 0)
240 {
241 // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003
242 if (!SplitIconIndex_Defined)
243 {
244 GetRealIconIndex(
245 #ifdef UNDER_CE
246 FTEXT("\\")
247 #endif
248 FTEXT("__FILE__.001"), 0, SplitIconIndex);
249 SplitIconIndex_Defined = true;
250 }
251 return SplitIconIndex;
252 }
253
254 CExtIconPair pair;
255 pair.Ext = ext;
256 GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex);
257 _extMap.Insert(insertPos, pair);
258 // if (typeName) *typeName = pair.TypeName;
259 return pair.IconIndex;
260 }
261
262 /*
263 int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
264 {
265 return GetIconIndex(attrib, fileName, NULL);
266 }
267 */
268
GetSysImageList(bool smallIcons)269 HIMAGELIST GetSysImageList(bool smallIcons)
270 {
271 SHFILEINFO shellInfo;
272 return (HIMAGELIST)SHGetFileInfo(TEXT(""),
273 FILE_ATTRIBUTE_NORMAL |
274 FILE_ATTRIBUTE_DIRECTORY,
275 &shellInfo, sizeof(shellInfo),
276 SHGFI_USEFILEATTRIBUTES |
277 SHGFI_SYSICONINDEX |
278 (smallIcons ? SHGFI_SMALLICON : SHGFI_ICON));
279 }
280