Skip to content

Commit 99a84fe

Browse files
committed
- Enhanced code and user interface
- Enhanced functionality to run on startup and improved package manager support (Chocolatey, Scoop, and WinGet) - Fixed a bug that prevented the "RunOnPriority" setting from being saved. - Improved auto-update feature - Improved string capitalization for non-ASCII languages - Revised some texts for more precise descriptions - Updated the Hungarian language
1 parent 69fc889 commit 99a84fe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2544
-425
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ winget install IgorMundstein.WinMemoryCleaner
2929
| Feature | Description |
3030
|:---|:---|
3131
| **Always on Top** | Pins the main application window so it is always visible above other windows. |
32-
| **Auto Optimization** | Set the app to clean memory automatically, either by period (`Every X hours`) or when free RAM drops below a specified percentage (`When free memory is below X percent`). |
32+
| **Auto Optimization** | Set the app to clean memory automatically, either by period (`Every X hours`) or when free physical RAM drops below a specified threshold (`When free physical memory is below X percent`). |
3333
| **Auto Update** | Automatically checks for new versions every 24 hours to keep the application up to date. |
3434
| **Close after Optimization**| The application will automatically close after a memory optimization is completed. |
3535
| **Close to Notification Area**| Minimizes the app to the system tray instead of closing when the 'X' button is clicked. |
@@ -267,7 +267,7 @@ When new versions require translation updates, we may use AI tools to provide a
267267
| 🇩🇪 German | [Calvin](https://github.com/Slluxx), [Niklas Englmeier](https://github.com/iamniklas), [Steve](https://github.com/uDEV2019) | 🇷🇺 Russian | [Ruslan](https://github.com/ruslooob) |
268268
| 🇬🇷 Greek | [Theodoros Katsageorgis](https://github.com/tkatsageorgis) | 🇷🇸 Serbian | [Dragoš Milošević](https://github.com/DragorMilos) |
269269
| 🇮🇱 Hebrew | [Eliezer Bloy](https://github.com/eliezerbloy) | 🇸🇮 Slovenian | [Jadran Rudec](https://github.com/JadranR) |
270-
| 🇭🇺 Hungarian | [Csizmadia Gyorgy](https://github.com/gycsisz) | 🇪🇸 Spanish | [Ajneb Al Revés](https://github.com/AjnebAlReves), [Fran](https://github.com/FrannDzs) |
270+
| 🇭🇺 Hungarian | [gycsisz](https://github.com/gycsisz) | 🇪🇸 Spanish | [Ajneb Al Revés](https://github.com/AjnebAlReves), [Fran](https://github.com/FrannDzs) |
271271
| 🇮🇩 Indonesian | [Mochammad Misbahus Surur](https://github.com/Eskeyz), [Minids](https://github.com/tdnphantom) | 🇹🇭 Thai | [nongice](https://github.com/21icepril) |
272272
| 🇮🇪 Irish | [Happygolucky254](https://github.com/Happygolucky254) | 🇹🇷 Turkish | [Rıza Emet](https://github.com/rizaemet), [Viollje](https://github.com/Viollje) |
273273
| 🇮🇹 Italian | [Michele](https://github.com/wintrymichi) | 🇺🇦 Ukrainian | [Riebi](https://github.com/RieBi), [Oleksandr](https://github.com/Mariachi1231) |

src/App.xaml

Lines changed: 88 additions & 83 deletions
Large diffs are not rendered by default.

src/App.xaml.cs

Lines changed: 143 additions & 124 deletions
Large diffs are not rendered by default.

src/Converters/NullToVisibilityConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
3636
/// <returns>
3737
/// A converted value. If the method returns null, the valid null value is used.
3838
/// </returns>
39-
/// <exception cref="System.NotImplementedException"></exception>
39+
/// <exception cref="NotImplementedException"></exception>
4040
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
4141
{
4242
throw new NotImplementedException();

src/Core/Constants.cs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.IO;
32

43
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
54

@@ -13,13 +12,14 @@ public static class Constants
1312
public static class App
1413
{
1514
public const int AutoOptimizationMemoryUsageInterval = 5; // Minute
16-
public const int AutoUpdateInterval = 24; // Hour
15+
public const string EmbeddedResourcePath = "WinMemoryCleaner.Resources.";
16+
public const string EmbeddedResourcePathExtension = ".json";
1717
public const string Id = "4B3E3081-D421-4AAC-B3DE-808B1A9CCD30";
1818
public const string KeyFile = "WinMemoryCleaner.snk";
1919
public const string License = "GPL-3.0";
20-
public const string LocalizationResourceExtension = ".json";
21-
public const string LocalizationResourcePath = "WinMemoryCleaner.Resources.Localization.";
20+
public const string LocalizationResourcePath = EmbeddedResourcePath + "Localization.";
2221
public const string Name = "WinMemoryCleaner";
22+
public const string ThemesResourcePath = EmbeddedResourcePath + "Themes.";
2323
public const string Title = "Windows Memory Cleaner";
2424
public const string VersionFormat = "{0}.{1}.{2}";
2525

@@ -28,14 +28,6 @@ public static class Author
2828
public const string Name = "Igor Mundstein";
2929
}
3030

31-
public static class CommandLineArgument
32-
{
33-
public const string Install = "Install";
34-
public const string Package = "Package";
35-
public const string Service = "Service";
36-
public const string Uninstall = "Uninstall";
37-
}
38-
3931
public static class Certificate
4032
{
4133
public static class Release
@@ -49,6 +41,14 @@ public static class Test
4941
}
5042
}
5143

44+
public static class CommandLineArgument
45+
{
46+
public const string Install = "Install";
47+
public const string Package = "Package";
48+
public const string Service = "Service";
49+
public const string Uninstall = "Uninstall";
50+
}
51+
5252
public static class Defaults
5353
{
5454
public static readonly string Path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
@@ -77,11 +77,35 @@ public static class Repository
7777
private const string GitHubRaw = "https://raw.githubusercontent.com/IgorMundstein/WinMemoryCleaner/main";
7878

7979
public static readonly Uri AboutUri = new Uri(GitHub + "?tab=readme-ov-file#windows-memory-cleaner");
80-
public static readonly Uri AssemblyInfoUri = new Uri(Path.Combine(GitHubRaw, "src/Properties/AssemblyInfo.cs"));
80+
public static readonly Uri AssemblyInfoUri = new Uri(GitHubRaw + "/src/Properties/AssemblyInfo.cs");
8181
public static readonly Uri DownloadUri = new Uri(GitHub + "?tab=readme-ov-file#-download");
82-
public static readonly Uri LatestExeUri = new Uri(Path.Combine(GitHub, "releases/latest/download/WinMemoryCleaner.exe"));
82+
public static readonly Uri LatestExeUri = new Uri(GitHub + "/releases/latest/download/WinMemoryCleaner.exe");
8383
public static readonly Uri Uri = new Uri(GitHub);
8484
}
85+
86+
public static class Update
87+
{
88+
public const string BackupDirName = "Backups";
89+
public const int BackupRetentionDays = 3; // Day
90+
public const int CheckInterval = 24; // Hour
91+
public const string ChecksumsFileName = "checksums.txt";
92+
public const int ChecksumsMaxRetries = 3;
93+
public const int ChecksumsRetryDelay = 2; // Second
94+
public const int DownloadTimeout = 60; // Second
95+
public const int MaxConnectionLimit = 10;
96+
public const string MutexName = @"Local\WinMemoryCleaner_AutoUpdate_Mutex";
97+
public const bool RequireAuthenticode = true; // Require Authenticode trust and known thumbprint
98+
public const bool RequireChecksum = true; // Require checksum to be present and matching
99+
public const bool RequireKnownDownloadUri = true; // Require expected HTTPS GitHub URL shape
100+
public const int ReplaceMaxTries = 120; // Count
101+
public const int ReplaceRetryDelayMs = 1000; // Millisecond
102+
public const string TempRootDirName = "WinMemoryCleaner";
103+
public const string TokenEnvVar = "WMC_UPDATE_TOKEN";
104+
public const string TokenFilePrefix = "WMC.";
105+
public const string TokenFileSuffix = ".txt";
106+
public const string UserAgent = "WinMemoryCleaner-Updater/1.0";
107+
public const bool VerifyFileVersionInfo = true;
108+
}
85109
}
86110

87111
public static class Windows
@@ -93,6 +117,7 @@ public static class Attribute
93117
public const int BorderColor = 34;
94118
public const int WindowCornerPreference = 33;
95119
}
120+
96121
public static class Value
97122
{
98123
public const int WindowCornerPreferenceRound = 2;

src/Core/Enums.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ public enum StartupType
9898
Silent,
9999
Uninstallation
100100
}
101+
102+
public enum Theme
103+
{
104+
Dark,
105+
Light
106+
}
101107
}
102108
}
103109

src/Core/ExtensionMethods.cs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public static string Capitalize(this string obj)
2323
: Regex.Replace
2424
(
2525
Localizer.Culture.TextInfo.ToLower(obj),
26-
@"(^|(?<=\.))(\s*)([a-zA-Z])",
26+
@"(^|(?<=\.))(\s*)(\p{L})",
2727
m => m.Groups[1].Value + m.Groups[2].Value + Localizer.Culture.TextInfo.ToUpper(m.Groups[3].Value[0])
2828
);
2929
}
@@ -77,27 +77,6 @@ public static string GetHex(this System.Windows.Media.Color obj, bool includeAlp
7777
return Helper.ToHexCode(obj.R, obj.G, obj.B);
7878
}
7979

80-
/// <summary>
81-
/// Get exception error message.
82-
/// </summary>
83-
/// <param name="obj">The object.</param>
84-
/// <returns></returns>
85-
public static string GetMessage(this Exception obj)
86-
{
87-
var exception = obj;
88-
var messages = new List<string>();
89-
90-
do
91-
{
92-
messages.Add(exception.Message.Trim());
93-
94-
exception = exception.InnerException;
95-
}
96-
while (exception != null);
97-
98-
return string.Join(". ", messages.Distinct());
99-
}
100-
10180
/// <summary>
10281
/// Gets the key value.
10382
/// </summary>
@@ -122,6 +101,40 @@ public static string GetMessage(this Exception obj)
122101
}
123102
}
124103

104+
/// <summary>
105+
/// Returns a compact, de-duplicated message across the exception chain.
106+
/// </summary>
107+
public static string GetMessage(this Exception obj)
108+
{
109+
if (obj == null)
110+
return null;
111+
112+
var exception = obj;
113+
var messages = new List<string>();
114+
115+
do
116+
{
117+
try
118+
{
119+
var message = exception.Message;
120+
121+
if (!string.IsNullOrEmpty(message))
122+
messages.Add(message.Trim());
123+
else
124+
messages.Add(exception.ToString());
125+
}
126+
catch
127+
{
128+
messages.Add(exception.ToString());
129+
}
130+
131+
exception = exception.InnerException;
132+
}
133+
while (exception != null);
134+
135+
return string.Join(". ", messages.Distinct());
136+
}
137+
125138
/// <summary>
126139
/// Gets the reason string.
127140
/// </summary>
@@ -279,4 +292,4 @@ public static Color ToColor(this System.Windows.Media.SolidColorBrush obj)
279292
return new KeyValuePair<double, Enums.Memory.Unit>(obj / Math.Pow(1024, mag), (Enums.Memory.Unit)mag);
280293
}
281294
}
282-
}
295+
}

