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