• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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