Coder hai 8 meses
pai
achega
dc1cf6812f

+ 5 - 0
Bmp.WinForms/Bmp.WinForms.csproj

@@ -5,6 +5,7 @@
 		<Nullable>enable</Nullable>
 		<UseWindowsForms>true</UseWindowsForms>
 		<ImplicitUsings>enable</ImplicitUsings>
+		<ApplicationIcon>Icon.ico</ApplicationIcon>
 	</PropertyGroup>
 
 	<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
@@ -16,6 +17,10 @@
 	</PropertyGroup>
 
 	<ItemGroup>
+	  <Content Include="Icon.ico" />
+	</ItemGroup>
+
+	<ItemGroup>
 	  <PackageReference Include="Enums.NET" Version="4.0.1" />
 	</ItemGroup>
 

BIN=BIN
Bmp.WinForms/Icon.ico


+ 10 - 1
Bmp.WinForms/MainForm.cs

@@ -2,6 +2,7 @@ using System.ComponentModel;
 using System.Text;
 using System.Threading.Channels;
 using Bmp.Core.Common.EventBus;
+using Bmp.Core.Common.Win32;
 using Bmp.Core.NAudioExt;
 using Bmp.Core.Playback.Inputs;
 using Bmp.Core.Playback.Outputs;
@@ -52,7 +53,15 @@ namespace Bmp.WinForms
             InitializeComponent();
         }
 