src/Core/Helper.cs

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using System;
2+
using System.Diagnostics;
3+
using System.IO;
24
using System.Linq.Expressions;
5+
using System.Reflection;
6+
using System.Web.Script.Serialization;
37

48
namespace WinMemoryCleaner
59
{
@@ -8,6 +12,97 @@ namespace WinMemoryCleaner
812
/// </summary>
913
public static class Helper
1014
{
15+
/// <summary>
16+
/// Determines if the current Windows version supports updates via GitHub TLS/SNI.
17+
/// Returns false for legacy Windows versions (XP/2003) that cannot reach GitHub.
18+
/// </summary>
19+
/// <returns>True if updates are supported; otherwise, false.</returns>
20+
public static bool IsAutoUpdateSupported
21+
{
22+
get
23+
{
24+
try
25+
{
26+
var os = Environment.OSVersion;
27+
28+
if (os.Version != null && os.Version.Major < 6)
29+
return false; // Windows XP/2003 and earlier
30+
}
31+
catch
32+
{
33+
}
34+
35+
return true;
36+
}
37+
}
38+
39+
/// <summary>
40+
/// Converts the specified JSON string to an object of type T
41+
/// </summary>
42+
/// <typeparam name="T"></typeparam>
43+
/// <param name="input">The input.</param>
44+
/// <returns></returns>
45+
public static T Deserialize<T>(string input)
46+
{
47+
return new JavaScriptSerializer().Deserialize<T>(input);
48+
}
49+
50+
/// <summary>
51+
/// Creates a directory exists. Ignores failures.
52+
/// </summary>
53+
public static void CreateDirectory(string path)
54+
{
55+
try
56+
{
57+
if (!string.IsNullOrEmpty(path) && !Directory.Exists(path))
58+
Directory.CreateDirectory(path);
59+
}
60+
catch
61+
{
62+
}
63+
}
64+
65+
/// <summary>
66+
/// Gets the current application's assembly version.
67+
/// </summary>
68+
public static Version GetCurrentVersion()
69+
{
70+
try
71+
{
72+
return (Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()).GetName().Version ?? new Version(0, 0, 0, 0);
73+
}
74+
catch
75+
{
76+
return new Version(0, 0, 0, 0);
77+
}
78+
}
79+
80+
/// <summary>
81+
/// Returns the executable path of the current process.
82+
/// </summary>
83+
public static string GetExecutablePath()
84+
{
85+
try
86+
{
87+
var entry = Assembly.GetEntryAssembly();
88+
89+
if (entry != null && !string.IsNullOrEmpty(entry.Location))
90+
return entry.Location;
91+
}
92+
catch
93+
{
94+
}
95+
96+
try
97+
{
98+
return Process.GetCurrentProcess().MainModule.FileName;
99+
}
100+
catch
101+
{
102+
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName);
103+
}
104+
}
105+
11106
/// <summary>
12107
/// Gets the string name of a property or field.
13108
/// </summary>
@@ -27,6 +122,20 @@ public static string NameOf<T>(Expression<Func<T>> expression)
27122
return memberExpression.Member.Name;
28123
}
29124

125+
/// <summary>
126+
/// Reads the embedded resource.
127+
/// </summary>
128+
/// <param name="name">Name of the resource.</param>
129+
/// <returns></returns>
130+
public static T ReadEmbeddedResource<T>(string name)
131+
{
132+
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
133+
using (var reader = new StreamReader(stream))
134+
{
135+
return Deserialize<T>(reader.ReadToEnd());
136+
}
137+
}
138+
30139
/// <summary>
31140
/// Converts to hexcode.
32141
/// </summary>
@@ -43,4 +152,4 @@ public static string ToHexCode(byte red, byte green, byte blue, byte? alpha = nu
43152
return string.Format(Localizer.Culture, "#{0:X2}{1:X2}{2:X2}", red, green, blue);
44153
}
45154
}
46-
}
155+
}

0 commit comments

Comments
 (0)