Home | History | Annotate | Download | only in FileManager
      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 
     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;
     47   CSHGetFileInfoInit()
     48   {
     49     shGetFileInfoW = (SHGetFileInfoWP)
     50     ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");
     51   }
     52 } g_SHGetFileInfoInit;
     53 #endif
     54 
     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 
     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 
    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 
    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 
    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