셸에서 사용하는 파일 아이콘 가져오기
.Net(C# 또는 VB: 상관 없음)에서 실제 기존 파일에 대한 파일 경로 문자열, FileInfo 구조 또는 FileSystemInfo 구조가 주어지면 해당 파일에 대해 셸(탐색기)에서 사용하는 아이콘을 어떻게 확인할 수 있습니까?
저는 현재 이것을 어떤 용도로 사용할 계획은 없지만, 이 질문을 보고 어떻게 해야 하는지 궁금증이 생겼고 여기 SO에 보관하는 것이 유용할 것 같다는 생각이 들었습니다.
Imports System.Drawing
Module Module1
Sub Main()
Dim filePath As String = "C:\myfile.exe"
Dim TheIcon As Icon = IconFromFilePath(filePath)
If TheIcon IsNot Nothing Then
''#Save it to disk, or do whatever you want with it.
Using stream As New System.IO.FileStream("c:\myfile.ico", IO.FileMode.CreateNew)
TheIcon.Save(stream)
End Using
End If
End Sub
Public Function IconFromFilePath(filePath As String) As Icon
Dim result As Icon = Nothing
Try
result = Icon.ExtractAssociatedIcon(filePath)
Catch ''# swallow and return nothing. You could supply a default Icon here as well
End Try
Return result
End Function
End Module
SHGetFileInfo를 사용해야 합니다.
Icon.Extract Associated아이콘은 대부분의 경우 SHGetFileInfo와 동일하게 작동하지만 SHGetFileInfo는 UNC 경로(예: "\\ComputerName\")와 함께 작동할 수 있습니다.아이콘을 클릭하는 동안 공유 폴더\"를 클릭합니다.연관된 추출아이콘을 사용할 수 없습니다.UNC 경로가 필요하거나 사용해야 할 경우 Icon 대신 SHGetFileInfo를 사용하는 것이 가장 좋습니다.연관된 아이콘을 추출합니다.
이것은 SHGetFileInfo를 사용하는 방법에 대한 좋은 CodeProject 기사입니다.
레지스트리를 사용하라는 모든 사용자를 무시하십시오!레지스트리가 API가 아닙니다.당신이 원하는 API는 SHGetFileInfo with SHGFI_ICON입니다.다음 위치에서 P/Invoke 서명을 받을 수 있습니다.
http://www.pinvoke.net/default.aspx/shell32.SHGetFileInfo
스테판의 대답을 C# 버전으로 나타낸 것에 지나지 않습니다.
using System.Drawing;
class Class1
{
public static void Main()
{
var filePath = @"C:\myfile.exe";
var theIcon = IconFromFilePath(filePath);
if (theIcon != null)
{
// Save it to disk, or do whatever you want with it.
using (var stream = new System.IO.FileStream(@"c:\myfile.ico", System.IO.FileMode.CreateNew))
{
theIcon.Save(stream);
}
}
}
public static Icon IconFromFilePath(string filePath)
{
var result = (Icon)null;
try
{
result = Icon.ExtractAssociatedIcon(filePath);
}
catch (System.Exception)
{
// swallow and return nothing. You could supply a default Icon here as well
}
return result;
}
}
이것은 제 프로젝트에서 제게 도움이 됩니다. 누군가에게 도움이 되기를 바랍니다.
P/Invoke가 포함된 C#입니다. WinXP 이후 x86/x64 시스템에서 지금까지 작동합니다.
(Shell.cs )
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
namespace IconExtraction
{
internal sealed class Shell : NativeMethods
{
#region OfExtension
///<summary>
/// Get the icon of an extension
///</summary>
///<param name="filename">filename</param>
///<param name="overlay">bool symlink overlay</param>
///<returns>Icon</returns>
public static Icon OfExtension(string filename, bool overlay = false)
{
string filepath;
string[] extension = filename.Split('.');
string dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache");
Directory.CreateDirectory(dirpath);
if (String.IsNullOrEmpty(filename) || extension.Length == 1)
{
filepath = Path.Combine(dirpath, "dummy_file");
}
else
{
filepath = Path.Combine(dirpath, String.Join(".", "dummy", extension[extension.Length - 1]));
}
if (File.Exists(filepath) == false)
{
File.Create(filepath);
}
Icon icon = OfPath(filepath, true, true, overlay);
return icon;
}
#endregion
#region OfFolder
///<summary>
/// Get the icon of an extension
///</summary>
///<returns>Icon</returns>
///<param name="overlay">bool symlink overlay</param>
public static Icon OfFolder(bool overlay = false)
{
string dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache", "dummy");
Directory.CreateDirectory(dirpath);
Icon icon = OfPath(dirpath, true, true, overlay);
return icon;
}
#endregion
#region OfPath
///<summary>
/// Get the normal,small assigned icon of the given path
///</summary>
///<param name="filepath">physical path</param>
///<param name="small">bool small icon</param>
///<param name="checkdisk">bool fileicon</param>
///<param name="overlay">bool symlink overlay</param>
///<returns>Icon</returns>
public static Icon OfPath(string filepath, bool small = true, bool checkdisk = true, bool overlay = false)
{
Icon clone;
SHGFI_Flag flags;
SHFILEINFO shinfo = new SHFILEINFO();
if (small)
{
flags = SHGFI_Flag.SHGFI_ICON | SHGFI_Flag.SHGFI_SMALLICON;
}
else
{
flags = SHGFI_Flag.SHGFI_ICON | SHGFI_Flag.SHGFI_LARGEICON;
}
if (checkdisk == false)
{
flags |= SHGFI_Flag.SHGFI_USEFILEATTRIBUTES;
}
if (overlay)
{
flags |= SHGFI_Flag.SHGFI_LINKOVERLAY;
}
if (SHGetFileInfo(filepath, 0, ref shinfo, Marshal.SizeOf(shinfo), flags) == 0)
{
throw (new FileNotFoundException());
}
Icon tmp = Icon.FromHandle(shinfo.hIcon);
clone = (Icon)tmp.Clone();
tmp.Dispose();
if (DestroyIcon(shinfo.hIcon) != 0)
{
return clone;
}
return clone;
}
#endregion
}
}
(NativeMethods.cs )
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace IconExtraction
{
internal class NativeMethods
{
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[DllImport("user32.dll")]
public static extern int DestroyIcon(IntPtr hIcon);
[DllImport("shell32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
[DllImport("Shell32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags);
[DllImport("Shell32.dll")]
public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags);
}
public enum SHGFI_Flag : uint
{
SHGFI_ATTR_SPECIFIED = 0x000020000,
SHGFI_OPENICON = 0x000000002,
SHGFI_USEFILEATTRIBUTES = 0x000000010,
SHGFI_ADDOVERLAYS = 0x000000020,
SHGFI_DISPLAYNAME = 0x000000200,
SHGFI_EXETYPE = 0x000002000,
SHGFI_ICON = 0x000000100,
SHGFI_ICONLOCATION = 0x000001000,
SHGFI_LARGEICON = 0x000000000,
SHGFI_SMALLICON = 0x000000001,
SHGFI_SHELLICONSIZE = 0x000000004,
SHGFI_LINKOVERLAY = 0x000008000,
SHGFI_SYSICONINDEX = 0x000004000,
SHGFI_TYPENAME = 0x000000400
}
}
레지스트리 접근 방식의 문제는 아이콘 인덱스 ID를 명시적으로 가져오지 않는다는 것입니다.때때로(항상은 아닐지라도) 리소스 아이콘이 표시됩니다.응용 프로그램 개발자가 아이콘의 슬롯 이름을 지정하는 데 사용하는 별칭인 ID입니다.
따라서 레지스트리 방법은 모든 개발자가 리소스를 사용한다는 것을 의미합니다.암시적 아이콘 인덱스 ID(0 기반, 절대, 결정론적)와 동일한 ID입니다.
레지스트리 위치를 스캔하면 마이너스 숫자가 많이 표시되며, 때로는 텍스트 참조(즉, 아이콘 인덱스 ID가 아닌 경우)도 표시됩니다.암묵적인 방법은 OS가 작업을 수행할 수 있도록 하기 때문에 더 나은 것 같습니다.
지금 이 새로운 방법을 테스트하는 것 뿐이지만, 그것은 타당하고 바라건대 이 문제를 해결할 수 있습니다.
특정 확장명의 아이콘에만 관심이 있고 임시 파일을 만들 수 있다면 여기에 표시된 예를 따를 수 있습니다.
C# 코드:
public Icon LoadIconFromExtension(string extension)
{
string path = string.Format("dummy{0}", extension);
using (File.Create(path)) { }
Icon icon = Icon.ExtractAssociatedIcon(path);
File.Delete(path);
return icon;
}
이 링크에 정보가 있는 것 같습니다.이것은 많은 레지스트리 트래버싱을 포함하지만 실행 가능한 것으로 보입니다.예는 C++에 있습니다.
- 연장을 결정합니다.
- 레지스트리에서 다음으로 이동
"HKCR\.{extension}"
filetype
) "HKCR\{filetype}\DefaultIcon"
기본값 읽기: 아이콘 파일(또는 아이콘 리소스가 내장된 .exe와 같은 아이콘 컨테이너 파일)의 경로입니다.- 필요한 경우 언급된 파일에서 아이콘 리소스를 추출하는 기본 방법을 사용합니다.
주석에서 편집/백업:
꽤 흔한 일입니다 다음과 것이 있습니다."foo.exe,3"
즉, 사용 가능한 아이콘의 아이콘 번호 4(색인은 0 기반)입니다.값 ",0"은 암시적(및 선택 사항)입니다.카운터가 0이거나 누락된 경우 셸에서 사용 가능한 첫 번째 아이콘이 사용됩니다.
응용 프로그램에 여러 개의 아이콘이 포함될 수 있으며, 그 중 하나만 추출해도 충분하지 않을 수 있습니다.저는 나중에 심을 만들기 위한 컴파일에서 다시 사용하기 위해 혼자 아이콘을 선택하고 싶었습니다.
작동하는 - 작동는공방인법적 - 용사를 사용합니다.IconLib.Unofficial
0.73.0 이상.
다음과 같은 코드 추가:
MultiIcon multiIcon = new MultiIcon();
multiIcon.Load(<in path>);
multiIcon.Save(<out path>, MultiIconFormat.ICO);
응용 프로그램에서 사용하는 아이콘을 추출할 수 있습니다.
그러나 라이브러리 자체는 .net 프레임워크 4.6.1 - v4.8에서 작동하며 .net core에서는 작동하지 않습니다.
제가 시도한 다른 방법들도 있습니다.
Icon icon = Icon.ExtractAssociatedIcon(<in path>);
using (FileStream stream = new FileStream(<out path>, FileMode.CreateNew))
{
icon.Save(stream);
}
하나의 아이콘에 대해서만 작동하지만 손상되기도 합니다. method를 사용할 .SHGetFileInfo
.
PeNet 라이브러리를 사용하는 코드는 다음과 같습니다.
var peFile = new PeFile(cmdArgs.iconpath);
byte[] icon = peFile.Icons().First().AsSpan().ToArray();
File.WriteAllBytes(iconPath, icon);
PeNet에서는 아이콘을 추출할 수 있지만 원래 형식이 아니며 여러 개의 아이콘이 있습니다.이 커밋에서는 전체 기능이 개발되지만 기능을 어떻게 사용해야 하는지에 대한 단서는 아직 없습니다.기능이 성숙될 때까지 기다려야 할 수도 있습니다.(258호 침투 참조)
ICSharpCode.Decompiler
유사한 기능을 제공하기 위해 개인 메서드에 사용할 수 있습니다.
PEFile file = new PEFile(cmdArgs.iconpath);
var resources = file.Reader.ReadWin32Resources();
if (resources != null)
{
var createAppIcon = typeof(WholeProjectDecompiler).GetMethod("CreateApplicationIcon", BindingFlags.Static | BindingFlags.NonPublic);
byte[] icon = (byte[])createAppIcon.Invoke(null, new[] { file });
File.WriteAllBytes(iconPath, icon);
}
하지만 .net core 3.1 컴파일된 바이너리에 예외가 있었습니다. 아마도 그 라이브러리가 모든 경우에 작동하지는 않을 것입니다.
언급URL : https://stackoverflow.com/questions/462270/get-file-icon-used-by-shell
'programing' 카테고리의 다른 글
Xcode - 다운로드할 수 있는 dSYM이 없습니다. (0) | 2023.06.02 |
---|---|
루비에서 __FILE_은 무엇을 의미합니까? (0) | 2023.06.02 |
Azure DocumentDb에서 레코드 수 가져오기 (0) | 2023.06.02 |
Swift에서 "Index"를 "Int" 유형으로 변환하는 방법은 무엇입니까? (0) | 2023.06.02 |
분기의 파일 제거로 인한 병합 충돌을 해결하려면 어떻게 해야 합니까? (0) | 2023.05.28 |