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(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 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