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 20extern bool g_IsNT; 21#endif 22 23int 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 52typedef DWORD_PTR (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); 53 54static struct C_SHGetFileInfo_Init 55{ 56 Func_SHGetFileInfoW f_SHGetFileInfoW; 57 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 66static 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 78DWORD_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/* 101DWORD_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 130static 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 148static 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 166int 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/* 262int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName) 263{ 264 return GetIconIndex(attrib, fileName, NULL); 265} 266*/ 267 268HIMAGELIST 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