chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,351 @@
|
||||
// SysIconUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../../../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "../../../Windows/FileDir.h"
|
||||
|
||||
#include "SysIconUtils.h"
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <ShlObj.h>
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
CExtToIconMap g_Ext_to_Icon_Map;
|
||||
|
||||
int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl)
|
||||
{
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
SHGetSpecialFolderLocation(NULL, csidl, &pidl);
|
||||
if (pidl)
|
||||
{
|
||||
SHFILEINFO shFileInfo;
|
||||
shFileInfo.iIcon = -1;
|
||||
const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl),
|
||||
FILE_ATTRIBUTE_DIRECTORY,
|
||||
&shFileInfo, sizeof(shFileInfo),
|
||||
SHGFI_PIDL | SHGFI_SYSICONINDEX);
|
||||
/*
|
||||
IMalloc *pMalloc;
|
||||
SHGetMalloc(&pMalloc);
|
||||
if (pMalloc)
|
||||
{
|
||||
pMalloc->Free(pidl);
|
||||
pMalloc->Release();
|
||||
}
|
||||
*/
|
||||
// we use OLE2.dll function here
|
||||
CoTaskMemFree(pidl);
|
||||
if (res)
|
||||
return shFileInfo.iIcon;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
typedef DWORD_PTR (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
|
||||
|
||||
static struct C_SHGetFileInfo_Init
|
||||
{
|
||||
Func_SHGetFileInfoW f_SHGetFileInfoW;
|
||||
C_SHGetFileInfo_Init()
|
||||
{
|
||||
f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS(
|
||||
Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"),
|
||||
"SHGetFileInfoW");
|
||||
// f_SHGetFileInfoW = NULL; // for debug
|
||||
}
|
||||
} g_SHGetFileInfo_Init;
|
||||
#endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define My_SHGetFileInfoW SHGetFileInfoW
|
||||
#else
|
||||
static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)
|
||||
{
|
||||
if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW)
|
||||
return 0;
|
||||
return g_SHGetFileInfo_Init.f_SHGetFileInfoW(pszPath, attrib, psfi, cbFileInfo, uFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(
|
||||
CFSTR path, DWORD attrib, int &iconIndex)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT || !g_SHGetFileInfo_Init.f_SHGetFileInfoW)
|
||||
{
|
||||
SHFILEINFO shFileInfo;
|
||||
// ZeroMemory(&shFileInfo, sizeof(shFileInfo));
|
||||
shFileInfo.iIcon = -1; // optional
|
||||
const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path),
|
||||
attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE,
|
||||
&shFileInfo, sizeof(shFileInfo),
|
||||
SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
|
||||
iconIndex = shFileInfo.iIcon;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SHFILEINFOW shFileInfo;
|
||||
// ZeroMemory(&shFileInfo, sizeof(shFileInfo));
|
||||
shFileInfo.iIcon = -1; // optional
|
||||
const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path),
|
||||
attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE,
|
||||
&shFileInfo, sizeof(shFileInfo),
|
||||
SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
|
||||
// (shFileInfo.iIcon == 0) returned for unknown extensions and files without extension
|
||||
iconIndex = shFileInfo.iIcon;
|
||||
// we use SHGFI_USEFILEATTRIBUTES, and
|
||||
// (res != 0) is expected for main cases, even if there are no such file.
|
||||
// (res == 0) for path with kSuperPrefix "\\?\"
|
||||
// Also SHGFI_USEFILEATTRIBUTES still returns icon inside exe.
|
||||
// So we can use SHGFI_USEFILEATTRIBUTES for any case.
|
||||
// UString temp = fs2us(path); // for debug
|
||||
// UString tempName = temp.Ptr(temp.ReverseFind_PathSepar() + 1); // for debug
|
||||
// iconIndex = -1; // for debug
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib)
|
||||
{
|
||||
int iconIndex = -1;
|
||||
if (!Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(
|
||||
path, attrib, iconIndex))
|
||||
iconIndex = -1;
|
||||
return iconIndex;
|
||||
}
|
||||
|
||||
|
||||
HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
|
||||
CFSTR path, DWORD attrib, Int32 *iconIndex)
|
||||
{
|
||||
*iconIndex = -1;
|
||||
int iconIndexTemp;
|
||||
if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(
|
||||
path, attrib, iconIndexTemp))
|
||||
{
|
||||
*iconIndex = iconIndexTemp;
|
||||
return S_OK;
|
||||
}
|
||||
return GetLastError_noZero_HRESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
SHFILEINFO shFileInfo;
|
||||
shFileInfo.szTypeName[0] = 0;
|
||||
DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo,
|
||||
sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
|
||||
if (typeName)
|
||||
*typeName = GetUnicodeString(shFileInfo.szTypeName);
|
||||
iconIndex = shFileInfo.iIcon;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SHFILEINFOW shFileInfo;
|
||||
shFileInfo.szTypeName[0] = 0;
|
||||
DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo,
|
||||
sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
|
||||
if (typeName)
|
||||
*typeName = shFileInfo.szTypeName;
|
||||
iconIndex = shFileInfo.iIcon;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &vect, DWORD attrib, unsigned &insertPos)
|
||||
{
|
||||
unsigned left = 0, right = vect.Size();
|
||||
while (left != right)
|
||||
{
|
||||
const unsigned mid = (left + right) / 2;
|
||||
const DWORD midAttrib = vect[mid].Attrib;
|
||||
if (attrib == midAttrib)
|
||||
return (int)mid;
|
||||
if (attrib < midAttrib)
|
||||
right = mid;
|
||||
else
|
||||
left = mid + 1;
|
||||
}
|
||||
insertPos = left;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar_t *ext, unsigned &insertPos)
|
||||
{
|
||||
unsigned left = 0, right = vect.Size();
|
||||
while (left != right)
|
||||
{
|
||||
const unsigned mid = (left + right) / 2;
|
||||
const int compare = MyStringCompareNoCase(ext, vect[mid].Ext);
|
||||
if (compare == 0)
|
||||
return (int)mid;
|
||||
if (compare < 0)
|
||||
right = mid;
|
||||
else
|
||||
left = mid + 1;
|
||||
}
|
||||
insertPos = left;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// bool DoItemAlwaysStart(const UString &name);
|
||||
|
||||
int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)
|
||||
{
|
||||
int dotPos = -1;
|
||||
unsigned i;
|
||||
for (i = 0;; i++)
|
||||
{
|
||||
const wchar_t c = fileName[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c == '.')
|
||||
dotPos = (int)i;
|
||||
// we don't need IS_PATH_SEPAR check, because (fileName) doesn't include path prefix.
|
||||
// if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0)
|
||||
{
|
||||
char s[256];
|
||||
sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib);
|
||||
OutputDebugStringA(s);
|
||||
OutputDebugStringW(fileName);
|
||||
}
|
||||
*/
|
||||
|
||||
if ((attrib & FILE_ATTRIBUTE_DIRECTORY) || dotPos < 0)
|
||||
for (unsigned k = 0;; k++)
|
||||
{
|
||||
if (k >= 2)
|
||||
return -1;
|
||||
unsigned insertPos = 0;
|
||||
const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);
|
||||
if (index >= 0)
|
||||
{
|
||||
// if (typeName) *typeName = _attribMap[index].TypeName;
|
||||
return _attribMap[(unsigned)index].IconIndex;
|
||||
}
|
||||
CAttribIconPair pair;
|
||||
pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(
|
||||
#ifdef UNDER_CE
|
||||
FTEXT("\\")
|
||||
#endif
|
||||
FTEXT("__DIR__")
|
||||
, attrib
|
||||
// , pair.TypeName
|
||||
);
|
||||
if (_attribMap.Size() < (1u << 16) // we limit cache size
|
||||
|| attrib < (1u << 15)) // we want to put all items with basic attribs to cache
|
||||
{
|
||||
/*
|
||||
char s[256];
|
||||
sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib);
|
||||
OutputDebugStringA(s);
|
||||
*/
|
||||
pair.Attrib = attrib;
|
||||
_attribMap.Insert(insertPos, pair);
|
||||
// if (typeName) *typeName = pair.TypeName;
|
||||
return pair.IconIndex;
|
||||
}
|
||||
if (pair.IconIndex >= 0)
|
||||
return pair.IconIndex;
|
||||
attrib = (attrib & FILE_ATTRIBUTE_DIRECTORY) ?
|
||||
FILE_ATTRIBUTE_DIRECTORY :
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
CObjectVector<CExtIconPair> &map =
|
||||
(attrib & FILE_ATTRIBUTE_COMPRESSED) ?
|
||||
_extMap_Compressed : _extMap_Normal;
|
||||
const wchar_t *ext = fileName + dotPos + 1;
|
||||
unsigned insertPos = 0;
|
||||
const int index = FindInSorted_Ext(map, ext, insertPos);
|
||||
if (index >= 0)
|
||||
{
|
||||
const CExtIconPair &pa = map[index];
|
||||
// if (typeName) *typeName = pa.TypeName;
|
||||
return pa.IconIndex;
|
||||
}
|
||||
|
||||
for (i = 0;; i++)
|
||||
{
|
||||
const wchar_t c = ext[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c < L'0' || c > L'9')
|
||||
break;
|
||||
}
|
||||
if (i != 0 && ext[i] == 0)
|
||||
{
|
||||
// Shell_GetFileInfo_SysIconIndex_for_Path is too slow for big number of split extensions: .001, .002, .003
|
||||
if (!SplitIconIndex_Defined)
|
||||
{
|
||||
Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(
|
||||
#ifdef UNDER_CE
|
||||
FTEXT("\\")
|
||||
#endif
|
||||
FTEXT("__FILE__.001"), FILE_ATTRIBUTE_ARCHIVE, SplitIconIndex);
|
||||
SplitIconIndex_Defined = true;
|
||||
}
|
||||
return SplitIconIndex;
|
||||
}
|
||||
|
||||
CExtIconPair pair;
|
||||
pair.Ext = ext;
|
||||
pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(
|
||||
us2fs(fileName + dotPos),
|
||||
attrib & FILE_ATTRIBUTE_COMPRESSED ?
|
||||
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED:
|
||||
FILE_ATTRIBUTE_ARCHIVE);
|
||||
if (map.Size() < (1u << 16) // we limit cache size
|
||||
// || DoItemAlwaysStart(fileName + dotPos) // we want some popular extensions in cache
|
||||
)
|
||||
map.Insert(insertPos, pair);
|
||||
// if (typeName) *typeName = pair.TypeName;
|
||||
return pair.IconIndex;
|
||||
}
|
||||
|
||||
|
||||
HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons)
|
||||
{
|
||||
SHFILEINFO shFileInfo;
|
||||
// shFileInfo.hIcon = NULL; // optional
|
||||
const DWORD_PTR res = SHGetFileInfo(TEXT(""),
|
||||
/* FILE_ATTRIBUTE_ARCHIVE | */
|
||||
FILE_ATTRIBUTE_DIRECTORY,
|
||||
&shFileInfo, sizeof(shFileInfo),
|
||||
SHGFI_USEFILEATTRIBUTES |
|
||||
SHGFI_SYSICONINDEX |
|
||||
(smallIcons ? SHGFI_SMALLICON : SHGFI_LARGEICON));
|
||||
#if 0
|
||||
// (shFileInfo.hIcon == NULL), because we don't use SHGFI_ICON.
|
||||
// so DestroyIcon() is not required
|
||||
if (res && shFileInfo.hIcon) // unexpected
|
||||
DestroyIcon(shFileInfo.hIcon);
|
||||
#endif
|
||||
return (HIMAGELIST)res;
|
||||
}
|
||||
Reference in New Issue
Block a user