From e34d59c1f7124536fda50a0659ae69b2816b1fd1 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Mon, 19 Oct 2020 21:50:42 +1300 Subject: [PATCH] Cleaned up Icon creation (mostly) Managed to fix large icon creation thanks to work from Maurizio. Fied an issue with file selection for Icon generation. Also found a new issue with ShortcutList that needs fixing shortly. https://tabbles.net/how-to-have-large-file-icons-with-shgetfileinfo-in-c/ --- HeliosPlus/GameLibraries/SteamLibrary.cs | 3 +- HeliosPlus/HeliosPlus.csproj | 10 + HeliosPlus/IconFromFile.cs | 606 +++++++++++++++++++++++ HeliosPlus/Program.cs | 6 + HeliosPlus/ShellIcon.cs | 136 +++++ HeliosPlus/ShortcutItem.cs | 448 +++++++++++++++-- HeliosPlus/UIForms/ShortcutForm.cs | 49 +- 7 files changed, 1172 insertions(+), 86 deletions(-) create mode 100644 HeliosPlus/IconFromFile.cs create mode 100644 HeliosPlus/ShellIcon.cs diff --git a/HeliosPlus/GameLibraries/SteamLibrary.cs b/HeliosPlus/GameLibraries/SteamLibrary.cs index b3a4e2a..02c1b9e 100644 --- a/HeliosPlus/GameLibraries/SteamLibrary.cs +++ b/HeliosPlus/GameLibraries/SteamLibrary.cs @@ -501,7 +501,7 @@ namespace HeliosPlus.GameLibraries // Next, we need to get the Icons we want to use, and make sure it's the latest one. string steamGameIconPath = ""; // First of all, we attempt to use the Icon that Steam has cached, if it's available, as that will be updated to the latest - if (File.Exists(steamAppInfo[steamGameId].GameSteamIconPath)) + if (File.Exists(steamAppInfo[steamGameId].GameSteamIconPath) && steamAppInfo[steamGameId].GameSteamIconPath.EndsWith(".ico")) { steamGameIconPath = steamAppInfo[steamGameId].GameSteamIconPath; } @@ -516,6 +516,7 @@ namespace HeliosPlus.GameLibraries { // Now we need to get the Icon from the app if possible if it's not in the games folder steamGameIconPath = steamGameExe; + break; } } diff --git a/HeliosPlus/HeliosPlus.csproj b/HeliosPlus/HeliosPlus.csproj index b0c2d19..9fe8b70 100644 --- a/HeliosPlus/HeliosPlus.csproj +++ b/HeliosPlus/HeliosPlus.csproj @@ -62,6 +62,7 @@ + @@ -71,6 +72,7 @@ + @@ -80,8 +82,10 @@ + + @@ -199,6 +203,9 @@ 0.73.0 + + 2.4.0 + 13.8.2 @@ -213,6 +220,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + 1.0.4 + 12.0.3 diff --git a/HeliosPlus/IconFromFile.cs b/HeliosPlus/IconFromFile.cs new file mode 100644 index 0000000..71292aa --- /dev/null +++ b/HeliosPlus/IconFromFile.cs @@ -0,0 +1,606 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +//using System.Windows; +using System.Drawing.Imaging; +//using System.Windows.Media.Imaging; + +using System.Diagnostics; +using System.Drawing; +using System.Windows; + +namespace HeliosPlus +{ + class IconFromFile + { + // Constants that we need in the function call + + private const int SHGFI_ICON = 0x100; + + private const int SHGFI_SMALLICON = 0x1; + + private const int SHGFI_LARGEICON = 0x0; + + private const int SHIL_JUMBO = 0x4; + private const int SHIL_EXTRALARGE = 0x2; + + // This structure will contain information about the file + + public struct SHFILEINFO + { + + // Handle to the icon representing the file + + public IntPtr hIcon; + + // Index of the icon within the image list + + public int iIcon; + + // Various attributes of the file + + public uint dwAttributes; + + // Path to the file + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + + public string szDisplayName; + + // File type + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + + public string szTypeName; + + }; + + [System.Runtime.InteropServices.DllImport("Kernel32.dll")] + public static extern Boolean CloseHandle(IntPtr handle); + + private struct IMAGELISTDRAWPARAMS + { + public int cbSize; + public IntPtr himl; + public int i; + public IntPtr hdcDst; + public int x; + public int y; + public int cx; + public int cy; + public int xBitmap; // x offest from the upperleft of bitmap + public int yBitmap; // y offset from the upperleft of bitmap + public int rgbBk; + public int rgbFg; + public int fStyle; + public int dwRop; + public int fState; + public int Frame; + public int crEffect; + } + + [StructLayout(LayoutKind.Sequential)] + private struct IMAGEINFO + { + public IntPtr hbmImage; + public IntPtr hbmMask; + public int Unused1; + public int Unused2; + public Rect rcImage; + } + + #region Private ImageList COM Interop (XP) + [ComImportAttribute()] + [GuidAttribute("46EB5926-582E-4017-9FDF-E8998DAA0950")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + //helpstring("Image List"), + interface IImageList + { + [PreserveSig] + int Add( + IntPtr hbmImage, + IntPtr hbmMask, + ref int pi); + + [PreserveSig] + int ReplaceIcon( + int i, + IntPtr hicon, + ref int pi); + + [PreserveSig] + int SetOverlayImage( + int iImage, + int iOverlay); + + [PreserveSig] + int Replace( + int i, + IntPtr hbmImage, + IntPtr hbmMask); + + [PreserveSig] + int AddMasked( + IntPtr hbmImage, + int crMask, + ref int pi); + + [PreserveSig] + int Draw( + ref IMAGELISTDRAWPARAMS pimldp); + + [PreserveSig] + int Remove( + int i); + + [PreserveSig] + int GetIcon( + int i, + int flags, + ref IntPtr picon); + + [PreserveSig] + int GetImageInfo( + int i, + ref IMAGEINFO pImageInfo); + + [PreserveSig] + int Copy( + int iDst, + IImageList punkSrc, + int iSrc, + int uFlags); + + [PreserveSig] + int Merge( + int i1, + IImageList punk2, + int i2, + int dx, + int dy, + ref Guid riid, + ref IntPtr ppv); + + [PreserveSig] + int Clone( + ref Guid riid, + ref IntPtr ppv); + + [PreserveSig] + int GetImageRect( + int i, + ref Rect prc); + + [PreserveSig] + int GetIconSize( + ref int cx, + ref int cy); + + [PreserveSig] + int SetIconSize( + int cx, + int cy); + + [PreserveSig] + int GetImageCount( + ref int pi); + + [PreserveSig] + int SetImageCount( + int uNewCount); + + [PreserveSig] + int SetBkColor( + int clrBk, + ref int pclr); + + [PreserveSig] + int GetBkColor( + ref int pclr); + + [PreserveSig] + int BeginDrag( + int iTrack, + int dxHotspot, + int dyHotspot); + + [PreserveSig] + int EndDrag(); + + [PreserveSig] + int DragEnter( + IntPtr hwndLock, + int x, + int y); + + [PreserveSig] + int DragLeave( + IntPtr hwndLock); + + [PreserveSig] + int DragMove( + int x, + int y); + + [PreserveSig] + int SetDragCursorImage( + ref IImageList punk, + int iDrag, + int dxHotspot, + int dyHotspot); + + [PreserveSig] + int DragShowNolock( + int fShow); + +/* [PreserveSig] + int GetDragImage( + ref Point ppt, + ref Point pptHotspot, + ref Guid riid, + ref IntPtr ppv);*/ + + [PreserveSig] + int GetItemFlags( + int i, + ref int dwFlags); + + [PreserveSig] + int GetOverlayImage( + int iOverlay, + ref int piIndex); + }; + #endregion + + /// + /// SHGetImageList is not exported correctly in XP. See KB316931 + /// http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q316931 + /// Apparently (and hopefully) ordinal 727 isn't going to change. + /// + [DllImport("shell32.dll", EntryPoint = "#727")] + private extern static int SHGetImageList( + int iImageList, + ref Guid riid, + out IImageList ppv + ); + + // The signature of SHGetFileInfo (located in Shell32.dll) + [DllImport("Shell32.dll")] + public static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags); + + [DllImport("Shell32.dll")] + public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags); + + [DllImport("shell32.dll", SetLastError = true)] + static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, Int32 nFolder, + ref IntPtr ppidl); + + [DllImport("user32")] + public static extern int DestroyIcon(IntPtr hIcon); + + public struct pair + { + public System.Drawing.Icon icon { get; set; } + public IntPtr iconHandleToDestroy { set; get; } + + } + + public static int DestroyIcon2(IntPtr hIcon) + { + return DestroyIcon(hIcon); + } + + /*private static BitmapSource bitmap_source_of_icon(System.Drawing.Icon ic) + { + var ic2 = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(ic.Handle, + System.Windows.Int32Rect.Empty, + System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); + ic2.Freeze(); + return ((BitmapSource)ic2); + }*/ + + /*public static BitmapSource SystemIcon(bool small, ShellLib.ShellApi.CSIDL csidl) + { + + IntPtr pidlTrash = IntPtr.Zero; + int hr = SHGetSpecialFolderLocation(IntPtr.Zero, (int)csidl, ref pidlTrash); + Debug.Assert(hr == 0); + + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + + // Get a handle to the large icon + uint flags; + uint SHGFI_PIDL = 0x000000008; + if (!small) + { + flags = SHGFI_PIDL | SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES; + } + else + { + flags = SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES; + } + + var res = SHGetFileInfo(pidlTrash, 0, ref shinfo, Marshal.SizeOf(shinfo), flags); + Debug.Assert(res != 0); + + var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon); + Marshal.FreeCoTaskMem(pidlTrash); + var bs = bitmap_source_of_icon(myIcon); + myIcon.Dispose(); + bs.Freeze(); // importantissimo se no fa memory leak + DestroyIcon(shinfo.hIcon); + CloseHandle(shinfo.hIcon); + return bs; + + }*/ + +/* public static BitmapSource GetSmallBitmapFromFile(string FileName, bool small, bool checkDisk, bool addOverlay) + { + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + uint SHGFI_LINKOVERLAY = 0x000008000; + + uint flags; + if (small) + { + flags = SHGFI_ICON | SHGFI_SMALLICON; + } + else + { + flags = SHGFI_ICON | SHGFI_LARGEICON; + } + if (!checkDisk) + flags |= SHGFI_USEFILEATTRIBUTES; + if (addOverlay) + flags |= SHGFI_LINKOVERLAY; + + var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags); + if (res == 0) + { + throw (new System.IO.FileNotFoundException()); + } + + var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon); + + var bs = bitmap_source_of_icon(myIcon); + myIcon.Dispose(); + bs.Freeze(); // importantissimo se no fa memory leak + DestroyIcon(shinfo.hIcon); + CloseHandle(shinfo.hIcon); + return bs; + + }*/ + + public static Bitmap GetSmallBitmapFromFile(string FileName, bool small, bool checkDisk, bool addOverlay) + { + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + uint SHGFI_LINKOVERLAY = 0x000008000; + + uint flags; + if (small) + { + flags = SHGFI_ICON | SHGFI_SMALLICON; + } + else + { + flags = SHGFI_ICON | SHGFI_LARGEICON; + } + if (!checkDisk) + flags |= SHGFI_USEFILEATTRIBUTES; + if (addOverlay) + flags |= SHGFI_LINKOVERLAY; + + var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags); + if (res == 0) + { + throw (new System.IO.FileNotFoundException()); + } + + var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon); + + Bitmap bm = myIcon.ToBitmap(); + myIcon.Dispose(); + DestroyIcon(shinfo.hIcon); + //CloseHandle(shinfo.hIcon); + return bm; + + } + + /*public static BitmapSource GetLargeBitmapSourceFromFile(string FileName, bool jumbo, bool checkDisk) + { + + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + uint SHGFI_SYSICONINDEX = 0x4000; + + int FILE_ATTRIBUTE_NORMAL = 0x80; + + uint flags; + flags = SHGFI_SYSICONINDEX; + + if (!checkDisk) // This does not seem to work. If I try it, a folder icon is always returned. + flags |= SHGFI_USEFILEATTRIBUTES; + + var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags); + if (res == 0) + { + throw (new System.IO.FileNotFoundException()); + } + var iconIndex = shinfo.iIcon; + + // Get the System IImageList object from the Shell: + Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950"); + + IImageList iml; + int size = jumbo ? SHIL_JUMBO : SHIL_EXTRALARGE; + var hres = SHGetImageList(size, ref iidImageList, out iml); // writes iml + //if (hres == 0) + //{ + // throw (new System.Exception("Error SHGetImageList")); + //} + + IntPtr hIcon = IntPtr.Zero; + int ILD_TRANSPARENT = 1; + hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon); + //if (hres == 0) + //{ + // throw (new System.Exception("Error iml.GetIcon")); + //} + + var myIcon = System.Drawing.Icon.FromHandle(hIcon); + var bs = bitmap_source_of_icon(myIcon); + myIcon.Dispose(); + bs.Freeze(); // very important to avoid memory leak + DestroyIcon(hIcon); + CloseHandle(hIcon); + + return bs; + + }*/ + + public static Icon GetSmallIconFromFile(string FileName, bool small, bool checkDisk, bool addOverlay) + { + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + uint SHGFI_LINKOVERLAY = 0x000008000; + + uint flags; + if (small) + { + flags = SHGFI_ICON | SHGFI_SMALLICON; + } + else + { + flags = SHGFI_ICON | SHGFI_LARGEICON; + } + if (!checkDisk) + flags |= SHGFI_USEFILEATTRIBUTES; + if (addOverlay) + flags |= SHGFI_LINKOVERLAY; + + var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags); + if (res == 0) + { + throw (new System.IO.FileNotFoundException()); + } + + var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon); + DestroyIcon(shinfo.hIcon); + //CloseHandle(shinfo.hIcon); + return myIcon; + + } + + public static Icon GetLargeIconFromFile(string FileName, bool jumbo, bool checkDisk) + { + + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + uint SHGFI_SYSICONINDEX = 0x4000; + + int FILE_ATTRIBUTE_NORMAL = 0x80; + + uint flags; + flags = SHGFI_SYSICONINDEX; + + if (!checkDisk) // This does not seem to work. If I try it, a folder icon is always returned. + flags |= SHGFI_USEFILEATTRIBUTES; + + var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags); + if (res == 0) + { + throw (new System.IO.FileNotFoundException()); + } + var iconIndex = shinfo.iIcon; + + // Get the System IImageList object from the Shell: + Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950"); + + IImageList iml; + int size = jumbo ? SHIL_JUMBO : SHIL_EXTRALARGE; + var hres = SHGetImageList(size, ref iidImageList, out iml); // writes iml + //if (hres == 0) + //{ + // throw (new System.Exception("Error SHGetImageList")); + //} + + IntPtr hIcon = IntPtr.Zero; + int ILD_TRANSPARENT = 1; + hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon); + //if (hres == 0) + //{ + // throw (new System.Exception("Error iml.GetIcon")); + //} + + var myIcon = System.Drawing.Icon.FromHandle(hIcon); + //myIcon.Dispose(); + DestroyIcon(hIcon); + //CloseHandle(hIcon); + + return myIcon; + + } + + public static Bitmap GetLargeBitmapFromFile(string FileName, bool jumbo, bool checkDisk) + { + + SHFILEINFO shinfo = new SHFILEINFO(); + + uint SHGFI_USEFILEATTRIBUTES = 0x000000010; + uint SHGFI_SYSICONINDEX = 0x4000; + + int FILE_ATTRIBUTE_NORMAL = 0x80; + + uint flags; + flags = SHGFI_SYSICONINDEX; + + if (!checkDisk) // This does not seem to work. If I try it, a folder icon is always returned. + flags |= SHGFI_USEFILEATTRIBUTES; + + var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags); + if (res == 0) + { + throw (new System.IO.FileNotFoundException()); + } + var iconIndex = shinfo.iIcon; + + // Get the System IImageList object from the Shell: + Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950"); + + IImageList iml; + int size = jumbo ? SHIL_JUMBO : SHIL_EXTRALARGE; + var hres = SHGetImageList(size, ref iidImageList, out iml); // writes iml + //if (hres == 0) + //{ + // throw (new System.Exception("Error SHGetImageList")); + //} + + IntPtr hIcon = IntPtr.Zero; + int ILD_TRANSPARENT = 1; + hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon); + //if (hres == 0) + //{ + // throw (new System.Exception("Error iml.GetIcon")); + //} + + var myIcon = System.Drawing.Icon.FromHandle(hIcon); + Bitmap bm = myIcon.ToBitmap(); + myIcon.Dispose(); + DestroyIcon(hIcon); + //CloseHandle(hIcon); + + return bm; + + } + } +} diff --git a/HeliosPlus/Program.cs b/HeliosPlus/Program.cs index f66ad9e..4ef58d9 100644 --- a/HeliosPlus/Program.cs +++ b/HeliosPlus/Program.cs @@ -63,6 +63,12 @@ namespace HeliosPlus { Console.WriteLine($"Copyright © Terry MacDonald 2020-{DateTime.Today.Year}"); Console.WriteLine(@"Based on Helios Display Management - Copyright © Soroush Falahati 2017-2020"); + + //Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + var app = new CommandLineApplication(); //app.Name = "HeliosDM+"; diff --git a/HeliosPlus/ShellIcon.cs b/HeliosPlus/ShellIcon.cs new file mode 100644 index 0000000..28219d5 --- /dev/null +++ b/HeliosPlus/ShellIcon.cs @@ -0,0 +1,136 @@ +// ----------------------------------------------------------------------- +// +// Distributed under Microsoft Public License (MS-PL). +// http://www.opensource.org/licenses/MS-PL +// +// ----------------------------------------------------------------------- + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace HeliosPlus { + + /// + /// Get a small or large Icon with an easy C# function call + /// that returns a 32x32 or 16x16 System.Drawing.Icon depending on which function you call + /// either GetSmallIcon(string fileName) or GetLargeIcon(string fileName) + /// + public static class ShellIcon + { + #region Interop constants + + private const uint FILE_ATTRIBUTE_NORMAL = 0x80; + private const uint FILE_ATTRIBUTE_DIRECTORY = 0x10; + + #endregion + + #region Interop data types + + [StructLayout(LayoutKind.Sequential)] + private struct SHFILEINFO + { + public IntPtr hIcon; + public IntPtr iIcon; + public uint dwAttributes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szDisplayName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public string szTypeName; + } + + [Flags] + private enum SHGFI : int + { + /// get icon + Icon = 0x000000100, + /// get display name + DisplayName = 0x000000200, + /// get type name + TypeName = 0x000000400, + /// get attributes + Attributes = 0x000000800, + /// get icon location + IconLocation = 0x000001000, + /// return exe type + ExeType = 0x000002000, + /// get system icon index + SysIconIndex = 0x000004000, + /// put a link overlay on icon + LinkOverlay = 0x000008000, + /// show icon in selected state + Selected = 0x000010000, + /// get only specified attributes + Attr_Specified = 0x000020000, + /// get large icon + LargeIcon = 0x000000000, + /// get small icon + SmallIcon = 0x000000001, + /// get open icon + OpenIcon = 0x000000002, + /// get shell size icon + ShellIconSize = 0x000000004, + /// pszPath is a pidl + PIDL = 0x000000008, + /// use passed dwFileAttribute + UseFileAttributes = 0x000000010, + /// apply the appropriate overlays + AddOverlays = 0x000000020, + /// Get the index of the overlay in the upper 8 bits of the iIcon + OverlayIndex = 0x000000040, + } + + #endregion + + private class Win32 + { + [DllImport("shell32.dll")] + public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags); + + [DllImport("User32.dll")] + public static extern int DestroyIcon(IntPtr hIcon); + + } + + public static Icon GetSmallFolderIcon() + { + return GetIcon("folder", SHGFI.SmallIcon | SHGFI.UseFileAttributes, true); + } + + public static Icon GetLargeFolderIcon() + { + return GetIcon("folder", SHGFI.LargeIcon | SHGFI.UseFileAttributes, true); + } + + public static Icon GetSmallIcon(string fileName) + { + return GetIcon(fileName, SHGFI.SmallIcon); + } + + public static Icon GetLargeIcon(string fileName) + { + return GetIcon(fileName, SHGFI.LargeIcon); + } + + public static Icon GetSmallIconFromExtension(string extension) + { + return GetIcon(extension, SHGFI.SmallIcon | SHGFI.UseFileAttributes); + } + + public static Icon GetLargeIconFromExtension(string extension) + { + return GetIcon(extension, SHGFI.LargeIcon | SHGFI.UseFileAttributes); + } + + private static Icon GetIcon(string fileName, SHGFI flags, bool isFolder = false) + { + SHFILEINFO shinfo = new SHFILEINFO(); + + IntPtr hImgSmall = Win32.SHGetFileInfo(fileName, isFolder ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL, ref shinfo, (uint)Marshal.SizeOf(shinfo), (uint)(SHGFI.Icon | flags)); + + Icon icon = (Icon)System.Drawing.Icon.FromHandle(shinfo.hIcon).Clone(); + Win32.DestroyIcon(shinfo.hIcon); + return icon; + } + } +} \ No newline at end of file diff --git a/HeliosPlus/ShortcutItem.cs b/HeliosPlus/ShortcutItem.cs index c0b76d3..6d9acb0 100644 --- a/HeliosPlus/ShortcutItem.cs +++ b/HeliosPlus/ShortcutItem.cs @@ -25,6 +25,8 @@ using System.Threading; using HeliosPlus.InterProcess; using HeliosPlus.UIForms; using ComponentFactory.Krypton.Toolkit; +using MintPlayer.IconUtils; +using System.Windows.Media.Imaging; namespace HeliosPlus { @@ -97,7 +99,7 @@ namespace HeliosPlus private List _startPrograms; [JsonIgnore] public string _originalIconPath; - private Bitmap _shortcutBitmap, _originalBitmap; + private Bitmap _shortcutBitmap, _originalLargeBitmap, _originalSmallBitmap; [JsonIgnore] public string _savedShortcutIconCacheFilename; @@ -155,13 +157,14 @@ namespace HeliosPlus // Now we need to find and populate the profileUuid _profileUuid = profile.UUID; - // We create the OriginalBitmap from the IconPath - _originalBitmap = ToBitmap(_originalIconPath); + // We create the OriginalLargeBitmap from the IconPath + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); + _originalSmallBitmap = ToSmallBitmap(_originalIconPath); // We create the ShortcutBitmap from the OriginalBitmap // (We only do it if there is a valid profile) if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } @@ -189,12 +192,12 @@ namespace HeliosPlus _profileUuid = profile.UUID; // We create the OriginalBitmap from the IconPath - _originalBitmap = ToBitmap(_originalIconPath); + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); // We create the ShortcutBitmap from the OriginalBitmap // (We only do it if there is a valid profile) if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } @@ -236,12 +239,12 @@ namespace HeliosPlus } // We create the OriginalBitmap from the IconPath - _originalBitmap = ToBitmap(_originalIconPath); + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); // We create the ShortcutBitmap from the OriginalBitmap // (We only do it if there is a valid profile) if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } public ShortcutItem( @@ -280,12 +283,12 @@ namespace HeliosPlus _profileUuid = profile.UUID; // We create the OriginalBitmap from the IconPath - _originalBitmap = ToBitmap(_originalIconPath); + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); // We create the ShortcutBitmap from the OriginalBitmap // (We only do it if there is a valid profile) if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } @@ -312,12 +315,12 @@ namespace HeliosPlus _profileUuid = profile.UUID; // We create the OriginalBitmap from the IconPath - _originalBitmap = ToBitmap(_originalIconPath); + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); // We create the ShortcutBitmap from the OriginalBitmap // (We only do it if there is a valid profile) if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } @@ -357,12 +360,12 @@ namespace HeliosPlus } // We create the OriginalBitmap from the IconPath - _originalBitmap = ToBitmap(_originalIconPath); + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); // We create the ShortcutBitmap from the OriginalBitmap // (We only do it if there is a valid profile) if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } @@ -649,25 +652,39 @@ namespace HeliosPlus _originalIconPath = value; // And we do the same for the OriginalBitmap - _originalBitmap = ToBitmap(_originalIconPath); + _originalLargeBitmap = ToLargeBitmap(_originalIconPath); } } - [JsonConverter(typeof(CustomBitmapConverter))] - public Bitmap OriginalBitmap + /*[JsonConverter(typeof(CustomBitmapConverter))] + public Bitmap OriginalSmallBitmap { get { - return _originalBitmap; + return _originalSmallBitmap; } set { - _originalBitmap = value; + _originalSmallBitmap = value; + } + }*/ + + [JsonConverter(typeof(CustomBitmapConverter))] + public Bitmap OriginalLargeBitmap + { + get + { + return _originalLargeBitmap; + } + + set + { + _originalLargeBitmap = value; // And we do the same for the Bitmap overlay, but only if the ProfileToUse is set if (_profileToUse is ProfileItem) - _shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); } } @@ -737,7 +754,7 @@ namespace HeliosPlus shortcut.GameArguments = GameArguments; shortcut.GameArgumentsRequired = GameArgumentsRequired; shortcut.OriginalIconPath = OriginalIconPath; - shortcut.OriginalBitmap = OriginalBitmap; + shortcut.OriginalLargeBitmap = OriginalLargeBitmap; shortcut.ShortcutBitmap = ShortcutBitmap; shortcut.SavedShortcutIconCacheFilename = SavedShortcutIconCacheFilename; shortcut.IsPossible = IsPossible; @@ -780,7 +797,7 @@ namespace HeliosPlus } } - public static Bitmap ExtractVistaIcon(Icon icoIcon) + /* public static Bitmap ExtractVistaIcon(Icon icoIcon) { Bitmap bmpPngExtracted = null; try @@ -815,7 +832,7 @@ namespace HeliosPlus return null; } return bmpPngExtracted; - } + }*/ /* public Bitmap ToBitmap(int width = 256, int height = 256, PixelFormat format = PixelFormat.Format32bppArgb) { @@ -831,26 +848,102 @@ namespace HeliosPlus return bitmap; }*/ - private Bitmap ToBitmapFromExe(string fileNameAndPath) + private const string Shell32 = "shell32.dll"; + + /*private Bitmap ToBitmapFromExe(string fileNameAndPath) { - /* IconExtractor ie = new IconExtractor(fileNameAndPath); - Icon[] allIcons = ie.GetAllIcons(); - Icon biggestIcon = allIcons.OrderByDescending(item => item.Size).First(); - //_originalBitmap = ExtractVistaIcon(biggestIcon); - Bitmap bitmapToReturn = IconUtil.ToBitmap(biggestIcon); - if (bitmapToReturn == null) - bitmapToReturn = biggestIcon.ToBitmap(); - return bitmapToReturn; - */ if (String.IsNullOrWhiteSpace(fileNameAndPath)) return null; - Icon exeIcon = IconUtils.ExtractIcon.ExtractIconFromExecutable(fileNameAndPath); - Bitmap bitmapToReturn = exeIcon.ToBitmap(); - exeIcon.Dispose(); - return bitmapToReturn; - } - private Bitmap ToBitmapFromIcon(string fileNameAndPath) + *//*IconActions ia = new IconActions(); + + int index = 0; + var sb = new StringBuilder(fileNameAndPath, 500); + IconReference iconReference = new IconReference(sb.ToString(), index); + + var largeIcons = new IntPtr[1]; + var smallIcons = new IntPtr[1]; + ia.ExtractIcon(iconReference.FilePath, iconReference.IconIndex, largeIcons, smallIcons, 1); + + System.Windows. + + BitmapSource bitmapSource; + try + { + bitmapSource = Imaging.CreateBitmapSourceFromHIcon(largeIcons[0], Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); + } + catch + { + return null; + } + + ia.DestroyIconAtHandle(largeIcons[0]); + ia.DestroyIconAtHandle(smallIcons[0]); + + return bitmapSource; +*//* + //IconFromFile iconFromFile = new IconFromFile(); + Bitmap bm = IconFromFile.GetLargeBitmapFromFile(fileNameAndPath, true, true); + return bm; + + //var icons = MintPlayer.IconUtils.IconExtractor.Split(fileNameAndPath); + + *//*var folder = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(fileNameAndPath), "Split"); + if (!System.IO.Directory.Exists(folder)) System.IO.Directory.CreateDirectory(folder); + var index = 1; + foreach (var icon in icons) + { + var filename = System.IO.Path.Combine(folder, "icon_" + (index++).ToString() + ".ico"); + using (var fs = new System.IO.FileStream(filename, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite)) + { + icon.Save(fs); + } + } +*//* + + Icon ExeIcon = ExtractIcon.ExtractIconFromExecutable(fileNameAndPath); + FileStream fs = new FileStream(fileNameAndPath, FileMode.Open, FileAccess.Read, FileShare.Read); + MultiIcon mi = new MultiIcon(); + mi.Load(fs); + int count = mi.Count; + TsudaKageyu.IconExtractor ie = new TsudaKageyu.IconExtractor(fileNameAndPath); + Icon[] allIcons = ie.GetAllIcons(); + Icon biggestIcon = allIcons.OrderByDescending(item => item.Size).First(); + //_originalBitmap = ExtractVistaIcon(biggestIcon); + Bitmap bitmapToReturn = IconUtil.ToBitmap(biggestIcon); + if (bitmapToReturn == null) + bitmapToReturn = biggestIcon.ToBitmap(); + + // Only gets the 32x32 icon! + //Icon exeIcon = IconUtils.ExtractIcon.ExtractIconFromExecutable(fileNameAndPath); + //Bitmap bitmapToReturn = exeIcon.ToBitmap(); + //exeIcon.Dispose(); + return bitmapToReturn; + }*/ + +/* public static BitmapSource ConvertBitmap(Bitmap source) + { + return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( + source.GetHbitmap(), + IntPtr.Zero, + Int32Rect.Empty, + BitmapSizeOptions.FromEmptyOptions()); + }*/ + + /*public static Bitmap BitmapFromSource(BitmapSource bitmapsource) + { + Bitmap bitmap; + using (var outStream = new MemoryStream()) + { + BitmapEncoder enc = new BmpBitmapEncoder(); + enc.Frames.Add(BitmapFrame.Create(bitmapsource)); + enc.Save(outStream); + bitmap = new Bitmap(outStream); + } + return bitmap; + }*/ + + /*private Bitmap ToBitmapFromIcon(string fileNameAndPath) { if (String.IsNullOrWhiteSpace(fileNameAndPath)) return null; @@ -859,24 +952,27 @@ namespace HeliosPlus Bitmap bitmapToReturn = icoIcon.ToBitmap(); icoIcon.Dispose(); return bitmapToReturn; - } + }*/ - private Bitmap ToBitmap(string fileNameAndPath) + private Bitmap ToLargeBitmap(string fileNameAndPath) { if (String.IsNullOrWhiteSpace(fileNameAndPath)) return null; - string fileExtension = Path.GetExtension(fileNameAndPath); - if (fileExtension.Equals(".ico",StringComparison.OrdinalIgnoreCase)) - { - return ToBitmapFromIcon(fileNameAndPath); - } - else - { - return ToBitmapFromExe(fileNameAndPath); - } + Bitmap bm = IconFromFile.GetLargeBitmapFromFile(fileNameAndPath, true, true); + return bm; } + private Bitmap ToSmallBitmap(string fileNameAndPath) + { + if (String.IsNullOrWhiteSpace(fileNameAndPath)) + return null; + + Bitmap bm = IconFromFile.GetSmallBitmapFromFile(fileNameAndPath, false, true, false); + return bm; + } + + public Bitmap ToBitmapOverlay(Bitmap originalBitmap, Bitmap overlayBitmap, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb) { @@ -919,7 +1015,7 @@ namespace HeliosPlus return combinedBitmap; } - public MultiIcon ToIcon() + /*public MultiIcon ToIcon() { var iconSizes = new[] { @@ -942,7 +1038,7 @@ namespace HeliosPlus g.InterpolationMode = InterpolationMode.NearestNeighbor; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.CompositingQuality = CompositingQuality.AssumeLinear; - g.DrawImage(_originalBitmap, new Rectangle(0, 0, size.Width, size.Height)); + g.DrawImage(_originalLargeBitmap, new Rectangle(0, 0, size.Width, size.Height)); } icon.Add(bitmap); @@ -957,7 +1053,7 @@ namespace HeliosPlus multiIcon.SelectedIndex = 0; return multiIcon; - } + }*/ public MultiIcon ToIconOverlay() { @@ -975,7 +1071,7 @@ namespace HeliosPlus foreach (var size in iconSizes) { - Bitmap bitmapOverlay = ToBitmapOverlay(_originalBitmap, ProfileToUse.ProfileTightestBitmap, size.Width, size.Height); + Bitmap bitmapOverlay = ToBitmapOverlay(_originalLargeBitmap, ProfileToUse.ProfileTightestBitmap, size.Width, size.Height); icon.Add(bitmapOverlay); if (size.Width >= 256 && size.Height >= 256) @@ -991,6 +1087,112 @@ namespace HeliosPlus return multiIcon; } + /*internal static class ExtractIcon + { + [UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)] + //[SuppressUnmanagedCodeSecurity] + internal delegate bool ENUMRESNAMEPROC(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr LockResource(IntPtr hResData); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + //[SuppressUnmanagedCodeSecurity] + public static extern bool EnumResourceNames(IntPtr hModule, IntPtr lpszType, ENUMRESNAMEPROC lpEnumFunc, IntPtr lParam); + + + private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; + private readonly static IntPtr RT_ICON = (IntPtr)3; + private readonly static IntPtr RT_GROUP_ICON = (IntPtr)14; + + public static Icon ExtractIconFromExecutable(string path) + { + IntPtr hModule = LoadLibraryEx(path, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); + var tmpData = new List(); + + ENUMRESNAMEPROC callback = (h, t, name, l) => + { + var dir = GetDataFromResource(hModule, RT_GROUP_ICON, name); + + // Calculate the size of an entire .icon file. + + int count = BitConverter.ToUInt16(dir, 4); // GRPICONDIR.idCount + int len = 6 + 16 * count; // sizeof(ICONDIR) + sizeof(ICONDIRENTRY) * count + for (int i = 0; i < count; ++i) + len += BitConverter.ToInt32(dir, 6 + 14 * i + 8); // GRPICONDIRENTRY.dwBytesInRes + + using (var dst = new BinaryWriter(new MemoryStream(len))) + { + // Copy GRPICONDIR to ICONDIR. + + dst.Write(dir, 0, 6); + + int picOffset = 6 + 16 * count; // sizeof(ICONDIR) + sizeof(ICONDIRENTRY) * count + + for (int i = 0; i < count; ++i) + { + // Load the picture. + + ushort id = BitConverter.ToUInt16(dir, 6 + 14 * i + 12); // GRPICONDIRENTRY.nID + var pic = GetDataFromResource(hModule, RT_ICON, (IntPtr)id); + + // Copy GRPICONDIRENTRY to ICONDIRENTRY. + + dst.Seek(6 + 16 * i, 0); + + dst.Write(dir, 6 + 14 * i, 8); // First 8bytes are identical. + dst.Write(pic.Length); // ICONDIRENTRY.dwBytesInRes + dst.Write(picOffset); // ICONDIRENTRY.dwImageOffset + + // Copy a picture. + + dst.Seek(picOffset, 0); + dst.Write(pic, 0, pic.Length); + + picOffset += pic.Length; + } + + tmpData.Add(((MemoryStream)dst.BaseStream).ToArray()); + } + return true; + }; + EnumResourceNames(hModule, RT_GROUP_ICON, callback, IntPtr.Zero); + byte[][] iconData = tmpData.ToArray(); + using (var ms = new MemoryStream(iconData[0])) + { + return new Icon(ms); + } + } + private static byte[] GetDataFromResource(IntPtr hModule, IntPtr type, IntPtr name) + { + // Load the binary data from the specified resource. + + IntPtr hResInfo = FindResource(hModule, name, type); + + IntPtr hResData = LoadResource(hModule, hResInfo); + + IntPtr pResData = LockResource(hResData); + + uint size = SizeofResource(hModule, hResInfo); + + byte[] buf = new byte[size]; + Marshal.Copy(pResData, buf, 0, buf.Length); + + return buf; + } + } +*/ public (bool,string) IsValid() { @@ -1171,6 +1373,144 @@ namespace HeliosPlus } + /*internal class IconActions + { + // Constants + // ========= + + private const string Shell32 = "shell32.dll"; + private const string User32 = "user32.dll"; + + // External Methods + // ================ + + [DllImport(Shell32, CharSet = CharSet.Auto)] + private static extern int PickIconDlg(IntPtr hwndOwner, StringBuilder lpstrFile, int nMaxFile, ref int lpdwIconIndex); + + [DllImport(Shell32, CharSet = CharSet.Auto)] + private static extern uint ExtractIconEx(string szFileName, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons); + + [DllImport(User32, CharSet = CharSet.Auto)] + private static extern bool DestroyIcon(IntPtr handle); + + // Methods + // ======= + + public int PickIconDialog(IntPtr hwndOwner, StringBuilder lpstrFile, int nMaxFile, ref int lpdwIconIndex) + { + return PickIconDlg(hwndOwner, lpstrFile, nMaxFile, ref lpdwIconIndex); + } + + public uint ExtractIcon(string szFileName, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons) + { + return ExtractIconEx(szFileName, nIconIndex, phiconLarge, phiconSmall, nIcons); + } + + public bool DestroyIconAtHandle(IntPtr handle) + { + return DestroyIcon(handle); + } + } + + public class IconReference + { + // Constants + // ========= + + private const string comma = ","; + + // Variables + // ========= + + private static readonly Regex regex = new Regex(@".+\,[0-9]+$"); + + // Properties + // ========== + + /// + /// File path to the icon. + /// + public string FilePath { get; private set; } + + /// + /// Index of the icon within the file. + /// + public int IconIndex { get; private set; } + + // Constructors + // ============ + + /// + /// Constructor. + /// + /// A reference for an icon within either an .ico, .exe, or .dll. Must be a valid file location followed by a comma and then an int. + /// Ignore. + public IconReference(string reference) + { + if (!regex.IsMatch(reference)) + { + throw new ArgumentException("[reference] must be a valid file location followed by a comma and then an int"); + } + + string[] split = reference.Split(','); + string index = split[split.Length - 1]; + string filePath = reference.Substring(0, reference.Length - index.Length - 1); + + Setup(filePath, index); + } + + /// + /// Constructor. + /// + /// A valid file location for an .ico, .exe, or .dll. + /// The index of the icon wanted within the file. + public IconReference(string filePath, string index) + { + Setup(filePath, index); + } + + /// + /// Constructor. + /// + /// A valid file location for an .ico, .exe, or .dll. + /// The index of the icon wanted within the file. + public IconReference(string filePath, int index) + { + Setup(filePath, index); + } + + /// + /// Returns the FileName and the IconIndex separated by a comma + /// + /// Returns the FileName and the IconIndex separated by a comma + public override string ToString() + { + return (FilePath ?? string.Empty) + comma + (IconIndex.ToString() ?? string.Empty); + } + + private void Setup(string filepath, string index) + { + if (!int.TryParse(index, out int iconIndex)) + { + throw new ArgumentException("Parameter [index] needs to be castable to an integer"); + } + + Setup(filepath, iconIndex); + } + + private void Setup(string filepath, int index) + { + if (index < 0) + { + throw new ArgumentException("Parameter [index] needs to be greater than or equal to zero"); + } + + FilePath = filepath; + IconIndex = index; + } + }*/ + + #region JsonConverterBitmap internal class CustomBitmapConverter : JsonConverter { diff --git a/HeliosPlus/UIForms/ShortcutForm.cs b/HeliosPlus/UIForms/ShortcutForm.cs index a1dd325..4d0a0bd 100644 --- a/HeliosPlus/UIForms/ShortcutForm.cs +++ b/HeliosPlus/UIForms/ShortcutForm.cs @@ -668,47 +668,34 @@ namespace HeliosPlus.UIForms // Load the Games ListView foreach (var game in SteamLibrary.AllInstalledGames.OrderBy(game => game.Name)) { - if (File.Exists(game.IconPath)) + Bitmap bm = null; + try { - try - { - if (game.IconPath.EndsWith(".ico")) - { - // if it's an icon try to load it as a bitmap - il_games.Images.Add(Image.FromFile(game.IconPath)); - } - else if (game.IconPath.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase) || game.IconPath.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase)) - { - // otherwise use IconExtractor - /*IconExtractor IconEx = new IconExtractor(game.GameIconPath); - Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.*/ - - Icon icoAppIcon = Icon.ExtractAssociatedIcon(game.IconPath); - // We first try high quality icons - Bitmap extractedBitmap = ShortcutItem.ExtractVistaIcon(icoAppIcon); - if (extractedBitmap == null) - extractedBitmap = icoAppIcon.ToBitmap(); - il_games.Images.Add(extractedBitmap); - } - } - catch (Exception ex) - { - Console.WriteLine($"ShortcutForm exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - il_games.Images.Add(Image.FromFile("Resources/Steam.ico")); - } + bm = IconFromFile.GetSmallBitmapFromFile(game.IconPath, false, true, false); } - else + catch (Exception ex) { - //(Icon)global::Calculate.Properties.Resources.ResourceManager.GetObject("Steam.ico"); - il_games.Images.Add(Image.FromFile("Resources/Steam.ico")); + Console.WriteLine($"ShortcutForm exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); } - + try + { + bm = IconFromFile.GetSmallBitmapFromFile(game.ExePath, false, true, false); + } + catch (Exception ex) + { + Console.WriteLine($"ShortcutForm exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); + bm = Properties.Resources.Steam.ToBitmap(); + } + + // Add the images to the images array + il_games.Images.Add(bm); if (!Visible) { return; } + // ADd the game to the game array lv_games.Items.Add(new ListViewItem { Text = game.Name,