v0.4: mic tray icon from mmres.dll, version in form title

This commit is contained in:
2026-08-10 12:39:33 +00:00
parent fbbb52df90
commit 08d6eeb46e
3 changed files with 80 additions and 5 deletions
+56
View File
@@ -0,0 +1,56 @@
using System.Runtime.InteropServices;
namespace Robovoice.App;
internal static class IconExtractor
{
private const string Source = @"%SystemRoot%\System32\mmres.dll";
private static readonly int[] CandidateIndices = { 5, 12 };
public static Icon? TryExtractMicrophone(int size = 32)
{
string path = Environment.ExpandEnvironmentVariables(Source);
if (!File.Exists(path)) return null;
foreach (int index in CandidateIndices)
{
if (ExtractIconAt(path, index, size, size) is { } icon)
return icon;
}
return null;
}
private static Icon? ExtractIconAt(string path, int index, int width, int height)
{
IntPtr[] hicons = new IntPtr[1];
IntPtr[] ids = new IntPtr[1];
int count = PrivateExtractIcons(path, index, width, height, hicons, ids, 1, 0);
if (count <= 0 || hicons[0] == IntPtr.Zero) return null;
try
{
return Icon.FromHandle(hicons[0]);
}
catch
{
DestroyIcon(hicons[0]);
return null;
}
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int PrivateExtractIcons(
string lpszFile,
int nIconIndex,
int cxIcon,
int cyIcon,
IntPtr[] phicon,
IntPtr[] phiconId,
int nIcons,
int flags);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DestroyIcon(IntPtr hIcon);
}
+19 -1
View File
@@ -29,6 +29,7 @@ internal sealed partial class MainForm : Form
_config = AppConfig.Load(); _config = AppConfig.Load();
Directory.CreateDirectory(AppConfig.AppDataDir); Directory.CreateDirectory(AppConfig.AppDataDir);
Directory.CreateDirectory(_voicesDir); Directory.CreateDirectory(_voicesDir);
Text = $"Robovoice {AppVersion}";
Load += OnLoad; Load += OnLoad;
FormClosing += OnFormClosing; FormClosing += OnFormClosing;
} }
@@ -426,12 +427,26 @@ internal sealed partial class MainForm : Form
if (_trayInit) return; if (_trayInit) return;
_trayInit = true; _trayInit = true;
var micIcon = IconExtractor.TryExtractMicrophone();
if (micIcon is not null)
{
_trayIcon = new NotifyIcon
{
Icon = micIcon,
Text = $"Robovoice {AppVersion}",
Visible = true,
};
Icon = micIcon;
}
else
{
_trayIcon = new NotifyIcon _trayIcon = new NotifyIcon
{ {
Icon = SystemIcons.Application, Icon = SystemIcons.Application,
Text = "Robovoice", Text = $"Robovoice {AppVersion}",
Visible = true, Visible = true,
}; };
}
var menu = new ContextMenuStrip(); var menu = new ContextMenuStrip();
menu.Items.Add("Show", null, (_, _) => ShowWindow()); menu.Items.Add("Show", null, (_, _) => ShowWindow());
@@ -444,6 +459,9 @@ internal sealed partial class MainForm : Form
_trayIcon.DoubleClick += (_, _) => ShowWindow(); _trayIcon.DoubleClick += (_, _) => ShowWindow();
} }
private static string AppVersion =>
typeof(MainForm).Assembly.GetName().Version?.ToString() ?? "0.0";
private void OnResize(object? sender, EventArgs e) private void OnResize(object? sender, EventArgs e)
{ {
if (WindowState == FormWindowState.Minimized && chkMinimizeToTray.Checked) if (WindowState == FormWindowState.Minimized && chkMinimizeToTray.Checked)
+1
View File
@@ -17,6 +17,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Version>0.4.0</Version>
</PropertyGroup> </PropertyGroup>
</Project> </Project>