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
16extern bool g_IsNT;
17#endif
18
19int 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
42typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
43
44struct CSHGetFileInfoInit
45{
46  SHGetFileInfoWP shGetFileInfoW;
47  CSHGetFileInfoInit()
48  {
49    shGetFileInfoW = (SHGetFileInfoWP)
50    ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");
51  }
52} g_SHGetFileInfoInit;
53#endif
54
55static 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
67DWORD_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/*
90DWORD_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
119static 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
137static 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
155int 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/*
251int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
252{
253  return GetIconIndex(attrib, fileName, NULL);
254}
255*/
256