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