-        private void Initialize() => Text = Const.AppTitle;
+        private void Initialize()
+        {
+            Text = Const.AppTitle;
+            var eIcon = IconExtractor.GetMainIcon();
+            if (null != eIcon)
+            {
+                Icon = eIcon;
+            }
+        }
 
         public void SetServiceProvider(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;
 

+ 191 - 0
Bmp.WinForms/Win32/IconExtractor.cs

@@ -0,0 +1,191 @@
+/*
+ *  IconExtractor/IconUtil for .NET
+ *  Copyright (C) 2014 Tsuda Kageyu. All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System.ComponentModel;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+namespace Bmp.Core.Common.Win32;
+
+public class IconExtractor
+{
+    ////////////////////////////////////////////////////////////////////////
+    // Constants
+
+    // Flags for LoadLibraryEx().
+
+    private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
+
+    // Resource types for EnumResourceNames().
+
+    private static readonly IntPtr RtIcon = (IntPtr)3;
+    private static readonly IntPtr RtGroupIcon = (IntPtr)14;
+
+    ////////////////////////////////////////////////////////////////////////
+    // Fields
+
+    private byte[][] _iconData = null;   // Binary data of each icon.
+
+    ////////////////////////////////////////////////////////////////////////
+    // Public properties
+
+    /// <summary>
+    /// Gets the count of the icons in the associated file.
+    /// </summary>
+    public int Count => _iconData.Length;
+
+    /// <summary>
+    /// Initializes a new instance of the IconExtractor class from the specified file name.
+    /// </summary>
+    /// <param name="fileName">The file to extract icons from.</param>
+    public IconExtractor(string fileName) => Initialize(fileName);
+
+    /// <summary>
+    /// Extracts an icon from the file.
+    /// </summary>
+    /// <param name="index">Zero based index of the icon to be extracted.</param>
+    /// <returns>A System.Drawing.Icon object.</returns>
+    /// <remarks>Always returns new copy of the Icon. It should be disposed by the user.</remarks>
+    public Icon GetIcon(int index)
+    {
+        if (index < 0 || Count <= index) throw new ArgumentOutOfRangeException(nameof(index));
+
+        // Create an Icon based on a .ico file in memory.
+
+        using (var ms = new MemoryStream(_iconData[index])) return new Icon(ms);
+    }
+
+    private void Initialize(string fileName)
+    {
+        if (fileName == null) throw new ArgumentNullException(nameof(fileName));
+
+        var hModule = IntPtr.Zero;
+        try
+        {
+            hModule = NativeMethods.LoadLibraryEx(fileName, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
+            if (hModule == IntPtr.Zero) throw new Win32Exception();
+
+            // Enumerate the icon resource and build .ico files in memory.
+
+            var tmpData = new List<byte[]>();
+
+            bool Callback(IntPtr h, IntPtr t, IntPtr name, IntPtr l)
+            {
+                // Refer the following URL for the data structures used here:
+                // http://msdn.microsoft.com/en-us/library/ms997538.aspx
+
+                // RT_GROUP_ICON resource consists of a GRPICONDIR and GRPICONDIRENTRY's.
+
+                var dir = GetDataFromResource(hModule, RtGroupIcon, name);
+
+                // Calculate the size of an entire .icon file.
+
+                int count = BitConverter.ToUInt16(dir, 4); // GRPICONDIR.idCount
+                var len = 6 + 16 * count; // sizeof(ICONDIR) + sizeof(ICONDIRENTRY) * count
+                for (var 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);
+
+                    var picOffset = 6 + 16 * count; // sizeof(ICONDIR) + sizeof(ICONDIRENTRY) * count
+
+                    for (var i = 0; i < count; ++i)
+                    {
+                        // Load the picture.
+
+                        var id = BitConverter.ToUInt16(dir, 6 + 14 * i + 12); // GRPICONDIRENTRY.nID
+                        var pic = GetDataFromResource(hModule, RtIcon, (IntPtr)id);
+
+                        // Copy GRPICONDIRENTRY to ICONDIRENTRY.
+
+                        dst.Seek(6 + 16 * i, SeekOrigin.Begin);
+
+                        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, SeekOrigin.Begin);
+                        dst.Write(pic, 0, pic.Length);
+
+                        picOffset += pic.Length;
+                    }
+
+                    tmpData.Add(((MemoryStream)dst.BaseStream).ToArray());
+                }
+
+                return true;
+            }
+
+            NativeMethods.EnumResourceNames(hModule, RtGroupIcon, Callback, IntPtr.Zero);
+
+            _iconData = tmpData.ToArray();
+        }
+        finally
+        {
+            if (hModule != IntPtr.Zero) NativeMethods.FreeLibrary(hModule);
+        }
+    }
+
+    private static byte[] GetDataFromResource(IntPtr hModule, IntPtr type, IntPtr name)
+    {
+        // Load the binary data from the specified resource.
+
+        var hResInfo = NativeMethods.FindResource(hModule, name, type);
+        if (hResInfo == IntPtr.Zero)
+            throw new Win32Exception();
+
+        var hResData = NativeMethods.LoadResource(hModule, hResInfo);
+        if (hResData == IntPtr.Zero)
+            throw new Win32Exception();
+
+        var pResData = NativeMethods.LockResource(hResData);
+        if (pResData == IntPtr.Zero)
+            throw new Win32Exception();
+
+        var size = NativeMethods.SizeofResource(hModule, hResInfo);
+        if (size == 0)
+            throw new Win32Exception();
+
+        var buf = new byte[size];
+        Marshal.Copy(pResData, buf, 0, buf.Length);
+
+        return buf;
+    }
+
+    public static Icon? GetMainIcon()
+    {
+        var iex = new IconExtractor(Application.ExecutablePath);
+        return iex.Count > 0 ? iex.GetIcon(0) : null;
+    }
+}

+ 39 - 0
Bmp.WinForms/Win32/NativeMethod.cs

@@ -0,0 +1,39 @@
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace Bmp.Core.Common.Win32;
+
+internal static class NativeMethods
+{
+    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
+
+    [DllImport("kernel32.dll", SetLastError = true)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern bool FreeLibrary(IntPtr hModule);
+
+    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern bool EnumResourceNames(IntPtr hModule, IntPtr lpszType, Enumresnameproc lpEnumFunc, IntPtr lParam);
+
+    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType);
+
+    [DllImport("kernel32.dll", SetLastError = true)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
+
+    [DllImport("kernel32.dll", SetLastError = true)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern IntPtr LockResource(IntPtr hResData);
+
+    [DllImport("kernel32.dll", SetLastError = true)]
+    [SuppressUnmanagedCodeSecurity]
+    public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
+}
+
+[UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
+[SuppressUnmanagedCodeSecurity]
+internal delegate bool Enumresnameproc(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam);