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