34 Commits
Author SHA1 Message Date
BelimandGitHub 252f1d1119 Update to 1.30.243 2025-12-25 13:59:35 +01:00
BelimandGitHub 5a54950382 Update to 1.18.200 2025-07-09 16:58:08 +02:00
BelimandGitHub 209b2b59e0 Update to 1.17.177 2025-06-28 09:23:35 +02:00
BelimandGitHub ed7db8a8c4 Update README.md 2025-06-24 21:54:43 +02:00
Belim 01f11c7de7 Merge branch 'main' of https://github.com/builtbybel/Crapfixer 2025-06-24 19:23:23 +02:00
Belim c8502bfa7f Push 1.16-dev_branch 2025-06-24 19:23:13 +02:00
BelimandGitHub 1044c009a4 Update README.md 2025-06-20 18:53:55 +02:00
BelimandGitHub d85345eb41 Update to 1.16.156 2025-06-20 11:31:29 +02:00
BelimandGitHub 736dfb570a Update README.md 2025-06-14 20:22:29 +02:00
BelimandGitHub 748d7a972e Update to 1.15.137 2025-06-14 12:58:45 +02:00
BelimandGitHub 7b10d810bd Update README.md 2025-06-13 18:06:48 +02:00
BelimandGitHub af9556139b m Update zoicware @https://github.com/zoicware/RemoveWindowsAI 2025-06-12 21:46:39 +02:00
BelimandGitHub 410f9c5d75 Update zoicware @https://github.com/zoicware 2025-06-12 21:41:39 +02:00
BelimandGitHub 5f782bbc13 Add tools .ico 2025-06-12 17:24:36 +02:00
BelimandGitHub 125d38c608 Update to 1.14.126 2025-06-12 17:16:28 +02:00
BelimandGitHub 5276214773 Update update-check.html 2025-06-12 17:06:19 +02:00
BelimandGitHub 74ed54bbcd Update to 1.13.103 2025-06-09 12:54:49 +02:00
BelimandGitHub b1c7dac2ce Add Global hide via wildcard to CFEnhancer 2025-06-07 19:39:03 +02:00
BelimandGitHub 28ce4de343 Add changelog link to update-check.html 2025-06-03 20:07:33 +02:00
BelimandGitHub c85ca879cc Update update-check.html 2025-06-03 20:05:00 +02:00
BelimandGitHub 00c9d17786 Add changlog link to update-check.html 2025-06-03 20:03:27 +02:00
BelimandGitHub 532c94a0e0 Push 1.12.92 2025-06-03 17:12:34 +02:00
BelimandGitHub 8e7db90bbc Add files via upload 2025-06-03 15:01:09 +02:00
BelimandGitHub 841c638b62 Add files via upload 2025-06-03 14:59:45 +02:00
BelimandGitHub 81a8bb3dc9 Delete icons/options_d.png 2025-06-03 12:15:47 +02:00
BelimandGitHub 0c0fde335e Add files via upload 2025-06-03 12:15:34 +02:00
BelimandGitHub 0f5da5fbe9 Include Icon pack 2025-06-03 11:43:19 +02:00
BelimandGitHub 4b052de9fa Update to 1.11.71 2025-05-31 16:26:26 +02:00
Belim 60ccd48a59 Update update-check.html 2025-05-29 15:17:40 +02:00
Belim 3edf8f654b Merge branch 'main' of https://github.com/builtbybel/Crapfixer 2025-05-29 15:15:26 +02:00
Belim e7997f8093 Update to 1.10.58 2025-05-29 15:15:23 +02:00
BelimandGitHub e2aedfe1c0 Update update-check.html 2025-05-29 09:09:55 +02:00
BelimandGitHub 83f0d63225 Update README.md 2025-05-29 08:42:30 +02:00
BelimandGitHub 9d9b3ed478 Update to 1.6.300 2025-05-26 12:41:18 +02:00
40 changed files with 2537 additions and 1065 deletions
+85 -30
View File
@@ -9,7 +9,6 @@ using Windows.Management.Deployment;
namespace CrapFixer
{
public class AppAnalysisResult
{
public string AppName { get; set; }
@@ -43,13 +42,18 @@ namespace CrapFixer
}
/// <summary>
/// Analyzes the apps based on predefined apps (from resources) and logs the results in MainForm.
/// Analyzes the installed apps against provided bloatware patterns and whitelist,
/// logs the results, and returns the matches.
/// </summary>
/// <param name="predefinedApps"></param>
/// <returns></returns>
public async Task<List<AppAnalysisResult>> AnalyzeAndLogAppsAsync(string[] predefinedApps)
/// <param name="bloatwarePatterns">List of bloatware keywords to check against</param>
/// <param name="whitelistPatterns">List of app names to ignore</param>
/// <param name="scanAll">If true, scans all apps regardless of bloatware patterns</param>
public async Task<List<AppAnalysisResult>> AnalyzeAndLogAppsAsync(
string[] bloatwarePatterns,
string[] whitelistPatterns,
bool scanAll)
{
var apps = await AnalyzeAppsAsync(predefinedApps);
var apps = await AnalyzeAppsAsync(bloatwarePatterns, whitelistPatterns, scanAll);
if (apps.Count > 0)
{
@@ -64,37 +68,56 @@ namespace CrapFixer
Logger.Log("✅ No Microsoft Store bloatware apps found.", LogLevel.Info);
}
Logger.Log(""); // Add a blank line for spacing
return apps;
}
/// <summary>
/// Analyzes the apps based on predefined apps (from resources) and returns matching apps.
/// </summary>
/// <param name="predefinedApps"></param>
/// <returns></returns>
public async Task<List<AppAnalysisResult>> AnalyzeAppsAsync(string[] predefinedApps)
public async Task<List<AppAnalysisResult>> AnalyzeAppsAsync(string[] bloatwarePatterns, string[] whitelistPatterns, bool scanAll = false)
{
Logger.Log("\n🧩 APPS ANALYSIS", LogLevel.Info);
Logger.Log(new string('=', 50), LogLevel.Info);
await LoadAppsAsync(); // Load all apps before analysis
await LoadAppsAsync(); // Load all installed apps
var result = new List<AppAnalysisResult>();
// Check each app's name against predefined patterns
foreach (var app in _appDirectory)
{
foreach (string pattern in predefinedApps)
string appName = app.Key.ToLower();
// Always skip whitelisted apps
if (whitelistPatterns.Any(w => appName.Contains(w)))
continue;
if (scanAll)
{
if (app.Key.ToLower().Contains(pattern.ToLower()))
// If wildcard is set, include everything not whitelisted
result.Add(new AppAnalysisResult
{
result.Add(new AppAnalysisResult
AppName = app.Key,
FullName = app.Value
});
}
else
{
// Only match against provided patterns
foreach (var pattern in bloatwarePatterns)
{
if (appName.Contains(pattern))
{
AppName = app.Key,
FullName = app.Value // Store the full name
});
break;
result.Add(new AppAnalysisResult
{
AppName = app.Key,
FullName = app.Value
});
break;
}
}
}
}
@@ -171,39 +194,71 @@ namespace CrapFixer
return removedApps; // Return removed apps to update the UI
}
/// <summary>
/// Loads an external bloatware list from the CFEnhancer text file (comma-separated).
/// Falls back to an empty array if the file doesn't exist or fails to load.
/// Loads external bloatware and whitelist patterns from a text file (e.g., CFEnhancer.txt).
/// Also checks if wildcard (*) is set to scan all apps.
/// </summary>
public string[] LoadExternalBloatwareList(string fileName = "CFEnhancer.txt")
/// <param name="fileName">Name of the file to load from (must be in Plugins folder)</param>
/// <returns>
/// A tuple containing:
/// - bloatwarePatterns: List of apps to flag as bloatware
/// - whitelistPatterns: List of apps to ignore/exclude from detection
/// - scanAll: Whether all apps should be shown regardless of matching patterns
/// </returns>
public (string[] bloatwarePatterns, string[] whitelistPatterns, bool scanAll) LoadExternalBloatwarePatterns(string fileName = "CFEnhancer.txt")
{
try
{
string exeDir = AppDomain.CurrentDomain.BaseDirectory;
string pluginsDir = Path.Combine(exeDir, "plugins");
string fullPath = Path.Combine(pluginsDir, fileName);
string fullPath = Path.Combine(exeDir, "Plugins", fileName);
if (!File.Exists(fullPath))
{
Logger.Log($"⚠️ The bloatware radar stays basic for now 🧠. Get the CFEnhancer detection list from Options > Plugins ", LogLevel.Warning);
return Array.Empty<string>();
Logger.Log($"⚠️ The bloatware radar stays basic for now 🧠. Get the enhanced detection list from Options > Plugins > CFEnhancer plugin", LogLevel.Warning);
return (Array.Empty<string>(), Array.Empty<string>(), false);
}
var content = File.ReadAllText(fullPath);
return content.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim())
.ToArray();
var lines = File.ReadAllLines(fullPath);
var bloatware = new List<string>(); // Apps to detect as bloatware
var whitelist = new List<string>(); // Apps to ignore completely
bool scanAll = false; // Set to true if wildcard (*) is present
foreach (var line in lines)
{
// Strip comments after "#" and trim whitespace
var entry = line.Split('#')[0].Trim();
// Skip empty lines or lines with only comments
if (string.IsNullOrWhiteSpace(entry))
continue;
// Wildcard entry means: show all installed apps
if (entry == "*" || entry == "*.*")
{
scanAll = true;
continue;
}
// Entries starting with "!" go to the whitelist (excluded apps)
if (entry.StartsWith("!"))
whitelist.Add(entry.Substring(1).Trim().ToLower());
else
bloatware.Add(entry.ToLower()); // All other entries are bloatware patterns
}
return (bloatware.ToArray(), whitelist.ToArray(), scanAll);
}
catch (Exception ex)
{
Logger.Log($"Error reading external bloatware file: {ex.Message}", LogLevel.Warning);
return Array.Empty<string>();
return (Array.Empty<string>(), Array.Empty<string>(), false);
}
}
/// <summary>
/// OPTIONALLY!Returns all installed apps in the system.
/// OPTIONALLY!Returns all installed apps in the system.
/// </summary>
/// <returns></returns>
public async Task<List<AppAnalysisResult>> GetAllInstalledAppsAsync()
+18 -7
View File
@@ -7,7 +7,7 @@
<ProjectGuid>{FA7D5C89-63D3-4AF0-80C2-D650D35E575B}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>CFixer</RootNamespace>
<AssemblyName>CFixer</AssemblyName>
<AssemblyName>Crap Fixer</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
@@ -57,7 +57,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AppManagerService.cs" />
<Compile Include="Features\AI\AskCopilot.cs" />
<Compile Include="Features\AI\ClickToDo.cs" />
<Compile Include="Features\FeatureManager.cs" />
<Compile Include="Features\Edge\BrowserSignin.cs" />
<Compile Include="Features\Edge\DefaultTopSites.cs" />
@@ -78,6 +78,7 @@
<Compile Include="Features\System\SpeedUpShutdown.cs" />
<Compile Include="Features\System\SystemResponsiveness.cs" />
<Compile Include="Features\System\TaskbarEndTask.cs" />
<Compile Include="Features\UI\BingSearch.cs" />
<Compile Include="Features\UI\DarkMode.cs" />
<Compile Include="Features\UI\SearchBoxSuggestions.cs" />
<Compile Include="Features\UI\SnapAssistFlyout.cs" />
@@ -128,6 +129,11 @@
<Compile Include="Features\UI\ShowTaskViewButton.cs" />
<Compile Include="Features\UI\StartLayout.cs" />
<Compile Include="Features\UI\TaskbarAlignment.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Views\AboutView.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -152,6 +158,12 @@
<Compile Include="Views\OptionsView.Designer.cs">
<DependentUpon>OptionsView.cs</DependentUpon>
</Compile>
<Compile Include="Views\ViveView.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Views\ViveView.Designer.cs">
<DependentUpon>ViveView.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
@@ -162,6 +174,7 @@
</EmbeddedResource>
<EmbeddedResource Include="Views\AboutView.resx">
<DependentUpon>AboutView.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Views\PluginsView.resx">
<DependentUpon>PluginsView.cs</DependentUpon>
@@ -172,17 +185,15 @@
<EmbeddedResource Include="Views\OptionsView.resx">
<DependentUpon>OptionsView.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Views\ViveView.resx">
<DependentUpon>ViveView.cs</DependentUpon>
</EmbeddedResource>
<None Include="app.manifest" />
<Compile Include="Features\FeatureLoader.cs" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
+70
View File
@@ -0,0 +1,70 @@
using Microsoft.Win32;
using System;
using System.Threading.Tasks;
using CrapFixer;
namespace Settings.UI
{
/// <summary>
/// Disables the Click to Do feature, which also removes its entry from the right-click context menu.
/// Only available on Copilot+ PCs running Windows 11 24H2 or newer.
/// Requires a PC with an NPU (Neural Processing Unit).
/// </summary>
internal class ClickToDo: FeatureBase
{
private const string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\ClickToDo";
private const string valueName = "DisableClickToDo";
private const int recommendedValue = 1; // 1 = fully disabled, including context menu
public override string GetFeatureDetails()
{
return $"{keyName} | Value: {valueName} | Set to: {recommendedValue} (disables Click to Do, removing it from context menus). " +
"Note: This setting only applies on Copilot+ PCs with Windows 11 24H2 or newer.";
}
public override string ID()
{
return "Disable Click to Do (Only Copilot+ PCs)";
}
public override string Info()
{
return "Disables Click to Do entirely, including its context menu entry which uses on-device AI to suggest actions based on screen content. Only available on Copilot+ PCs with Windows 11 24H2 or newer.";
}
public override Task<bool> CheckFeature()
{
return Task.FromResult(Utils.IntEquals(keyName, valueName, recommendedValue));
}
public override Task<bool> DoFeature()
{
try
{
Registry.SetValue(keyName, valueName, recommendedValue, RegistryValueKind.DWord);
return Task.FromResult(true);
}
catch (Exception ex)
{
Logger.Log("Error disabling Click to Do: " + ex.Message, LogLevel.Error);
return Task.FromResult(false);
}
}
public override bool UndoFeature()
{
try
{
Registry.SetValue(keyName, valueName, 0, RegistryValueKind.DWord);
return true;
}
catch (Exception ex)
{
Logger.Log("Error re-enabling Click to Do: " + ex.Message, LogLevel.Error);
return false;
}
}
}
}
+5 -4
View File
@@ -1,13 +1,13 @@
using Settings.Issues;
using Settings.Ads;
using Settings.Ads;
using Settings.AI;
using Settings.Edge;
using Settings.Gaming;
using Settings.Issues;
using Settings.Personalization;
using Settings.Privacy;
using Settings.System;
using System.Collections.Generic;
using Settings.UI;
using System.Collections.Generic;
namespace Features
{
@@ -69,6 +69,7 @@ namespace Features
new FeatureNode(new ShowOrHideMostUsedApps()),
new FeatureNode(new ShowTaskViewButton()),
new FeatureNode(new DisableSearchBoxSuggestions()),
new FeatureNode(new DisableBingSearch()),
new FeatureNode(new StartLayout()),
new FeatureNode(new TaskbarAlignment()),
new FeatureNode(new Transparency()),
@@ -121,7 +122,7 @@ namespace Features
{
new FeatureNode(new CopilotTaskbar()),
new FeatureNode(new Recall()),
new FeatureNode(new AskCopilot()),
new FeatureNode(new ClickToDo()) { DefaultChecked = false },
}
},
};
+88 -54
View File
@@ -1,5 +1,6 @@
using Features;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -16,12 +17,14 @@ namespace CrapFixer
// Public properties to access the analysis results
public static int TotalChecked => totalChecked;
public static int IssuesFound => issuesFound;
public static void ResetAnalysis()
{
totalChecked = 0;
issuesFound = 0;
Logger.Clear();
}
/// <summary>
@@ -29,6 +32,9 @@ namespace CrapFixer
/// </summary>
public static void LoadFeatures(TreeView tree)
{
// Hide the TreeView to avoid flickering and visible scroll jump
tree.Visible = false;
var features = FeatureLoader.Load();
tree.Nodes.Clear();
@@ -43,6 +49,14 @@ namespace CrapFixer
}
tree.ExpandAll(); // expand all nodes
// Set scroll to top and make TreeView visible
tree.BeginInvoke(new Action(() =>
{
// Ensure the first node is shown at the top (prevents auto-scroll to bottom)
if (tree.Nodes.Count > 0) tree.TopNode = tree.Nodes[0];
tree.Visible = true;
}));
}
/// <summary>
@@ -166,52 +180,75 @@ namespace CrapFixer
RestoreChecked(child);
}
}
/// <summary>
/// Analyzes a selected feature and logs its status.
/// Analyzes a selected feature or, if it's a category, analyzes only checked child features.
/// </summary>
public static async void AnalyzeFeature(TreeNode node)
{
// no && node.Checked
// Analyze this node if it's a leaf node (not a category)
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
{
bool isOk = await fn.Feature.CheckFeature();
node.ForeColor = isOk ? Color.Gray : Color.Red;
Logger.Log(isOk
? $"✅ Feature: {fn.Name} is properly configured."
: $" Feature: {fn.Name} requires attention.\n ➤ {fn.Feature.GetFeatureDetails()}",
isOk ? LogLevel.Info : LogLevel.Warning);
if (!isOk)
if (isOk)
{
Logger.Log($" Feature: {fn.Name} is properly configured.", LogLevel.Info);
}
else
{
string category = node.Parent?.Text ?? "General";
Logger.Log($"❌ Feature: {fn.Name} requires attention.", LogLevel.Warning);
Logger.Log($" ➤ {fn.Feature.GetFeatureDetails()}");
Logger.Log(new string('-', 50), LogLevel.Info);
}
}
else
{
// If it's a category node, analyze only checked child nodes
foreach (TreeNode child in node.Nodes)
{
if (child.Checked)
AnalyzeFeature(child);
}
}
}
/// <summary>
/// Attempts to fix the selected feature and logs the result.
/// Attempts to fix the selected feature or, if it is a category, fixes only checked child features.
/// </summary>
public static async Task FixFeature(TreeNode node)
{
// no && node.Checked
// Try to fix this node if it is NOT a category (i.e., a leaf node)
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
{
// Always fix the selected leaf node, regardless of Checked
bool result = await fn.Feature.DoFeature();
Logger.Log(result
? $"🔧 {fn.Name} - Fixed"
: $"❌ {fn.Name} - ⚠️ Fix failed (This feature may require admin privileges)",
result ? LogLevel.Info : LogLevel.Error);
}
else
{
// If it's a category node, fix only checked child nodes (recursively)
foreach (TreeNode child in node.Nodes)
{
if (child.Checked)
await FixFeature(child);
}
}
}
/// <summary>
/// Restores the selected feature to its original state and logs the result.
/// Restores a selected feature (always) or, if it's a category, only restores checked child features.
/// Logs success or failure.
/// </summary>
public static void RestoreFeature(TreeNode node)
{
// no && node.Checked
// Restore feature node regardless of Checked state
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
{
bool ok = fn.Feature.UndoFeature();
@@ -220,38 +257,26 @@ namespace CrapFixer
: $"❌ {fn.Name} - Restore failed",
ok ? LogLevel.Info : LogLevel.Error);
}
}
/// <summary>
/// Recursively previews changes for all checked features.
/// </summary>
/// <param name="node"></param>
public static void PreviewChanges(TreeNode node)
{
if (node.Tag is FeatureNode fn)
else
{
if (!fn.IsCategory && fn.Feature != null)
{
string details = fn.Feature.GetFeatureDetails();
string category = node.Parent?.Text ?? "General";
Logger.Log($"🛈 [PREVIEW] [{category}] {fn.Name}", LogLevel.Info);
Logger.Log($" ➤ {details}");
Logger.Log(new string('-', 50), LogLevel.Info);
}
// For category nodes, only restore checked children
foreach (TreeNode child in node.Nodes)
PreviewChanges(child);
{
if (child.Checked)
RestoreFeature(child);
}
}
}
/// <summary>
/// Displays help information for the selected feature.
/// Displays help information for the selected feature or plugin.
/// If a feature is selected, also offers to search online.
/// </summary>
public static void ShowHelp(TreeNode node)
{
if (node.Tag is FeatureNode fn && fn.Feature != null)
// Show help for features
if (node?.Tag is FeatureNode fn && fn.Feature != null)
{
string info = fn.Feature.Info();
MessageBox.Show(
@@ -259,27 +284,36 @@ namespace CrapFixer
$"Help: {fn.Name}",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
// Optional online help
var result = MessageBox.Show(
"Would you like to search online for more information about this feature?",
"Online Help",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
string searchQuery = Uri.EscapeDataString(fn.Feature.GetFeatureDetails());
string webUrl = $"https://www.google.com/search?q={searchQuery}";
System.Diagnostics.Process.Start(new ProcessStartInfo
{
FileName = webUrl,
UseShellExecute = true
});
}
return;
}
else
// Show help for plugins
if (!PluginManager.ShowHelp(node))
{
MessageBox.Show("⚠️ No feature selected or feature is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBox.Show("⚠️ No feature or plugin selected, or help info unavailable.",
"Help",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}
/// <summary>
/// Opens the default web browser to search for help online for the selected feature (Extended ShowHelp).
/// </summary>
/// <param name="node"></param>
public static void ShowHelpOnline(TreeNode node)
{
if (node?.Tag is FeatureNode fn)
{
string searchQuery = Uri.EscapeDataString( fn.Feature.GetFeatureDetails());
string webUrl = $"microsoft-edge:https://www.google.com/search?q={searchQuery}";
System.Diagnostics.Process.Start(webUrl);
}
}
}
}
+6 -12
View File
@@ -23,7 +23,6 @@ namespace Settings.Issues
var totalSize = GetDirectorySize(tempPath);
bool isOk = totalSize <= 50;
return Task.FromResult(isOk);
}
@@ -34,13 +33,12 @@ namespace Settings.Issues
}
}
public override string GetFeatureDetails()
{
try
{
var totalSize = GetDirectorySize(tempPath);
return $"Temp folder size: {totalSize} MB (We need also to include cleanmgr in the next run)";
return $"Temp folder size: {totalSize} MB (including cleanmgr /sagerun:1 in the next run)";
}
catch (Exception ex)
{
@@ -53,7 +51,7 @@ namespace Settings.Issues
{
try
{
await CleanTempFolderAsync();
await CleanTempFolderAsync();
await RunDiskCleanup();
Logger.Log("Basic Cleanup completed successfully.", LogLevel.Info);
return true;
@@ -65,7 +63,6 @@ namespace Settings.Issues
}
}
private async Task CleanTempFolderAsync()
{
var files = await Task.Run(() => Directory.GetFiles(tempPath, "*", SearchOption.AllDirectories));
@@ -75,7 +72,7 @@ namespace Settings.Issues
{
try
{
await Task.Run(() => File.Delete(file));
await Task.Run(() => File.Delete(file));
Logger.Log($"Deleted file: {file}", LogLevel.Info);
}
catch (Exception ex)
@@ -98,7 +95,6 @@ namespace Settings.Issues
}
}
// calculate the size of the directory in MB
private long GetDirectorySize(string directory)
{
@@ -110,7 +106,6 @@ namespace Settings.Issues
// Calculate size of all files
size += directoryInfo.GetFiles("*", SearchOption.AllDirectories).Sum(file => file.Length);
return size / (1024 * 1024); // return size in MB
}
catch (Exception ex)
@@ -144,13 +139,13 @@ namespace Settings.Issues
using (var process1 = Process.Start(startInfo1))
{
if (process1 != null)
await Task.Run(() => process1.WaitForExit());
await Task.Run(() => process1.WaitForExit());
}
using (var process2 = Process.Start(startInfo2))
{
if (process2 != null)
await Task.Run(() => process2.WaitForExit());
await Task.Run(() => process2.WaitForExit());
}
}
catch (Exception ex)
@@ -159,8 +154,7 @@ namespace Settings.Issues
}
}
// Undo method: Cleanup cannot be undone, so return false
public override bool UndoFeature() => false;
}
}
}
+6 -5
View File
@@ -1,7 +1,8 @@
using System;
using CrapFixer;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading.Tasks;
using CrapFixer;
namespace Settings.System
{
@@ -29,9 +30,9 @@ namespace Settings.System
try
{
string output = await ExecuteCommand("winget upgrade --include-unknown");
string output = await ExecuteCommand("winget upgrade --include-unknown" );
Logger.Log("Winget upgrade check:\n" + output, LogLevel.Info);
Logger.Log("Winget upgrade check:\n" + output, LogLevel.Info, new Font("Cascadia Mono", 8.25f));
return output.ToLower().Contains("available");
}
@@ -122,4 +123,4 @@ namespace Settings.System
return tcs.Task;
}
}
}
}
+62
View File
@@ -0,0 +1,62 @@
using Microsoft.Win32;
using System;
using System.Threading.Tasks;
using CrapFixer;
namespace Settings.UI
{
internal class DisableBingSearch : FeatureBase
{
private const string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Search";
private const string valueName = "BingSearchEnabled";
private const int recommendedValue = 0;
public override string GetFeatureDetails()
{
return $"{keyName} | Value: {valueName} | Recommended Value: {recommendedValue}";
}
public override string ID()
{
return "Disable Bing Search";
}
public override string Info()
{
return "This feature disables Bing integration in Windows Search.";
}
public override Task<bool> CheckFeature()
{
return Task.FromResult(Utils.IntEquals(keyName, valueName, recommendedValue));
}
public override Task<bool> DoFeature()
{
try
{
Registry.SetValue(keyName, valueName, recommendedValue, RegistryValueKind.DWord);
return Task.FromResult(true);
}
catch (Exception ex)
{
Logger.Log("Error in DisableBingSearch: " + ex.Message, LogLevel.Error);
return Task.FromResult(false);
}
}
public override bool UndoFeature()
{
try
{
Registry.SetValue(keyName, valueName, 1, RegistryValueKind.DWord);
return true;
}
catch (Exception ex)
{
Logger.Log("Error undoing DisableBingSearch: " + ex.Message, LogLevel.Error);
return false;
}
}
}
}
+40 -6
View File
@@ -7,25 +7,37 @@ using System.Windows.Forms;
/// </summary>
public static class Logger
{
/// <summary>
/// The RichTextBox control to which log messages are written.
/// </summary>
public static RichTextBox OutputBox;
private static readonly Font DefaultFont = new Font("Consolas", 8.25f, FontStyle.Regular);
private static readonly Font DefaultFont = new Font("Tahoma", 8.25f, FontStyle.Regular);
public static void Log(string message, LogLevel level = LogLevel.Info)
/// <summary>
/// Writes a message with an optional log level and custom font.
/// </summary>
/// <param name="message">The message to display.</param>
/// <param name="level">The log level (e.g., Info, Warning, Error).</param>
/// <param name="customFont">An optional font for the message.</param>
public static void Log(string message, LogLevel level = LogLevel.Info, Font customFont = null)
{
if (OutputBox == null) return;
if (OutputBox.InvokeRequired)
{
OutputBox.Invoke(new Action(() => LogInternal(message, level)));
OutputBox.Invoke(new Action(() => LogInternal(message, level, customFont)));
}
else
{
LogInternal(message, level);
LogInternal(message, level, customFont);
}
}
private static void LogInternal(string message, LogLevel level)
/// <summary>
/// Internal method to append text to the RichTextBox with formatting.
/// </summary>
private static void LogInternal(string message, LogLevel level, Font customFont = null)
{
// string prefix = $"[{DateTime.Now:HH:mm:ss}] [{level}] ";
string fullMessage = message + Environment.NewLine;
@@ -51,10 +63,11 @@ public static class Logger
break;
}
// Append text with color
// Append formatted message
OutputBox.SelectionStart = OutputBox.TextLength;
OutputBox.SelectionLength = 0;
OutputBox.SelectionColor = color;
OutputBox.SelectionFont = customFont ?? DefaultFont; // use custom font if provided, otherwise use default
OutputBox.AppendText(fullMessage);
// Reset selection to default
@@ -62,8 +75,29 @@ public static class Logger
OutputBox.SelectionFont = DefaultFont; // reset font
OutputBox.ScrollToCaret(); // scroll to the end
}
/// <summary>
/// Clears the log output.
/// </summary>
public static void Clear()
{
if (OutputBox == null || OutputBox.IsDisposed)
return;
if (OutputBox.InvokeRequired)
{
OutputBox.Invoke(new Action(Clear));
return;
}
OutputBox.Clear();
OutputBox.SelectionColor = Color.Black;
}
}
/// <summary>
/// Log level types used to define message severity.
/// </summary>
public enum LogLevel
{
Info,
+46 -20
View File
@@ -1,9 +1,9 @@
using System.Collections.ObjectModel;
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Threading.Tasks;
using Microsoft.Win32;
// This file is part of CFixer.
namespace OSHelper
{
internal class OSHelper
@@ -14,37 +14,63 @@ namespace OSHelper
{
try
{
using (PowerShell powerShellInstance = PowerShell.Create())
using (PowerShell ps = PowerShell.Create())
{
powerShellInstance.AddScript("Get-CimInstance -ClassName Win32_OperatingSystem");
Collection<PSObject> psOutput = powerShellInstance.Invoke();
ps.AddScript("Get-CimInstance -ClassName Win32_OperatingSystem");
var results = ps.Invoke();
foreach (PSObject outputItem in psOutput)
foreach (var result in results)
{
if (outputItem != null)
{
string productName = outputItem.Properties["Caption"]?.Value?.ToString();
if (!string.IsNullOrEmpty(productName))
{
string osVersion = productName.Contains("Windows 10") ? "Windows 10" : "Windows 11";
if (result == null) continue;
using (RegistryKey displayVersionKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
string caption = result.Properties["Caption"]?.Value?.ToString();
string version = result.Properties["Version"]?.Value?.ToString();
string build = result.Properties["BuildNumber"]?.Value?.ToString();
string displayVersion = Registry.GetValue(
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion",
"DisplayVersion", "")?.ToString();
// UBR = Update Build Revision
string ubr = Registry.GetValue(
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion",
"UBR", 0)?.ToString();
bool isInsider = false;
string ring = null;
using (var insiderKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\UpdateOrchestrator"))
{
if (insiderKey != null)
{
object enabled = insiderKey.GetValue("EnableInsiderBuilds");
if (enabled != null && Convert.ToInt32(enabled) == 1)
{
if (displayVersionKey != null)
{
string displayVersion = displayVersionKey.GetValue("DisplayVersion")?.ToString();
return $"{osVersion} ({displayVersion})";
}
isInsider = true;
ring = insiderKey.GetValue("Ring")?.ToString();
}
return osVersion;
}
}
string osName = caption?.Contains("Windows 11") == true ? "Windows 11" :
caption?.Contains("Windows 10") == true ? "Windows 10" :
caption ?? "Unknown OS";
string fullBuild = !string.IsNullOrEmpty(build) && !string.IsNullOrEmpty(ubr)
? $"{build}.{ubr}"
: build ?? "unknown";
string insiderInfo = isInsider ? $" (Insider: {ring})" : "";
return $"{osName} {displayVersion}{insiderInfo} (Build {fullBuild})";
}
}
}
catch
catch (Exception ex)
{
return $"OS info unavailable: {ex.Message}";
}
return "OS not supported";
});
}
+33 -26
View File
@@ -3,55 +3,65 @@ using System;
using System.Diagnostics;
using System.Windows.Forms;
// This file is part of CFixer.
namespace CrapFixer
{
internal class Utils
internal static class Utils
{
private const string GitHubUrl = "https://github.com/builtbybel/CrapFixer";
/// <summary>
/// Checks if a registry value is equal to a specified integer.
/// Checks if a registry value equals a specified integer.
/// </summary>
/// <param name="keyName"></param>
/// <param name="valueName"></param>
/// <param name="expectedValue"></param>
/// <returns></returns>
public static bool IntEquals(string keyName, string valueName, int expectedValue)
{
try
{
var value = Registry.GetValue(keyName, valueName, null);
return (value != null && (int)value == expectedValue);
object value = Registry.GetValue(keyName, valueName, null);
return value is int intValue && intValue == expectedValue;
}
catch (Exception ex)
{
MessageBox.Show(keyName, ex.Message, MessageBoxButtons.OK);
Logger.Log($"Registry check failed for {keyName}\\{valueName}: {ex.Message}", LogLevel.Error);
return false;
}
}
/// <summary>
/// Checks if a registry value is equal to a specified string.
/// Checks if a registry value equals a specified string.
/// </summary>
/// <param name="keyName"></param>
/// <param name="valueName"></param>
/// <param name="expectedValue"></param>
/// <returns></returns>
public static bool StringEquals(string keyName, string valueName, string expectedValue)
{
try
{
var value = Registry.GetValue(keyName, valueName, null);
return (value != null && (string)value == expectedValue);
object value = Registry.GetValue(keyName, valueName, null);
return value is string strValue && strValue == expectedValue;
}
catch (Exception ex)
{
MessageBox.Show(keyName, ex.Message, MessageBoxButtons.OK);
Logger.Log($"Registry check failed for {keyName}\\{valueName}: {ex.Message}", LogLevel.Error);
return false;
}
}
/// <summary>
/// Opens the GitHub project page in the default browser.
/// </summary>
public static void OpenGitHubPage(object sender, EventArgs e)
{
try
{
Process.Start(new ProcessStartInfo
{
FileName = GitHubUrl,
UseShellExecute = true
});
}
catch (Exception ex)
{
Logger.Log($"Failed to open GitHub page: {ex.Message}", LogLevel.Error);
}
}
/// <summary>
/// Restarts Windows Explorer to apply UI changes.
/// </summary>
@@ -61,22 +71,19 @@ namespace CrapFixer
{
Logger.Log("Restarting Windows Explorer to apply UI changes...", LogLevel.Info);
// Kill all explorer instances
foreach (var process in Process.GetProcessesByName("explorer"))
{
process.Kill();
process.WaitForExit();
}
// Restart explorer
Process.Start("explorer.exe");
Logger.Log("Explorer restarted successfully. Changes should now be visible.", LogLevel.Info);
Logger.Log("Explorer restarted successfully.", LogLevel.Info);
}
catch (Exception ex)
{
Logger.Log("Failed to restart Explorer: " + ex.Message, LogLevel.Error);
Logger.Log($"Failed to restart Explorer: {ex.Message}", LogLevel.Error);
}
}
}
}
}
+82 -22
View File
@@ -27,7 +27,9 @@ public static class IniStateManager
lines.Add("[APP]");
lines.Add($"Width={form.Width}");
lines.Add($"Height={form.Height}");
lines.Add(""); // empty line for spacing
lines.Add($"Top={form.Top}");
lines.Add($"Left={form.Left}");
// lines.Add(""); // empty line for spacing
// Append new FEATURES section (TreeView nodes states)
lines.Add("[FEATURES]");
@@ -62,8 +64,75 @@ public static class IniStateManager
}
}
// Loads global states (App size, TreeView nodes states) from the INI file
public static void Load(TreeView tree, Form form)
// Loads the global states (App size, TreeView nodes states) if enabled
public static void LoadFeaturesIfEnabled(TreeView tree)
{
if (IsViewSettingEnabled("SETTINGS", "checkSaveToINI"))
LoadFeatureStates(tree);
}
public static void ApplyWindowState(Form form)
{
if (File.Exists(IniPath))
{
// Load window size and position from INI file
LoadWindowState(form);
form.StartPosition = FormStartPosition.Manual;
}
else
{
// If INI file doesn't exist, set default position
form.StartPosition = FormStartPosition.CenterScreen;
}
}
// Loads only the window size and position from the INI file
public static void LoadWindowState(Form form)
{
if (!File.Exists(IniPath)) return;
var lines = File.ReadAllLines(IniPath);
var section = "";
foreach (var line in lines)
{
var trimmed = line.Trim();
if (string.IsNullOrWhiteSpace(trimmed)) continue;
// Check if line is a section header
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
{
section = trimmed;
continue;
}
if (section == "[APP]")
{
// Split line into key and value
var parts = trimmed.Split(new[] { '=' }, 2);
if (parts.Length != 2) continue;
var key = parts[0].Trim();
var value = parts[1].Trim();
// Parse and apply window size and position
if (int.TryParse(value, out int size))
{
if (key.Equals("Width", StringComparison.OrdinalIgnoreCase))
form.Width = size;
else if (key.Equals("Height", StringComparison.OrdinalIgnoreCase))
form.Height = size;
else if (key.Equals("Top", StringComparison.OrdinalIgnoreCase))
form.Top = size;
else if (key.Equals("Left", StringComparison.OrdinalIgnoreCase))
form.Left = size;
}
}
}
}
// Loads only the feature states (TreeView node checked states) from the INI file
public static void LoadFeatureStates(TreeView tree)
{
if (!File.Exists(IniPath)) return;
@@ -76,37 +145,28 @@ public static class IniStateManager
var trimmed = line.Trim();
if (string.IsNullOrWhiteSpace(trimmed)) continue;
// Check if line is a section
// Check if line is a section header
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
{
section = trimmed;
continue;
}
// Split line into key and value
var parts = trimmed.Split(new[] { '=' }, 2);
if (parts.Length != 2) continue;
var key = parts[0].Trim();
var value = parts[1].Trim();
if (section == "[FEATURES]")
{
// Split line into key and value
var parts = trimmed.Split(new[] { '=' }, 2);
if (parts.Length != 2) continue;
var key = parts[0].Trim();
var value = parts[1].Trim();
// Save checked state for each feature node
states[key] = value.ToLower() == "true";
}
else if (section == "[APP]")
{
if (int.TryParse(value, out int size))
{
if (key.Equals("Width", StringComparison.OrdinalIgnoreCase))
form.Width = size;
else if (key.Equals("Height", StringComparison.OrdinalIgnoreCase))
form.Height = size;
}
}
}
// Apply saved feature states to tree nodes
// Apply saved feature states to the TreeView nodes recursively
ApplyStates(tree.Nodes, states);
}
+131 -107
View File
@@ -29,7 +29,6 @@
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.panelContainer = new System.Windows.Forms.Panel();
this.panelContent = new System.Windows.Forms.Panel();
this.btnAnalyze = new System.Windows.Forms.Button();
@@ -38,10 +37,9 @@
this.treeFeatures = new System.Windows.Forms.TreeView();
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.analyzeMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.previewMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fixMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.seperatorToolStripMenuItem = new System.Windows.Forms.ToolStripSeparator();
this.restoreMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.seperatorToolStripMenuItem = new System.Windows.Forms.ToolStripSeparator();
this.helpMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.Apps = new System.Windows.Forms.TabPage();
this.checkedListBoxApps = new System.Windows.Forms.CheckedListBox();
@@ -50,15 +48,17 @@
this.rtbLogger = new System.Windows.Forms.RichTextBox();
this.btnFix = new System.Windows.Forms.Button();
this.panelHeader = new System.Windows.Forms.Panel();
this.btnGitHub = new System.Windows.Forms.Button();
this.lblOSInfo = new System.Windows.Forms.Label();
this.lblVersionInfo = new System.Windows.Forms.Label();
this.lblHeader = new System.Windows.Forms.Label();
this.pictureHeader = new System.Windows.Forms.PictureBox();
this.btnRestore = new System.Windows.Forms.Button();
this.linkUpdateCheck = new System.Windows.Forms.LinkLabel();
this.btnSettings = new System.Windows.Forms.Button();
this.btnHome = new System.Windows.Forms.Button();
this.btnTools = new System.Windows.Forms.Button();
this.btnFixer = new System.Windows.Forms.Button();
this.linkSelection = new System.Windows.Forms.LinkLabel();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.panelContainer.SuspendLayout();
this.panelContent.SuspendLayout();
this.tabControl.SuspendLayout();
@@ -77,15 +77,15 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.panelContainer.BackColor = System.Drawing.SystemColors.Control;
this.panelContainer.Controls.Add(this.panelContent);
this.panelContainer.Location = new System.Drawing.Point(99, 62);
this.panelContainer.Location = new System.Drawing.Point(90, 69);
this.panelContainer.Name = "panelContainer";
this.panelContainer.Size = new System.Drawing.Size(611, 382);
this.panelContainer.Size = new System.Drawing.Size(613, 375);
this.panelContainer.TabIndex = 198;
//
// panelContent
//
this.panelContent.AutoScroll = true;
this.panelContent.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
this.panelContent.BackColor = System.Drawing.Color.White;
this.panelContent.Controls.Add(this.btnAnalyze);
this.panelContent.Controls.Add(this.tabControl);
this.panelContent.Controls.Add(this.groupBox);
@@ -93,7 +93,7 @@
this.panelContent.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelContent.Location = new System.Drawing.Point(0, 0);
this.panelContent.Name = "panelContent";
this.panelContent.Size = new System.Drawing.Size(611, 382);
this.panelContent.Size = new System.Drawing.Size(613, 375);
this.panelContent.TabIndex = 205;
//
// btnAnalyze
@@ -102,7 +102,7 @@
this.btnAnalyze.AutoEllipsis = true;
this.btnAnalyze.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.btnAnalyze.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnAnalyze.Location = new System.Drawing.Point(280, 346);
this.btnAnalyze.Location = new System.Drawing.Point(268, 339);
this.btnAnalyze.Name = "btnAnalyze";
this.btnAnalyze.Size = new System.Drawing.Size(121, 29);
this.btnAnalyze.TabIndex = 1;
@@ -116,45 +116,42 @@
| System.Windows.Forms.AnchorStyles.Left)));
this.tabControl.Controls.Add(this.Windows);
this.tabControl.Controls.Add(this.Apps);
this.tabControl.HotTrack = true;
this.tabControl.Location = new System.Drawing.Point(0, 0);
this.tabControl.ItemSize = new System.Drawing.Size(68, 21);
this.tabControl.Location = new System.Drawing.Point(7, 5);
this.tabControl.Name = "tabControl";
this.tabControl.Padding = new System.Drawing.Point(20, 8);
this.tabControl.SelectedIndex = 0;
this.tabControl.ShowToolTips = true;
this.tabControl.Size = new System.Drawing.Size(270, 376);
this.tabControl.SizeMode = System.Windows.Forms.TabSizeMode.Fixed;
this.tabControl.Size = new System.Drawing.Size(255, 363);
this.tabControl.SizeMode = System.Windows.Forms.TabSizeMode.FillToRight;
this.tabControl.TabIndex = 199;
//
// Windows
//
this.Windows.AutoScroll = true;
this.Windows.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.Windows.Controls.Add(this.treeFeatures);
this.Windows.Location = new System.Drawing.Point(4, 32);
this.Windows.Location = new System.Drawing.Point(4, 25);
this.Windows.Name = "Windows";
this.Windows.Padding = new System.Windows.Forms.Padding(3);
this.Windows.Size = new System.Drawing.Size(262, 340);
this.Windows.Size = new System.Drawing.Size(247, 334);
this.Windows.TabIndex = 0;
this.Windows.Text = "Windows";
//
// treeFeatures
//
this.treeFeatures.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(242)))), ((int)(((byte)(242)))));
this.treeFeatures.BackColor = System.Drawing.Color.White;
this.treeFeatures.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.treeFeatures.CheckBoxes = true;
this.treeFeatures.ContextMenuStrip = this.contextMenuStrip;
this.treeFeatures.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeFeatures.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.treeFeatures.Indent = 20;
this.treeFeatures.ItemHeight = 23;
this.treeFeatures.Location = new System.Drawing.Point(3, 3);
this.treeFeatures.Location = new System.Drawing.Point(0, 0);
this.treeFeatures.Name = "treeFeatures";
this.treeFeatures.ShowLines = false;
this.treeFeatures.ShowNodeToolTips = true;
this.treeFeatures.ShowPlusMinus = false;
this.treeFeatures.ShowRootLines = false;
this.treeFeatures.Size = new System.Drawing.Size(256, 334);
this.treeFeatures.TabIndex = 196;
this.treeFeatures.Size = new System.Drawing.Size(247, 334);
this.treeFeatures.TabIndex = 0;
this.treeFeatures.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeFeatures_AfterCheck);
this.treeFeatures.MouseDown += new System.Windows.Forms.MouseEventHandler(this.treeFeatures_MouseDown);
//
@@ -162,14 +159,13 @@
//
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.analyzeMarkedFeatureToolStripMenuItem,
this.previewMarkedFeatureToolStripMenuItem,
this.fixMarkedFeatureToolStripMenuItem,
this.seperatorToolStripMenuItem,
this.restoreMarkedFeatureToolStripMenuItem,
this.seperatorToolStripMenuItem,
this.helpMarkedFeatureToolStripMenuItem});
this.contextMenuStrip.Name = "contextManualMenu";
this.contextMenuStrip.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
this.contextMenuStrip.Size = new System.Drawing.Size(119, 120);
this.contextMenuStrip.Size = new System.Drawing.Size(119, 98);
//
// analyzeMarkedFeatureToolStripMenuItem
//
@@ -178,13 +174,6 @@
this.analyzeMarkedFeatureToolStripMenuItem.Text = "Analyze";
this.analyzeMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.analyzeMarkedFeatureToolStripMenuItem_Click);
//
// previewMarkedFeatureToolStripMenuItem
//
this.previewMarkedFeatureToolStripMenuItem.Name = "previewMarkedFeatureToolStripMenuItem";
this.previewMarkedFeatureToolStripMenuItem.Size = new System.Drawing.Size(118, 22);
this.previewMarkedFeatureToolStripMenuItem.Text = "Preview";
this.previewMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.previewMarkedFeatureToolStripMenuItem_Click);
//
// fixMarkedFeatureToolStripMenuItem
//
this.fixMarkedFeatureToolStripMenuItem.Name = "fixMarkedFeatureToolStripMenuItem";
@@ -192,11 +181,6 @@
this.fixMarkedFeatureToolStripMenuItem.Text = "Fix";
this.fixMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.fixMarkedFeatureToolStripMenuItem_Click);
//
// seperatorToolStripMenuItem
//
this.seperatorToolStripMenuItem.Name = "seperatorToolStripMenuItem";
this.seperatorToolStripMenuItem.Size = new System.Drawing.Size(115, 6);
//
// restoreMarkedFeatureToolStripMenuItem
//
this.restoreMarkedFeatureToolStripMenuItem.Name = "restoreMarkedFeatureToolStripMenuItem";
@@ -204,6 +188,11 @@
this.restoreMarkedFeatureToolStripMenuItem.Text = "Restore";
this.restoreMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.restoreMarkedFeatureToolStripMenuItem_Click);
//
// seperatorToolStripMenuItem
//
this.seperatorToolStripMenuItem.Name = "seperatorToolStripMenuItem";
this.seperatorToolStripMenuItem.Size = new System.Drawing.Size(115, 6);
//
// helpMarkedFeatureToolStripMenuItem
//
this.helpMarkedFeatureToolStripMenuItem.Name = "helpMarkedFeatureToolStripMenuItem";
@@ -214,30 +203,28 @@
//
// Apps
//
this.Apps.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(242)))), ((int)(((byte)(242)))));
this.Apps.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.Apps.Controls.Add(this.checkedListBoxApps);
this.Apps.Location = new System.Drawing.Point(4, 32);
this.Apps.Location = new System.Drawing.Point(4, 25);
this.Apps.Name = "Apps";
this.Apps.Padding = new System.Windows.Forms.Padding(3);
this.Apps.Size = new System.Drawing.Size(262, 340);
this.Apps.Size = new System.Drawing.Size(247, 334);
this.Apps.TabIndex = 1;
this.Apps.Text = "Apps";
this.Apps.Text = "Applications";
//
// checkedListBoxApps
//
this.checkedListBoxApps.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(242)))), ((int)(((byte)(242)))));
this.checkedListBoxApps.BackColor = System.Drawing.Color.White;
this.checkedListBoxApps.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.checkedListBoxApps.Dock = System.Windows.Forms.DockStyle.Fill;
this.checkedListBoxApps.Font = new System.Drawing.Font("Tahoma", 8F);
this.checkedListBoxApps.FormattingEnabled = true;
this.checkedListBoxApps.Items.AddRange(new object[] {
"No analysis yet"});
this.checkedListBoxApps.Location = new System.Drawing.Point(3, 3);
this.checkedListBoxApps.Location = new System.Drawing.Point(0, 0);
this.checkedListBoxApps.Name = "checkedListBoxApps";
this.checkedListBoxApps.Size = new System.Drawing.Size(256, 334);
this.checkedListBoxApps.Size = new System.Drawing.Size(247, 334);
this.checkedListBoxApps.Sorted = true;
this.checkedListBoxApps.TabIndex = 336;
this.checkedListBoxApps.ThreeDCheckBoxes = true;
//
// groupBox
//
@@ -247,9 +234,10 @@
this.groupBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
this.groupBox.Controls.Add(this.comboLogActions);
this.groupBox.Controls.Add(this.rtbLogger);
this.groupBox.Location = new System.Drawing.Point(280, 21);
this.groupBox.ForeColor = System.Drawing.SystemColors.ControlDarkDark;
this.groupBox.Location = new System.Drawing.Point(268, 21);
this.groupBox.Name = "groupBox";
this.groupBox.Size = new System.Drawing.Size(320, 317);
this.groupBox.Size = new System.Drawing.Size(334, 310);
this.groupBox.TabIndex = 200;
this.groupBox.TabStop = false;
//
@@ -257,13 +245,14 @@
//
this.comboLogActions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.comboLogActions.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.comboLogActions.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboLogActions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.comboLogActions.Font = new System.Drawing.Font("Tahoma", 8.25F);
this.comboLogActions.FormattingEnabled = true;
this.comboLogActions.Location = new System.Drawing.Point(7, 292);
this.comboLogActions.Location = new System.Drawing.Point(7, 285);
this.comboLogActions.Name = "comboLogActions";
this.comboLogActions.Size = new System.Drawing.Size(305, 21);
this.comboLogActions.Size = new System.Drawing.Size(319, 21);
this.comboLogActions.TabIndex = 210;
this.comboLogActions.Visible = false;
//
@@ -274,13 +263,13 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.rtbLogger.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
this.rtbLogger.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.rtbLogger.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.rtbLogger.Location = new System.Drawing.Point(7, 12);
this.rtbLogger.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.rtbLogger.Location = new System.Drawing.Point(7, 19);
this.rtbLogger.Name = "rtbLogger";
this.rtbLogger.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
this.rtbLogger.Size = new System.Drawing.Size(305, 273);
this.rtbLogger.Size = new System.Drawing.Size(319, 263);
this.rtbLogger.TabIndex = 195;
this.rtbLogger.Text = "";
this.rtbLogger.WordWrap = false;
//
// btnFix
//
@@ -288,7 +277,7 @@
this.btnFix.AutoEllipsis = true;
this.btnFix.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.btnFix.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnFix.Location = new System.Drawing.Point(480, 346);
this.btnFix.Location = new System.Drawing.Point(482, 339);
this.btnFix.Name = "btnFix";
this.btnFix.Size = new System.Drawing.Size(121, 29);
this.btnFix.TabIndex = 2;
@@ -299,6 +288,7 @@
// panelHeader
//
this.panelHeader.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(77)))), ((int)(((byte)(77)))));
this.panelHeader.Controls.Add(this.btnGitHub);
this.panelHeader.Controls.Add(this.lblOSInfo);
this.panelHeader.Controls.Add(this.lblVersionInfo);
this.panelHeader.Controls.Add(this.lblHeader);
@@ -310,21 +300,42 @@
this.panelHeader.TabIndex = 204;
this.panelHeader.Paint += new System.Windows.Forms.PaintEventHandler(this.panelHeader_Paint);
//
// btnGitHub
//
this.btnGitHub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnGitHub.AutoSize = true;
this.btnGitHub.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnGitHub.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
this.btnGitHub.FlatAppearance.BorderSize = 0;
this.btnGitHub.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnGitHub.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnGitHub.ForeColor = System.Drawing.Color.Gainsboro;
this.btnGitHub.Location = new System.Drawing.Point(657, 7);
this.btnGitHub.Name = "btnGitHub";
this.btnGitHub.Size = new System.Drawing.Size(40, 40);
this.btnGitHub.TabIndex = 201;
this.btnGitHub.TabStop = false;
this.toolTip.SetToolTip(this.btnGitHub, "Love CrapFixer? Its open source — but your support keeps it alive! 💖");
this.btnGitHub.UseVisualStyleBackColor = true;
this.btnGitHub.Click += new System.EventHandler(this.btnGitHub_Click);
//
// lblOSInfo
//
this.lblOSInfo.AutoSize = true;
this.lblOSInfo.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F);
this.lblOSInfo.BackColor = System.Drawing.Color.Transparent;
this.lblOSInfo.Font = new System.Drawing.Font("Tahoma", 7.6F);
this.lblOSInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(230)))), ((int)(((byte)(230)))));
this.lblOSInfo.Location = new System.Drawing.Point(90, 37);
this.lblOSInfo.Name = "lblOSInfo";
this.lblOSInfo.Size = new System.Drawing.Size(116, 13);
this.lblOSInfo.Size = new System.Drawing.Size(120, 13);
this.lblOSInfo.TabIndex = 200;
this.lblOSInfo.Text = "Checking your system..";
//
// lblVersionInfo
//
this.lblVersionInfo.AutoSize = true;
this.lblVersionInfo.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.5F);
this.lblVersionInfo.BackColor = System.Drawing.Color.Transparent;
this.lblVersionInfo.Font = new System.Drawing.Font("Tahoma", 7.6F);
this.lblVersionInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(230)))), ((int)(((byte)(230)))));
this.lblVersionInfo.Location = new System.Drawing.Point(198, 15);
this.lblVersionInfo.Name = "lblVersionInfo";
@@ -335,6 +346,8 @@
// lblHeader
//
this.lblHeader.AutoEllipsis = true;
this.lblHeader.BackColor = System.Drawing.Color.Transparent;
this.lblHeader.Cursor = System.Windows.Forms.Cursors.Hand;
this.lblHeader.Font = new System.Drawing.Font("Tahoma", 14F, System.Drawing.FontStyle.Bold);
this.lblHeader.ForeColor = System.Drawing.Color.White;
this.lblHeader.Location = new System.Drawing.Point(89, 9);
@@ -342,29 +355,35 @@
this.lblHeader.Size = new System.Drawing.Size(117, 25);
this.lblHeader.TabIndex = 1;
this.lblHeader.Text = "CrapFixer";
this.toolTip.SetToolTip(this.lblHeader, "Click here to visit the CrapFixer website at github.com/builtbybel/crapfixer");
this.lblHeader.UseCompatibleTextRendering = true;
//
// pictureHeader
//
this.pictureHeader.Image = ((System.Drawing.Image)(resources.GetObject("pictureHeader.Image")));
this.pictureHeader.BackColor = System.Drawing.Color.Transparent;
this.pictureHeader.Cursor = System.Windows.Forms.Cursors.Hand;
this.pictureHeader.Image = global::CFixer.Properties.Resources.AppIcon;
this.pictureHeader.InitialImage = null;
this.pictureHeader.Location = new System.Drawing.Point(30, 9);
this.pictureHeader.Name = "pictureHeader";
this.pictureHeader.Size = new System.Drawing.Size(44, 41);
this.pictureHeader.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureHeader.TabIndex = 0;
this.pictureHeader.TabStop = false;
this.toolTip.SetToolTip(this.pictureHeader, "Click here to visit the CrapFixer website at github.com/builtbybel/crapfixer");
//
// btnRestore
//
this.btnRestore.AutoEllipsis = true;
this.btnRestore.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnRestore.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(114)))), ((int)(((byte)(114)))), ((int)(((byte)(114)))));
this.btnRestore.Cursor = System.Windows.Forms.Cursors.Default;
this.btnRestore.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
this.btnRestore.FlatAppearance.BorderSize = 0;
this.btnRestore.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnRestore.Font = new System.Drawing.Font("Tahoma", 8.25F);
this.btnRestore.ForeColor = System.Drawing.Color.White;
this.btnRestore.Location = new System.Drawing.Point(0, 129);
this.btnRestore.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnRestore.ForeColor = System.Drawing.Color.Gainsboro;
this.btnRestore.Location = new System.Drawing.Point(10, 142);
this.btnRestore.Name = "btnRestore";
this.btnRestore.Size = new System.Drawing.Size(99, 69);
this.btnRestore.Size = new System.Drawing.Size(80, 60);
this.btnRestore.TabIndex = 198;
this.btnRestore.TabStop = false;
this.btnRestore.Text = "&Restore";
@@ -379,46 +398,48 @@
this.linkUpdateCheck.AutoSize = true;
this.linkUpdateCheck.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.linkUpdateCheck.LinkColor = System.Drawing.Color.White;
this.linkUpdateCheck.Location = new System.Drawing.Point(595, 447);
this.linkUpdateCheck.Location = new System.Drawing.Point(590, 447);
this.linkUpdateCheck.Name = "linkUpdateCheck";
this.linkUpdateCheck.Size = new System.Drawing.Size(95, 13);
this.linkUpdateCheck.Size = new System.Drawing.Size(107, 13);
this.linkUpdateCheck.TabIndex = 203;
this.linkUpdateCheck.TabStop = true;
this.linkUpdateCheck.Text = "Check for updates";
this.linkUpdateCheck.TextAlign = System.Drawing.ContentAlignment.TopCenter;
this.linkUpdateCheck.Text = "Check for updates...";
this.linkUpdateCheck.TextAlign = System.Drawing.ContentAlignment.TopCenter;
this.linkUpdateCheck.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkUpdateCheck_LinkClicked);
//
// btnSettings
// btnTools
//
this.btnSettings.AutoEllipsis = true;
this.btnSettings.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnSettings.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(114)))), ((int)(((byte)(114)))), ((int)(((byte)(114)))));
this.btnSettings.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnSettings.Font = new System.Drawing.Font("Tahoma", 8.25F);
this.btnSettings.ForeColor = System.Drawing.Color.White;
this.btnSettings.Location = new System.Drawing.Point(0, 197);
this.btnSettings.Name = "btnSettings";
this.btnSettings.Size = new System.Drawing.Size(99, 69);
this.btnSettings.TabIndex = 205;
this.btnSettings.TabStop = false;
this.btnSettings.Text = "&Options";
this.btnSettings.UseVisualStyleBackColor = true;
this.btnTools.AutoEllipsis = true;
this.btnTools.Cursor = System.Windows.Forms.Cursors.Default;
this.btnTools.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
this.btnTools.FlatAppearance.BorderSize = 0;
this.btnTools.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnTools.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnTools.ForeColor = System.Drawing.Color.Gainsboro;
this.btnTools.Location = new System.Drawing.Point(10, 210);
this.btnTools.Name = "btnTools";
this.btnTools.Size = new System.Drawing.Size(80, 60);
this.btnTools.TabIndex = 205;
this.btnTools.TabStop = false;
this.btnTools.Text = "&Tools";
this.btnTools.UseVisualStyleBackColor = true;
//
// btnHome
// btnFixer
//
this.btnHome.AutoEllipsis = true;
this.btnHome.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(145)))), ((int)(((byte)(235)))));
this.btnHome.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnHome.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(66)))), ((int)(((byte)(131)))), ((int)(((byte)(222)))));
this.btnHome.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnHome.Font = new System.Drawing.Font("Tahoma", 8.25F);
this.btnHome.ForeColor = System.Drawing.Color.White;
this.btnHome.Location = new System.Drawing.Point(0, 61);
this.btnHome.Name = "btnHome";
this.btnHome.Size = new System.Drawing.Size(99, 69);
this.btnHome.TabIndex = 206;
this.btnHome.TabStop = false;
this.btnHome.Text = "&Fixer";
this.btnHome.UseVisualStyleBackColor = false;
this.btnFixer.AutoEllipsis = true;
this.btnFixer.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(150)))), ((int)(((byte)(200)))), ((int)(((byte)(240)))));
this.btnFixer.Cursor = System.Windows.Forms.Cursors.Default;
this.btnFixer.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
this.btnFixer.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnFixer.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnFixer.ForeColor = System.Drawing.Color.Gainsboro;
this.btnFixer.Location = new System.Drawing.Point(10, 74);
this.btnFixer.Name = "btnFixer";
this.btnFixer.Size = new System.Drawing.Size(80, 60);
this.btnFixer.TabIndex = 206;
this.btnFixer.TabStop = false;
this.btnFixer.Text = "&Fixer";
this.btnFixer.UseVisualStyleBackColor = false;
//
// linkSelection
//
@@ -441,15 +462,17 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(104)))), ((int)(((byte)(104)))), ((int)(((byte)(104)))));
this.AutoScroll = true;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(103)))), ((int)(((byte)(103)))), ((int)(((byte)(103)))));
this.ClientSize = new System.Drawing.Size(710, 466);
this.Controls.Add(this.linkSelection);
this.Controls.Add(this.btnHome);
this.Controls.Add(this.btnSettings);
this.Controls.Add(this.btnFixer);
this.Controls.Add(this.btnTools);
this.Controls.Add(this.panelHeader);
this.Controls.Add(this.btnRestore);
this.Controls.Add(this.linkUpdateCheck);
this.Controls.Add(this.panelContainer);
this.MinimumSize = new System.Drawing.Size(642, 337);
this.Name = "MainForm";
this.ShowIcon = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
@@ -495,13 +518,14 @@
private System.Windows.Forms.Panel panelContent;
private System.Windows.Forms.LinkLabel linkUpdateCheck;
private System.Windows.Forms.ToolStripMenuItem helpMarkedFeatureToolStripMenuItem;
private System.Windows.Forms.TreeView treeFeatures;
private System.Windows.Forms.Label lblOSInfo;
private System.Windows.Forms.Button btnSettings;
private System.Windows.Forms.Button btnHome;
private System.Windows.Forms.Button btnTools;
private System.Windows.Forms.Button btnFixer;
private System.Windows.Forms.LinkLabel linkSelection;
private System.Windows.Forms.ToolStripMenuItem previewMarkedFeatureToolStripMenuItem;
private System.Windows.Forms.ComboBox comboLogActions;
private System.Windows.Forms.TreeView treeFeatures;
private System.Windows.Forms.Button btnGitHub;
private System.Windows.Forms.ToolTip toolTip;
}
}
+124 -97
View File
@@ -4,6 +4,7 @@ using CFixer.Views;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -21,6 +22,7 @@ namespace CrapFixer
public MainForm()
{
InitializeComponent();
IniStateManager.ApplyWindowState(this);
// Set up the main navigation manager and logger
_navigationManager = new NavigationManager(panelContainer);
@@ -28,66 +30,67 @@ namespace CrapFixer
// Set up log actions controller
_logActions = new LogActions(rtbLogger);
_logActionsController = new LogActionsController(comboLogActions, _logActions);
}
// Load features and plugins, and restore INI state if enabled
private async void MainForm_Shown(object sender, EventArgs e)
{
await InitializeUI(); // _ = InitializeUI();
InitializeAppState();
}
private void InitializeAppState()
{
// Load features and plugins into the tree view
FeatureNodeManager.LoadFeatures(treeFeatures);
PluginManager.LoadPlugins(treeFeatures);
if (IniStateManager.IsViewSettingEnabled("SETTINGS", "checkSaveToINI"))
{
IniStateManager.Load(treeFeatures, this);
}
// Load settings from INI file if enabled
IniStateManager.LoadFeaturesIfEnabled(treeFeatures);
}
private void MainForm_Shown(object sender, EventArgs e)
private async Task InitializeUI()
{
InitializeUI();
}
// Initialize the navigation handler with buttons
_navigationHandler = new NavigationHandler(btnFixer, btnRestore, btnTools, btnGitHub);
private void InitializeUI()
{
// Set the default active button
_navigationHandler = new NavigationHandler(btnHome, btnSettings);
_navigationHandler.NavigationButtonClicked += button =>
{
if (button == btnHome)
{
_navigationManager.GoToMain();
}
else if (button == btnSettings)
{
_navigationManager.SwitchView(new OptionsView());
}
};
// Load navigation icons
await _navigationHandler.LoadNavigationIcons();
// Set up link label for update check
linkUpdateCheck.LinkClicked += (_, __) =>
Process.Start($"https://builtbybel.github.io/CrapFixer/update-check.html?version={Program.GetAppVersion()}");
// Register navigation handler
_navigationHandler.NavigationButtonClicked += NavigationHandler_NavigationButtonClicked;
// Set up log actions controller
// Register click handlers for GitHub links
pictureHeader.Click += PictureHeader_Click;
lblHeader.Click += PictureHeader_Click;
// Re-initialize log actions controller (optional if not changed)
_logActionsController = new LogActionsController(comboLogActions, _logActions);
// Set up version labels
async Task SetVersionLabels()
// Set version and OS info
lblVersionInfo.Text = $"v{Program.GetAppVersion()} ";
lblOSInfo.Text = await OSHelper.OSHelper.GetWindowsVersion();
}
// Handles navigation button clicks and switches views accordingly
private void NavigationHandler_NavigationButtonClicked(Button button)
{
if (button == btnFixer)
{
lblVersionInfo.Text = $"v{Program.GetAppVersion()} ";
lblOSInfo.Text = await OSHelper.OSHelper.GetWindowsVersion();
_navigationManager.GoToMain();
}
else if (button == btnTools)
{
_navigationManager.SwitchView(new OptionsView());
}
_ = SetVersionLabels();
}
private async void btnAnalyze_Click(object sender, EventArgs e)
{
rtbLogger.Clear();
// Analyze features
await FeatureNodeManager.AnalyzeAll(treeFeatures.Nodes);
// Analyze plugins
foreach (TreeNode node in treeFeatures.Nodes)
{
PluginManager.AnalyzeAll(node);
}
await PluginManager.AnalyzeAllPlugins(treeFeatures.Nodes);
// Analyze apps
await AnalyzeApps();
@@ -99,40 +102,35 @@ namespace CrapFixer
/// <summary>
/// Analyzes the apps and logs the results.
/// </summary>
/// <returns></returns>
private async Task AnalyzeApps()
{
checkedListBoxApps.Items.Clear();
// Try loading external bloatware list from file
string[] predefined = _appManager.LoadExternalBloatwareList();
// Try loading patterns from CFEnhancer.txt (located in Plugins folder)
var (bloatwarePatterns, whitelistPatterns, scanAll) = _appManager.LoadExternalBloatwarePatterns();
if (predefined.Length == 0)
if (bloatwarePatterns.Length == 0 && !scanAll)
{
// Fallback to internal resource if external file not found or empty
predefined = Resources.PredefinedApps?
// Fallback to internal resource if external file not found or empty and scanAll is not enabled
bloatwarePatterns = Resources.PredefinedApps?
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim()).ToArray() ?? Array.Empty<string>();
.Select(s => s.Trim().ToLower()).ToArray() ?? Array.Empty<string>();
// Logger.Log("Using built-in bloatware list.", LogLevel.Info);
whitelistPatterns = Array.Empty<string>();
Logger.Log("Using built-in bloatware list.", LogLevel.Info);
}
else
{
Logger.Log("Using external bloatware list via CFEnhancer", LogLevel.Info);
Logger.Log("🔎 Plugin ready: CFEnhancer (external bloatware list)", LogLevel.Info);
}
// Analyze installed apps against the predefined list
var apps = await _appManager.AnalyzeAndLogAppsAsync(predefined);
// Analyze installed apps based on patterns and whitelist, and optionally scan all
var apps = await _appManager.AnalyzeAndLogAppsAsync(bloatwarePatterns, whitelistPatterns, scanAll);
foreach (var app in apps)
{
checkedListBoxApps.Items.Add(app.FullName);
}
if (!apps.Any())
{
Logger.Log("✅ No bloatware apps found.", LogLevel.Info);
}
}
private async void btnFix_Click(object sender, EventArgs e)
@@ -182,53 +180,64 @@ namespace CrapFixer
}
}
/// <summary>
/// Analyzes all plugins and features starting from the selected node from the context menu.
/// </summary>
private async void analyzeMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
{
if (treeFeatures.SelectedNode is TreeNode selectedNode)
{
if (PluginManager.IsPluginNode(selectedNode))
Logger.Log($"🔎 Analyzing Feature: {selectedNode.Text}", LogLevel.Info);
// If a single node is selected (leaf node with no children),
// always analyze this node regardless of its Checked state.
if (selectedNode.Nodes.Count == 0)
{
await PluginManager.AnalyzePlugin(selectedNode);
}
else
Logger.Log($"🔎 Analyzing Feature: {selectedNode.Text}", LogLevel.Info);
{
// If a parent node is selected (has children),
// recursively analyze only the checked plugin nodes.
await PluginManager.AnalyzeAll(selectedNode);
}
// Perform feature-specific analysis (non-plugin)
FeatureNodeManager.AnalyzeFeature(selectedNode);
}
}
private async void previewMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
{
if (treeFeatures.SelectedNode is TreeNode selectedNode)
{
if (PluginManager.IsPluginNode(selectedNode))
{
await PluginManager.AnalyzePlugin(selectedNode);
}
else
{
FeatureNodeManager.PreviewChanges(selectedNode);
}
}
}
/// <summary>
/// Fixes all checked plugin and feature nodes starting from the selected node from the context menu.
/// </summary>
private async void fixMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
{
if (treeFeatures.SelectedNode is TreeNode selectedNode)
{
if (PluginManager.IsPluginNode(selectedNode))
await PluginManager.FixPlugin(selectedNode);
else
Logger.Log($"🔧 Fixing Feature: {selectedNode.Text}", LogLevel.Info);
Logger.Log($"🔧 Fixing Feature: {selectedNode.Text}", LogLevel.Info);
// Recursively fix all checked feature nodes (non-plugin)
await FeatureNodeManager.FixFeature(selectedNode);
// Recursively fix all checked plugin nodes starting from the selected node
await PluginManager.FixPlugin(selectedNode);
}
}
private void restoreMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
/// <summary>
/// Restores the selected plugin or feature to its previous state from the context menu.
/// </summary>
private async void restoreMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
{
if (treeFeatures.SelectedNode is TreeNode selectedNode)
{
if (PluginManager.IsPluginNode(selectedNode))
PluginManager.RestorePlugin(selectedNode);
// Restore the plugin using its Undo command if available!
await PluginManager.RestorePlugin(selectedNode);
else
Logger.Log($"↩️ Restoring Feature: {selectedNode.Text}", LogLevel.Info);
// Perform feature-specific restore (non-plugin)
FeatureNodeManager.RestoreFeature(selectedNode);
}
}
@@ -238,18 +247,6 @@ namespace CrapFixer
if (treeFeatures.SelectedNode is TreeNode selectedNode)
{
FeatureNodeManager.ShowHelp(selectedNode);
// Prompt for online search
var result = MessageBox.Show(
"Would you like to search online for more information about this feature?",
"Online Help",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
FeatureNodeManager.ShowHelpOnline(selectedNode);
}
}
}
@@ -322,26 +319,56 @@ namespace CrapFixer
private void panelHeader_Paint(object sender, PaintEventArgs e)
{
Panel panel = sender as Panel;
Graphics g = e.Graphics;
var panel = sender as Panel;
var g = e.Graphics;
// Fill background
// Solid background: #4D4D4D
g.Clear(Color.FromArgb(77, 77, 77));
// Draw a single magenta line at the bottom
using (Pen pen = new Pen(Color.FromArgb(100, 255, 0, 255))) // Magenta with transparency
// Inset line effect (3D-like): light line + shadow line
Color baseColor = Color.FromArgb(80, 80, 80); // inset base
using (var topLine = new Pen(ControlPaint.Light(baseColor, 0.0f)))
using (var bottomLine = new Pen(ControlPaint.Dark(baseColor, 0.2f)))
{
int y = panel.Height - 1; // Bottom-most pixel
g.DrawLine(pen, 0, y, panel.Width, y);
g.SmoothingMode = SmoothingMode.None;
g.DrawLine(topLine, 0, panel.Height - 2, panel.Width, panel.Height - 2);
g.DrawLine(bottomLine, 0, panel.Height - 1, panel.Width, panel.Height - 1);
}
}
// Handles click on the header image to open the GitHub page
private void PictureHeader_Click(object sender, EventArgs e)
{
Utils.OpenGitHubPage(sender, e);
}
// Handles link click to check for updates
private void linkUpdateCheck_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var updateUrl = $"https://builtbybel.github.io/CrapFixer/update-check.html?version={Program.GetAppVersion()}";
var psi = new ProcessStartInfo
{
FileName = updateUrl,
UseShellExecute = true
};
Process.Start(psi);
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (IniStateManager.IsViewSettingEnabled("SETTINGS", "checkSaveToINI"))
{
IniStateManager.Save(treeFeatures, this);
}
Logger.OutputBox = null; // Remove reference
}
private void btnGitHub_Click(object sender, EventArgs e)
{
_navigationManager.SwitchView(new OptionsView());
}
}
}
+6 -335
View File
@@ -120,339 +120,10 @@
<metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>23, 15</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureHeader.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
AABJRU5ErkJggg==
</value>
</data>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>171, 15</value>
</metadata>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>171, 15</value>
</metadata>
</root>
+104 -15
View File
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CFixer
@@ -13,14 +15,14 @@ namespace CFixer
// List of all buttons managed by the navigation handler
private readonly List<Button> _buttons;
// Color used for the active (selected) button
private readonly Color _activeColor = Color.FromArgb(76, 145, 235);
// Color used for the background of the active button
private readonly Color _activeBackgroundColor = Color.FromArgb(180, 150, 200, 240);
// Color used for inactive (non-selected) buttons
private readonly Color _inactiveColor = Color.FromArgb(104, 104, 104);
// Color used for the background of inactive buttons (same as form)
private readonly Color _inactiveBackgroundColor = Color.FromArgb(103, 103, 103);
// Border color for inactive buttons
private readonly Color _inactiveBorderColor = Color.FromArgb(114, 114, 114);
// Color used for the border of the active button
private readonly Color _activeBorderColor = Color.FromArgb(255, 120, 170, 210);
/// <summary>
/// Event fired when a navigation button is clicked.
@@ -46,28 +48,115 @@ namespace CFixer
if (sender is Button clickedButton)
{
SetActive(clickedButton);
clickedButton.FindForm().ActiveControl = null; // Remove focus so no extra border is drawn
NavigationButtonClicked?.Invoke(clickedButton);
}
}
/// <summary>
/// Sets the specified button as active, changing colors accordingly.
/// Sets the given button as active and updates the appearance of all buttons.
/// </summary>
/// <param name="activeButton">The button to highlight as active.</param>
/// <param name="activeButton">The button to mark as active.</param>
public void SetActive(Button activeButton)
{
foreach (var button in _buttons)
{
// Skip GitHub button to avoid conflicts with its custom behavior
if (button.Name.Equals("btnGitHub", StringComparison.OrdinalIgnoreCase))
continue;
bool isActive = button == activeButton;
// Set the background color for the button (active or inactive)
button.BackColor = isActive ? _activeColor : _inactiveColor;
if (isActive)
{
button.BackColor = _activeBackgroundColor;
button.FlatAppearance.BorderColor = _activeBorderColor;
button.FlatAppearance.BorderSize = 1;
}
else
{
button.BackColor = _inactiveBackgroundColor;
button.FlatAppearance.BorderSize = 0;
}
// Set the border color for the button (active or inactive)
button.FlatAppearance.BorderColor = isActive ? _activeColor : _inactiveBorderColor;
button.ForeColor = Color.WhiteSmoke;
}
}
// Set the text color to white for both active and inactive
button.ForeColor = Color.White;
/// <summary>
/// Loads and assigns icons to buttons asynchronously based on their names.
/// </summary>
/// <param name="iconFolder">The relative folder path where the icon files are located. Defaults to "icons". Each button's icon file name is
/// derived from the button's name by removing the "btn" prefix, converting the remainder to lowercase, and
/// appending ".png".</param>
public async Task LoadNavigationIcons(string iconFolder = "icons")
{
string basePath = AppDomain.CurrentDomain.BaseDirectory;
string fullIconPath = Path.Combine(basePath, iconFolder);
if (!Directory.Exists(fullIconPath)) return;
// Create graphics context to get system DPI scaling (default is 96 DPI)
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
float dpiScale = g.DpiX / 96f;
int defaultIconSize = (int)(32 * dpiScale); // Scale 32px base size with DPI
int githubIconSize = (int)(42 * dpiScale); // Special size for GitHub button
foreach (var button in _buttons)
{
// Convert button name like "btnHome" > "home.png"
string buttonName = button.Name.ToLower();
string fileName;
if (buttonName == "btngithub")
fileName = "github.png";
else if (buttonName.StartsWith("btn"))
fileName = buttonName.Replace("btn", "") + ".png";
else
continue;
string filePath = Path.Combine(fullIconPath, fileName);
if (!File.Exists(filePath))
continue;
try
{
// Read file bytes asynchronously off the UI thread
byte[] imageData = await Task.Run(() => File.ReadAllBytes(filePath));
using (var ms = new MemoryStream(imageData))
using (Image original = Image.FromStream(ms))
{
int iconSize = buttonName == "btngithub" ? githubIconSize : defaultIconSize;
Bitmap resized = new Bitmap(iconSize, iconSize);
try
{
using (Graphics gr = Graphics.FromImage(resized))
{
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
gr.DrawImage(original, 0, 0, iconSize, iconSize);
}
// Set button image
button.Image = resized;
button.ImageAlign = ContentAlignment.TopCenter;
button.TextAlign = ContentAlignment.BottomCenter;
}
catch
{
resized.Dispose(); // Cleanup if drawing fails
throw;
}
}
}
catch
{
// Optional: log or ignore loading errors
}
}
}
}
}
}
}
+273 -74
View File
@@ -1,13 +1,20 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
/// <summary>
/// Provides functionality to load, execute, analyze, and fix external PowerShell-based plugins.
/// </summary>
///
public static class PluginManager
{
/// 1. Execute a PowerShell script asynchronously and log output/errors.
public static async Task ExecutePlugin(string pluginPath)
{
try
@@ -21,9 +28,6 @@ public static class PluginManager
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
var outputBuilder = new StringBuilder();
var errorBuilder = new StringBuilder();
process.OutputDataReceived += (s, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
@@ -50,6 +54,7 @@ public static class PluginManager
}
}
/// 2. Load all .ps1 plugin files from the 'plugins' folder into a TreeView.
public static void LoadPlugins(TreeView treeView)
{
string pluginsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
@@ -57,13 +62,11 @@ public static class PluginManager
if (!Directory.Exists(pluginsFolder))
{
Directory.CreateDirectory(pluginsFolder);
// Logger.Log("No Plugins found.\nGet it on https://github.com/builtbybel/CrapFixer");
return;
}
var pluginsNode = new TreeNode("Plugins")
{
// NodeFont = new Font(treeView.Font, FontStyle.Bold),
BackColor = Color.Magenta,
ForeColor = Color.White
};
@@ -73,7 +76,7 @@ public static class PluginManager
var scriptName = Path.GetFileNameWithoutExtension(scriptPath);
var scriptNode = new TreeNode
{
Text = $"{scriptName} [PS]",
Text = $"{scriptName}", // [PS]
ToolTipText = scriptPath,
Tag = scriptPath,
Checked = false
@@ -82,117 +85,313 @@ public static class PluginManager
}
treeView.Nodes.Add(pluginsNode);
treeView.ExpandAll(); // expand all nodes
treeView.ExpandAll();
}
public static void AnalyzeAll(TreeNode node)
/// 3. Parse the [Commands] section from plugin content.
private static Dictionary<string, string> ParseCommands(string pluginContent)
{
if (node.Tag is string path && node.Checked)
{
Logger.Log($"🔎 Plugin ready: {Path.GetFileName(path)}");
}
foreach (TreeNode child in node.Nodes)
AnalyzeAll(child);
return ParseSection(pluginContent, "Commands");
}
/// <summary>
/// Executes all checked plugins in the tree view.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public static async Task FixChecked(TreeNode node)
/// 4. Parse the [Expect] section from plugin content.
private static Dictionary<string, string> ParseExpect(string pluginContent)
{
if (node.Checked)
return ParseSection(pluginContent, "Expect");
}
/// 5. Generic parser for named sections like [Commands] or [Expect].
/// Lines must be in 'key = value' format.
private static Dictionary<string, string> ParseSection(string content, string sectionName)
{
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var lines = content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
bool insideSection = false;
foreach (var line in lines)
{
// Show a warning for each checked plugin
if (node.Tag is string pluginPath)
var trimmed = line.Trim();
if (trimmed.Equals($"[{sectionName}]", StringComparison.OrdinalIgnoreCase))
{
var pluginName = Path.GetFileName(pluginPath); // get the plugin name
var proceed = ShowPluginWarning(pluginName); // the warning message box
if (!proceed) return; // If user chooses not to proceed, exit the method
insideSection = true;
continue;
}
// Exit the section when another section begins
if (insideSection)
{
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
break;
// Parse lines of form: key = value
var idx = trimmed.IndexOf('=');
if (idx > 0)
{
var key = trimmed.Substring(0, idx).Trim();
var val = trimmed.Substring(idx + 1).Trim();
result[key] = val;
}
}
}
if (node.Tag is string path && node.Checked)
{
await ExecutePlugin(path);
}
return result;
}
// Recursively process all child nodes
foreach (TreeNode child in node.Nodes)
await FixChecked(child);
/// 6. Execute a shell command (CMD) and return exit code and output.
private static async Task<(int exitCode, string output)> ExecuteCommand(string command)
{
var process = new Process();
var outputBuilder = new StringBuilder();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = $"/c \"{command}\"";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.OutputDataReceived += (s, e) => { if (e.Data != null) outputBuilder.AppendLine(e.Data); };
process.ErrorDataReceived += (s, e) => { if (e.Data != null) outputBuilder.AppendLine(e.Data); };
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
await Task.Run(() => process.WaitForExit());
return (process.ExitCode, outputBuilder.ToString());
}
/// <summary>
/// Analyzes individual plugin files.
/// 7. Analyzes a single plugin node by running its 'Check' command
/// and comparing the output against expected values defined in the [Expect] section.
/// Logs a summary indicating success if all checks pass, or warnings if mismatches occur.
/// Only the specified plugin node is analyzed, regardless of its checked state.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
/// <param name="node">The TreeNode representing the plugin to analyze, with script path stored in Tag.</param>
public static async Task AnalyzePlugin(TreeNode node)
{
if (node?.Tag is string path && File.Exists(path))
if (node == null || node.Tag == null || !File.Exists(node.Tag.ToString()))
{
string content = File.ReadAllText(path);
Logger.Log(new string('=', 50), LogLevel.Custom);
Logger.Log($"📄 Script content:{node.Text}\n{content}", LogLevel.Info);
await Task.CompletedTask;
// Logger.Log($"❌ Script file not found for plugin: {node?.Text}", LogLevel.Error);
Logger.Log(new string('-', 50), LogLevel.Info);
}
else
{
Logger.Log($"❌ Script file not found for plugin: {node?.Text}", LogLevel.Error);
string pluginName = node.Text;
string path = node.Tag.ToString();
string content = File.ReadAllText(path);
Dictionary<string, string> commands = ParseCommands(content);
Dictionary<string, string> expected = ParseExpect(content);
if (!commands.ContainsKey("Check"))
{
Logger.Log($"🔎 Plugin ready: [PS] {Path.GetFileName(path)}");
Logger.Log(new string('-', 50), LogLevel.Info);
}
else
{
string checkCmd = commands["Check"];
var result = await ExecuteCommand(checkCmd);
string output = result.Item2;
bool allMatched = true;
StringBuilder mismatchDetails = new StringBuilder();
foreach (var entry in expected)
{
string key = entry.Key;
string expectedVal = entry.Value;
var match = Regex.Match(output, $@"{Regex.Escape(key)}\s+REG_\w+\s+(\S+)", RegexOptions.IgnoreCase);
if (match.Success)
{
string actual = match.Groups[1].Value;
if (!expectedVal.Equals(actual, StringComparison.OrdinalIgnoreCase))
{
allMatched = false;
mismatchDetails.AppendLine($" ➤ {key}: expected '{expectedVal}', found '{actual}'");
}
}
else
{
allMatched = false;
mismatchDetails.AppendLine(
$" ➤ Warning: The registry key '{key}' could not be located in the output. " +
"This usually means the key is missing and the tweak will have to add it. " +
"[InternalCode: Could not be parsed from output]");
}
}
if (allMatched)
{
Logger.Log($"✅ Plugin: {pluginName} is properly configured.", LogLevel.Info);
node.ForeColor = Color.Gray;
}
else
{
Logger.Log($"❌ Plugin: {pluginName} requires attention.\n{mismatchDetails}", LogLevel.Warning);
node.ForeColor = Color.Red;
}
Logger.Log(new string('-', 50), LogLevel.Info);
}
}
}
/// <summary>
/// Executes individual plugin files.
/// 8. Applies the fix to a single plugin node.
/// This method processes only the specified node regardless of its checked state.
/// It attempts to run the "Do" command from the plugin script, or falls back to executing the entire script.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public static async Task FixPlugin(TreeNode node)
{
if (node?.Tag is string path && File.Exists(path))
{
Logger.Log($"🔧 Executing Plugin: {node.Text}", LogLevel.Info);
await ExecutePlugin(path);
}
else
{
Logger.Log($"❌ Script file not found for plugin: {node?.Text}", LogLevel.Error);
}
}
var content = File.ReadAllText(path);
var commands = ParseCommands(content);
public static void RestorePlugin(TreeNode node)
{
Logger.Log($"⚠️ Restore is not available for Plugins: {node?.Text}", LogLevel.Warning);
MessageBox.Show("Restore is not possible for Plugins.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
if (commands.TryGetValue("Do", out string doCmd))
{
Logger.Log($"🔧 Running Do command for plugin: {node.Text}");
var (exitCode, output) = await ExecuteCommand(doCmd);
Logger.Log($"Do Output:\n{output}");
Logger.Log(exitCode == 0 ? "✅ Fix applied successfully." : "❌ Fix failed.");
}
else
{
Logger.Log($"🔧 No Do command found, executing full script.");
await ExecutePlugin(path);
}
}
}
/// <summary>
/// Checks if the node is a plugin node.
/// 9. Reverts changes for a single plugin node.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public static async Task RestorePlugin(TreeNode node)
{
if (node?.Tag is string path && File.Exists(path))
{
var content = File.ReadAllText(path);
var commands = ParseCommands(content);
if (commands.TryGetValue("Undo", out string undoCmd))
{
Logger.Log($"♻️ Running Undo command for plugin: {node.Text}");
var (exitCode, output) = await ExecuteCommand(undoCmd);
Logger.Log($"Undo Output:\n{output}");
Logger.Log(exitCode == 0 ? "✅ Restore successful." : "❌ Restore failed.");
}
else
{
Logger.Log($"⚠️ No Undo command found. Restore not possible.");
MessageBox.Show("Restore is not possible for this plugin.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
/// 10. Recursively analyze all checked plugin nodes.
public static async Task AnalyzeAll(TreeNode node)
{
if (node.Checked && node.Tag is string path && File.Exists(path))
await AnalyzePlugin(node);
foreach (TreeNode child in node.Nodes)
await AnalyzeAll(child);
}
public static async Task AnalyzeAllPlugins(TreeNodeCollection nodes)
{
Logger.Log("\n🔌 PLUGIN ANALYSIS", LogLevel.Info);
Logger.Log(new string('=', 50), LogLevel.Info);
foreach (TreeNode node in nodes)
await AnalyzeAll(node);
}
/// 11. Recursively apply fixes for all checked plugin nodes.
public static async Task FixChecked(TreeNode node)
{
if (node.Checked && node.Tag is string pluginPath)
{
var pluginName = Path.GetFileName(pluginPath);
var proceed = ShowPluginWarning(pluginName);
if (!proceed) return;
await FixPlugin(node);
}
foreach (TreeNode child in node.Nodes)
await FixChecked(child);
}
/// 12. Return true if the node represents a PowerShell plugin file.
public static bool IsPluginNode(TreeNode node)
{
return node?.Tag is string path && path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Shows a warning message box when the root plugin node is checked.
/// </summary>
/// <returns>True if the user confirmed, otherwise false.</returns>
/// 13. Show a warning before executing external plugin code.
public static bool ShowPluginWarning(string pluginName)
{
var result = MessageBox.Show(
$"⚠️ WARNING: The plugin '{pluginName}' is an external script. Its execution is outside this apps responsibility and at your own risk.\n" +
"Proceed only if you trust the source of this plugin. Do you want to continue?",
"Plugin Activation Warning",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning
);
$"⚠️ WARNING: The plugin '{pluginName}' is an external script. Its execution is outside this app's responsibility and at your own risk.\n" +
"Proceed only if you trust the source of this plugin. Do you want to continue?",
"Plugin Activation Warning",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning
);
return result == DialogResult.Yes; // Return true if "Yes" was clicked
return result == DialogResult.Yes;
}
public static bool ShowHelp(TreeNode node)
{
string info = GetPluginHelpInfo(node);
if (!string.IsNullOrEmpty(info))
{
MessageBox.Show(info, $"Plugin Help: {node.Text}", MessageBoxButtons.OK, MessageBoxIcon.Information);
return true;
}
return false;
}
/// <summary>
/// Returns the help/info string from the plugin commands section for the given node.
/// Assumes node.Tag contains the script path as string.
/// </summary>
public static string GetPluginHelpInfo(TreeNode node)
{
if (node?.Tag is string path && File.Exists(path))
{
string content = File.ReadAllText(path);
// Simple parsing to find line starting with "Info=" under [Commands]
bool inCommandsSection = false;
foreach (var line in content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
{
var trimmed = line.Trim();
if (trimmed.StartsWith("[Commands]", StringComparison.OrdinalIgnoreCase))
{
inCommandsSection = true;
continue;
}
if (trimmed.StartsWith("[") && trimmed.EndsWith("]") && inCommandsSection)
{
// Left commands section
break;
}
if (inCommandsSection && trimmed.StartsWith("Info=", StringComparison.OrdinalIgnoreCase))
{
return trimmed.Substring(5).Trim(); // Return the text after "Info="
}
}
}
return null; // No info found or invalid node
}
}
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// indem Sie "*" wie unten gezeigt eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.252")]
[assembly: AssemblyFileVersion("1.2.252")]
[assembly: AssemblyVersion("1.16.156")]
[assembly: AssemblyFileVersion("1.16.156")]
+4 -4
View File
@@ -117,14 +117,14 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="AppIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\AppIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="PredefinedApps" xml:space="preserve">
<value>Solitaire,CandyCrush,Netflix, Facebook,Twitter,Instagram,TikTok,Spotify, Skype,OneNote,OneDrive, Mail, Calendar, Weather,News,Maps, Groove, Movies,TV, Phone, Camera,Feedback,FeedbackHub, GetHelp,GetStarted,Messaging,Office,Paint3D,Print3D,StickyNotes,Wallet,YourPhone,3DViewer,Alarms,VoiceRecorder,ToDo,Whiteboard,ZuneMusic,ZuneVideo,3DViewer, DevHome, Copilot,MicrosoftPCManager</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="AppIcon32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\AppIcon32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="AppIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\AppIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>
+34 -7
View File
@@ -35,6 +35,8 @@
this.linkGitHub = new System.Windows.Forms.LinkLabel();
this.btnDonate = new System.Windows.Forms.Button();
this.panelSettings = new System.Windows.Forms.Panel();
this.comboBoxCurrency = new System.Windows.Forms.ComboBox();
this.comboBoxAmount = new System.Windows.Forms.ComboBox();
this.lblCopyright = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.panelSettings.SuspendLayout();
@@ -58,7 +60,7 @@
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label1.AutoEllipsis = true;
this.label1.Location = new System.Drawing.Point(19, 138);
this.label1.Location = new System.Drawing.Point(15, 127);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(589, 26);
this.label1.TabIndex = 236;
@@ -88,12 +90,12 @@
// linkGitHub
//
this.linkGitHub.AutoSize = true;
this.linkGitHub.Location = new System.Drawing.Point(38, 173);
this.linkGitHub.Location = new System.Drawing.Point(34, 162);
this.linkGitHub.Name = "linkGitHub";
this.linkGitHub.Size = new System.Drawing.Size(193, 13);
this.linkGitHub.Size = new System.Drawing.Size(189, 13);
this.linkGitHub.TabIndex = 239;
this.linkGitHub.TabStop = true;
this.linkGitHub.Text = "https://github.com/builtbybel/CrapFixer";
this.linkGitHub.Text = "https://github.com/builtbybel/crapfixer";
this.linkGitHub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkGitHub_LinkClicked);
//
// btnDonate
@@ -104,16 +106,19 @@
this.btnDonate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDonate.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnDonate.ForeColor = System.Drawing.Color.White;
this.btnDonate.Location = new System.Drawing.Point(61, 85);
this.btnDonate.Location = new System.Drawing.Point(226, 91);
this.btnDonate.Name = "btnDonate";
this.btnDonate.Size = new System.Drawing.Size(207, 39);
this.btnDonate.Size = new System.Drawing.Size(101, 22);
this.btnDonate.TabIndex = 240;
this.btnDonate.Text = "Like CrapFixer? Support future updates on Ko-fi or PayPal";
this.btnDonate.Text = "Donate";
this.btnDonate.UseVisualStyleBackColor = false;
this.btnDonate.Click += new System.EventHandler(this.btnDonate_Click);
//
// panelSettings
//
this.panelSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
this.panelSettings.Controls.Add(this.comboBoxCurrency);
this.panelSettings.Controls.Add(this.comboBoxAmount);
this.panelSettings.Controls.Add(this.lblCopyright);
this.panelSettings.Controls.Add(this.btnDonate);
this.panelSettings.Controls.Add(this.lblHeader);
@@ -127,6 +132,26 @@
this.panelSettings.Size = new System.Drawing.Size(625, 395);
this.panelSettings.TabIndex = 242;
//
// comboBoxCurrency
//
this.comboBoxCurrency.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxCurrency.Font = new System.Drawing.Font("Tahoma", 9.25F);
this.comboBoxCurrency.FormattingEnabled = true;
this.comboBoxCurrency.Location = new System.Drawing.Point(157, 91);
this.comboBoxCurrency.Name = "comboBoxCurrency";
this.comboBoxCurrency.Size = new System.Drawing.Size(63, 22);
this.comboBoxCurrency.TabIndex = 243;
//
// comboBoxAmount
//
this.comboBoxAmount.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxAmount.Font = new System.Drawing.Font("Tahoma", 9.25F);
this.comboBoxAmount.FormattingEnabled = true;
this.comboBoxAmount.Location = new System.Drawing.Point(64, 91);
this.comboBoxAmount.Name = "comboBoxAmount";
this.comboBoxAmount.Size = new System.Drawing.Size(90, 22);
this.comboBoxAmount.TabIndex = 242;
//
// lblCopyright
//
this.lblCopyright.AutoSize = true;
@@ -163,5 +188,7 @@
private System.Windows.Forms.Button btnDonate;
private System.Windows.Forms.Panel panelSettings;
private System.Windows.Forms.Label lblCopyright;
private System.Windows.Forms.ComboBox comboBoxAmount;
private System.Windows.Forms.ComboBox comboBoxCurrency;
}
}
+38 -29
View File
@@ -1,5 +1,4 @@
using CrapFixer;
using CFixer.Views;
using System;
using System.Diagnostics;
using System.Windows.Forms;
@@ -19,6 +18,19 @@ namespace Views
{
// Update version label
this.lblVersionInfo.Text = $"v{Program.GetAppVersion()} ";
// Populate amount choices
comboBoxAmount.Items.AddRange(new object[] { "3.50", "5", "10",
"12", "15", "16",
"17", "18","20",
"25", "30", "35",
"40", "50", "60",
"70", "80", "100"});
comboBoxAmount.SelectedIndex = 2;
// Populate currency options
comboBoxCurrency.Items.AddRange(new object[] { "EUR", "USD", "GBP", "CAD", "AUD", "CHF" });
comboBoxCurrency.SelectedIndex = 0;
}
private void linkGitHub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
@@ -28,37 +40,34 @@ namespace Views
private void btnDonate_Click(object sender, EventArgs e)
{
var result = MessageBox.Show(
"Hi! I'm building CrapFixer solo. Want to support me and help launch Version 1.0?",
"Support CrapFixer ❤️",
MessageBoxButtons.YesNo,
MessageBoxIcon.Information);
string amount = comboBoxAmount.SelectedItem?.ToString();
string currency = comboBoxCurrency.SelectedItem?.ToString();
if (result == DialogResult.Yes)
if (string.IsNullOrEmpty(amount) || string.IsNullOrEmpty(currency))
{
var donationChoice = MessageBox.Show(
"Would you like to donate via PayPal? (Click No for Ko-fi)",
"Choose Your Support Method",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);
if (donationChoice == DialogResult.Yes)
{
System.Diagnostics.Process.Start(new ProcessStartInfo
{
FileName = "https://www.paypal.com/donate/?hosted_button_id=M9DW4VNKH9ECQ",
UseShellExecute = true
});
}
else if (donationChoice == DialogResult.No)
{
System.Diagnostics.Process.Start(new ProcessStartInfo
{
FileName = "https://ko-fi.com/builtbybel",
UseShellExecute = true
});
}
MessageBox.Show("Please select an amount and a currency.");
return;
}
string email = "belim@builtbybel.com";
string purpose = Uri.EscapeDataString("Support Development of the CrapFixer app.");
string returnUrl = Uri.EscapeDataString("https://github.com/Belim/support");
string cancelUrl = Uri.EscapeDataString("https://github.com/builtbybel/CrapFixer");
string url = $"https://www.paypal.com/cgi-bin/webscr?cmd=_donations" +
$"&business={Uri.EscapeDataString(email)}" +
$"&amount={amount}" +
$"&currency_code={currency}" +
$"&item_name={purpose}" +
$"&return={returnUrl}" +
$"&cancel_return={cancelUrl}";
System.Diagnostics.Process.Start(new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
}
}
}
+44 -22
View File
@@ -29,16 +29,18 @@
private void InitializeComponent()
{
this.panelSettings = new System.Windows.Forms.Panel();
this.btnViveMenu = new System.Windows.Forms.Button();
this.btnPluginsMenu = new System.Windows.Forms.Button();
this.panelSubContent = new System.Windows.Forms.Panel();
this.btnAboutMenu = new System.Windows.Forms.Button();
this.btnSettingsMenu = new System.Windows.Forms.Button();
this.btnPluginsMenu = new System.Windows.Forms.Button();
this.panelSettings.SuspendLayout();
this.SuspendLayout();
//
// panelSettings
//
this.panelSettings.BackColor = System.Drawing.Color.White;
this.panelSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(248)))));
this.panelSettings.Controls.Add(this.btnViveMenu);
this.panelSettings.Controls.Add(this.btnPluginsMenu);
this.panelSettings.Controls.Add(this.panelSubContent);
this.panelSettings.Controls.Add(this.btnAboutMenu);
@@ -49,15 +51,46 @@
this.panelSettings.Size = new System.Drawing.Size(625, 395);
this.panelSettings.TabIndex = 243;
//
// btnViveMenu
//
this.btnViveMenu.BackColor = System.Drawing.Color.White;
this.btnViveMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
this.btnViveMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
this.btnViveMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnViveMenu.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnViveMenu.Location = new System.Drawing.Point(14, 88);
this.btnViveMenu.Name = "btnViveMenu";
this.btnViveMenu.Size = new System.Drawing.Size(100, 32);
this.btnViveMenu.TabIndex = 248;
this.btnViveMenu.Text = "Features ";
this.btnViveMenu.UseVisualStyleBackColor = false;
this.btnViveMenu.Click += new System.EventHandler(this.btnViveMenu_Click);
//
// btnPluginsMenu
//
this.btnPluginsMenu.BackColor = System.Drawing.Color.White;
this.btnPluginsMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
this.btnPluginsMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
this.btnPluginsMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnPluginsMenu.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnPluginsMenu.Location = new System.Drawing.Point(14, 48);
this.btnPluginsMenu.Name = "btnPluginsMenu";
this.btnPluginsMenu.Size = new System.Drawing.Size(100, 32);
this.btnPluginsMenu.TabIndex = 247;
this.btnPluginsMenu.Text = "Plugins";
this.btnPluginsMenu.UseVisualStyleBackColor = false;
this.btnPluginsMenu.Click += new System.EventHandler(this.btnPluginsMenu_Click);
//
// panelSubContent
//
this.panelSubContent.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelSubContent.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
this.panelSubContent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelSubContent.Location = new System.Drawing.Point(135, 14);
this.panelSubContent.Location = new System.Drawing.Point(129, 8);
this.panelSubContent.Name = "panelSubContent";
this.panelSubContent.Size = new System.Drawing.Size(474, 363);
this.panelSubContent.Size = new System.Drawing.Size(487, 378);
this.panelSubContent.TabIndex = 246;
//
// btnAboutMenu
@@ -65,11 +98,12 @@
this.btnAboutMenu.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnAboutMenu.BackColor = System.Drawing.Color.White;
this.btnAboutMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
this.btnAboutMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
this.btnAboutMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnAboutMenu.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnAboutMenu.Location = new System.Drawing.Point(14, 343);
this.btnAboutMenu.Location = new System.Drawing.Point(14, 354);
this.btnAboutMenu.Name = "btnAboutMenu";
this.btnAboutMenu.Size = new System.Drawing.Size(107, 34);
this.btnAboutMenu.Size = new System.Drawing.Size(100, 32);
this.btnAboutMenu.TabIndex = 242;
this.btnAboutMenu.Text = "About";
this.btnAboutMenu.UseVisualStyleBackColor = false;
@@ -79,30 +113,17 @@
//
this.btnSettingsMenu.BackColor = System.Drawing.Color.White;
this.btnSettingsMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
this.btnSettingsMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
this.btnSettingsMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnSettingsMenu.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnSettingsMenu.Location = new System.Drawing.Point(14, 13);
this.btnSettingsMenu.Location = new System.Drawing.Point(14, 8);
this.btnSettingsMenu.Name = "btnSettingsMenu";
this.btnSettingsMenu.Size = new System.Drawing.Size(107, 34);
this.btnSettingsMenu.Size = new System.Drawing.Size(100, 32);
this.btnSettingsMenu.TabIndex = 241;
this.btnSettingsMenu.Text = "Settings";
this.btnSettingsMenu.UseVisualStyleBackColor = false;
this.btnSettingsMenu.Click += new System.EventHandler(this.btnSettingsMenu_Click);
//
// btnPluginsMenu
//
this.btnPluginsMenu.BackColor = System.Drawing.Color.White;
this.btnPluginsMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
this.btnPluginsMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnPluginsMenu.Font = new System.Drawing.Font("Tahoma", 8F);
this.btnPluginsMenu.Location = new System.Drawing.Point(14, 53);
this.btnPluginsMenu.Name = "btnPluginsMenu";
this.btnPluginsMenu.Size = new System.Drawing.Size(107, 34);
this.btnPluginsMenu.TabIndex = 247;
this.btnPluginsMenu.Text = "Plugins";
this.btnPluginsMenu.UseVisualStyleBackColor = false;
this.btnPluginsMenu.Click += new System.EventHandler(this.btnPluginsMenu_Click);
//
// OptionsView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -122,5 +143,6 @@
private System.Windows.Forms.Button btnAboutMenu;
private System.Windows.Forms.Panel panelSubContent;
private System.Windows.Forms.Button btnPluginsMenu;
private System.Windows.Forms.Button btnViveMenu;
}
}
+5
View File
@@ -29,5 +29,10 @@ namespace CFixer.Views
{
subNavigation.SwitchView(new PluginsView());
}
private void btnViveMenu_Click(object sender, EventArgs e)
{
subNavigation.SwitchView(new ViveView());
}
}
}
+111 -39
View File
@@ -30,20 +30,26 @@
{
this.btnPluginInstall = new System.Windows.Forms.Button();
this.btnDescription = new System.Windows.Forms.Button();
this.listBoxPlugins = new System.Windows.Forms.CheckedListBox();
this.progressBarDownload = new System.Windows.Forms.ProgressBar();
this.btnPluginOpen = new System.Windows.Forms.Button();
this.btnPluginEdit = new System.Windows.Forms.Button();
this.btnPluginRemove = new System.Windows.Forms.Button();
this.btnPluginSubmit = new System.Windows.Forms.Button();
this.btnPluginUpdateAll = new System.Windows.Forms.Button();
this.btnHelp = new System.Windows.Forms.Button();
this.textSearch = new System.Windows.Forms.TextBox();
this.linkPluginUsage = new System.Windows.Forms.LinkLabel();
this.listPlugins = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SuspendLayout();
//
// btnPluginInstall
//
this.btnPluginInstall.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPluginInstall.Location = new System.Drawing.Point(488, 46);
this.btnPluginInstall.Location = new System.Drawing.Point(500, 46);
this.btnPluginInstall.Name = "btnPluginInstall";
this.btnPluginInstall.Size = new System.Drawing.Size(121, 29);
this.btnPluginInstall.Size = new System.Drawing.Size(109, 29);
this.btnPluginInstall.TabIndex = 7;
this.btnPluginInstall.Text = "Install";
this.btnPluginInstall.UseVisualStyleBackColor = true;
@@ -59,53 +65,40 @@
this.btnDescription.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDescription.Location = new System.Drawing.Point(15, 10);
this.btnDescription.Name = "btnDescription";
this.btnDescription.Padding = new System.Windows.Forms.Padding(20, 0, 0, 0);
this.btnDescription.Padding = new System.Windows.Forms.Padding(20, 0, 100, 0);
this.btnDescription.Size = new System.Drawing.Size(594, 25);
this.btnDescription.TabIndex = 6;
this.btnDescription.Text = "Plugins Gallery (App restart needed after install)";
this.btnDescription.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnDescription.UseVisualStyleBackColor = true;
//
// listBoxPlugins
//
this.listBoxPlugins.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listBoxPlugins.Font = new System.Drawing.Font("Tahoma", 8.25F);
this.listBoxPlugins.FormattingEnabled = true;
this.listBoxPlugins.Location = new System.Drawing.Point(15, 44);
this.listBoxPlugins.Name = "listBoxPlugins";
this.listBoxPlugins.Size = new System.Drawing.Size(457, 340);
this.listBoxPlugins.TabIndex = 8;
this.listBoxPlugins.SelectedIndexChanged += new System.EventHandler(this.listBoxPlugins_SelectedIndexChanged);
//
// progressBarDownload
//
this.progressBarDownload.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBarDownload.Location = new System.Drawing.Point(15, 380);
this.progressBarDownload.Name = "progressBarDownload";
this.progressBarDownload.Size = new System.Drawing.Size(457, 12);
this.progressBarDownload.Size = new System.Drawing.Size(470, 12);
this.progressBarDownload.TabIndex = 9;
this.progressBarDownload.Visible = false;
//
// btnPluginOpen
// btnPluginEdit
//
this.btnPluginOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPluginOpen.Location = new System.Drawing.Point(488, 116);
this.btnPluginOpen.Name = "btnPluginOpen";
this.btnPluginOpen.Size = new System.Drawing.Size(121, 29);
this.btnPluginOpen.TabIndex = 10;
this.btnPluginOpen.Text = "Open";
this.btnPluginOpen.UseVisualStyleBackColor = true;
this.btnPluginOpen.Click += new System.EventHandler(this.btnPluginOpen_Click);
this.btnPluginEdit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPluginEdit.Location = new System.Drawing.Point(500, 151);
this.btnPluginEdit.Name = "btnPluginEdit";
this.btnPluginEdit.Size = new System.Drawing.Size(109, 29);
this.btnPluginEdit.TabIndex = 10;
this.btnPluginEdit.Text = "Edit";
this.btnPluginEdit.UseVisualStyleBackColor = true;
this.btnPluginEdit.Click += new System.EventHandler(this.btnPluginEdit_Click);
//
// btnPluginRemove
//
this.btnPluginRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPluginRemove.Location = new System.Drawing.Point(488, 151);
this.btnPluginRemove.Location = new System.Drawing.Point(500, 116);
this.btnPluginRemove.Name = "btnPluginRemove";
this.btnPluginRemove.Size = new System.Drawing.Size(121, 29);
this.btnPluginRemove.Size = new System.Drawing.Size(109, 29);
this.btnPluginRemove.TabIndex = 11;
this.btnPluginRemove.Text = "Remove";
this.btnPluginRemove.UseVisualStyleBackColor = true;
@@ -114,9 +107,9 @@
// btnPluginSubmit
//
this.btnPluginSubmit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnPluginSubmit.Location = new System.Drawing.Point(488, 345);
this.btnPluginSubmit.Location = new System.Drawing.Point(500, 345);
this.btnPluginSubmit.Name = "btnPluginSubmit";
this.btnPluginSubmit.Size = new System.Drawing.Size(121, 29);
this.btnPluginSubmit.Size = new System.Drawing.Size(109, 29);
this.btnPluginSubmit.TabIndex = 12;
this.btnPluginSubmit.Text = "Submit Plugin";
this.btnPluginSubmit.UseVisualStyleBackColor = true;
@@ -125,32 +118,105 @@
// btnPluginUpdateAll
//
this.btnPluginUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPluginUpdateAll.Location = new System.Drawing.Point(488, 81);
this.btnPluginUpdateAll.Location = new System.Drawing.Point(500, 81);
this.btnPluginUpdateAll.Name = "btnPluginUpdateAll";
this.btnPluginUpdateAll.Size = new System.Drawing.Size(121, 29);
this.btnPluginUpdateAll.Size = new System.Drawing.Size(109, 29);
this.btnPluginUpdateAll.TabIndex = 13;
this.btnPluginUpdateAll.Text = "Update All";
this.btnPluginUpdateAll.UseVisualStyleBackColor = true;
this.btnPluginUpdateAll.Click += new System.EventHandler(this.btnPluginUpdateAll_Click);
//
// btnHelp
//
this.btnHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnHelp.Location = new System.Drawing.Point(500, 186);
this.btnHelp.Name = "btnHelp";
this.btnHelp.Size = new System.Drawing.Size(109, 29);
this.btnHelp.TabIndex = 14;
this.btnHelp.Text = "Help";
this.btnHelp.UseVisualStyleBackColor = true;
this.btnHelp.Click += new System.EventHandler(this.btnHelp_Click);
//
// textSearch
//
this.textSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.textSearch.Location = new System.Drawing.Point(500, 233);
this.textSearch.Name = "textSearch";
this.textSearch.Size = new System.Drawing.Size(109, 20);
this.textSearch.TabIndex = 245;
this.textSearch.Text = "Search";
this.textSearch.Click += new System.EventHandler(this.textSearch_Click);
this.textSearch.TextChanged += new System.EventHandler(this.textSearch_TextChanged);
//
// linkPluginUsage
//
this.linkPluginUsage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.linkPluginUsage.AutoSize = true;
this.linkPluginUsage.BackColor = System.Drawing.Color.WhiteSmoke;
this.linkPluginUsage.Location = new System.Drawing.Point(535, 16);
this.linkPluginUsage.Name = "linkPluginUsage";
this.linkPluginUsage.Size = new System.Drawing.Size(67, 13);
this.linkPluginUsage.TabIndex = 246;
this.linkPluginUsage.TabStop = true;
this.linkPluginUsage.Text = "Usage notes";
this.linkPluginUsage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkPluginUsage_LinkClicked);
//
// listPlugins
//
this.listPlugins.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listPlugins.CheckBoxes = true;
this.listPlugins.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2,
this.columnHeader3});
this.listPlugins.FullRowSelect = true;
this.listPlugins.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.listPlugins.HideSelection = false;
this.listPlugins.Location = new System.Drawing.Point(15, 46);
this.listPlugins.Name = "listPlugins";
this.listPlugins.Size = new System.Drawing.Size(470, 328);
this.listPlugins.TabIndex = 247;
this.listPlugins.UseCompatibleStateImageBehavior = false;
this.listPlugins.View = System.Windows.Forms.View.Details;
this.listPlugins.SelectedIndexChanged += new System.EventHandler(this.listPlugins_SelectedIndexChanged);
//
// columnHeader1
//
this.columnHeader1.Text = "Plugin";
//
// columnHeader2
//
this.columnHeader2.Text = "Installed";
//
// columnHeader3
//
this.columnHeader3.Text = "Type";
this.columnHeader3.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
//
// PluginsView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoScroll = true;
this.BackColor = System.Drawing.Color.White;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
this.Controls.Add(this.listPlugins);
this.Controls.Add(this.linkPluginUsage);
this.Controls.Add(this.textSearch);
this.Controls.Add(this.btnHelp);
this.Controls.Add(this.btnPluginUpdateAll);
this.Controls.Add(this.btnPluginSubmit);
this.Controls.Add(this.btnPluginRemove);
this.Controls.Add(this.btnPluginOpen);
this.Controls.Add(this.btnPluginEdit);
this.Controls.Add(this.progressBarDownload);
this.Controls.Add(this.listBoxPlugins);
this.Controls.Add(this.btnPluginInstall);
this.Controls.Add(this.btnDescription);
this.Name = "PluginsView";
this.Size = new System.Drawing.Size(625, 395);
this.Load += new System.EventHandler(this.PluginsView_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
@@ -158,11 +224,17 @@
private System.Windows.Forms.Button btnPluginInstall;
private System.Windows.Forms.Button btnDescription;
private System.Windows.Forms.CheckedListBox listBoxPlugins;
private System.Windows.Forms.ProgressBar progressBarDownload;
private System.Windows.Forms.Button btnPluginOpen;
private System.Windows.Forms.Button btnPluginEdit;
private System.Windows.Forms.Button btnPluginRemove;
private System.Windows.Forms.Button btnPluginSubmit;
private System.Windows.Forms.Button btnPluginUpdateAll;
private System.Windows.Forms.Button btnHelp;
private System.Windows.Forms.TextBox textSearch;
private System.Windows.Forms.LinkLabel linkPluginUsage;
private System.Windows.Forms.ListView listPlugins;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.ColumnHeader columnHeader3;
}
}
+231 -71
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
@@ -10,8 +11,10 @@ namespace CFixer.Views
{
public partial class PluginsView : UserControl
{
private List<PluginEntry> plugins = new List<PluginEntry>();
private HashSet<string> installedPlugins = new HashSet<string>();
private List<PluginEntry> plugins = new List<PluginEntry>(); // All plugins from the manifest, so full squad
private List<PluginEntry> visiblePlugins = new List<PluginEntry>(); // Plugins currently shown in the UI (filtered or not)
private HashSet<string> installedPlugins = new HashSet<string>(); // Names of plugins already installed on disk
private const string manifestUrl = "https://raw.githubusercontent.com/builtbybel/CrapFixer/main/plugins/plugins_manifest.txt";
public class PluginEntry
@@ -31,6 +34,9 @@ namespace CFixer.Views
await LoadPlugins();
}
/// <summary>
/// Loads the currently installed plugins from disk into memory.
/// </summary>
private void LoadInstalledPlugins()
{
var pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
@@ -43,29 +49,28 @@ namespace CFixer.Views
}
}
/// <summary>
/// Loads plugins from the remote manifest and displays them.
/// </summary>
private async Task LoadPlugins()
{
try
{
LoadInstalledPlugins();
LoadInstalledPlugins(); // Load the plugins already installed on disk, gotta know whats up
using (var client = new WebClient())
{
// Download the plugin manifest
string content = await Task.Run(() => client.DownloadString(manifestUrl));
// Parse the manifest into our plugins list — all the available plugins decoded!
plugins = ParseManifest(content);
listBoxPlugins.Items.Clear();
foreach (var plugin in plugins)
{
var fileName = Path.GetFileName(plugin.Url);
string displayName = plugin.Name;
// Sync visiblePlugins with the full list to keep UI and data in perfect harmony
visiblePlugins = plugins.ToList();
if (installedPlugins.Contains(fileName))
displayName += " (Installed)";
listBoxPlugins.Items.Add(displayName);
}
// Update the ListBox so it shows all the plugins we're tracking right now
UpdateVisiblePlugins();
}
}
catch (Exception ex)
@@ -74,37 +79,61 @@ namespace CFixer.Views
}
}
/// <summary>
/// Parses the remote plugin manifest into a list of PluginEntry objects.
/// </summary>
private List<PluginEntry> ParseManifest(string content)
{
var result = new List<PluginEntry>();
var lines = content.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
PluginEntry current = null;
string currentKey = null;
foreach (var line in lines)
{
if (line.StartsWith("[") && line.EndsWith("]"))
var trimmedLine = line.Trim();
if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]"))
{
if (current != null)
result.Add(current);
var name = line.Substring(1, line.Length - 2).Trim();
var name = trimmedLine.Substring(1, trimmedLine.Length - 2).Trim();
current = new PluginEntry { Name = name };
currentKey = null;
}
else if (!string.IsNullOrWhiteSpace(line) && line.Contains("=") && current != null)
else if (!string.IsNullOrWhiteSpace(trimmedLine))
{
var parts = line.Split(new[] { '=' }, 2);
var key = parts[0].Trim();
var value = parts[1].Trim();
switch (key)
if (trimmedLine.Contains("=") && current != null)
{
case "description":
current.Description = value;
break;
var parts = trimmedLine.Split(new[] { '=' }, 2);
var key = parts[0].Trim();
var value = parts[1].Trim();
case "url":
current.Url = value;
break;
switch (key)
{
case "description":
current.Description = value;
currentKey = "description";
break;
case "url":
current.Url = value;
currentKey = "url";
break;
default:
currentKey = null;
break;
}
}
else if (currentKey == "description" && current != null)
{
// This line handles multi-line description values.
// If the previous key was "description" and the current line does not contain a new key=value pair,
// it is considered a continuation of the description.
// We append the new line to the existing description, preserving line breaks with "\n".
current.Description += "\n" + trimmedLine;
}
}
}
@@ -115,10 +144,14 @@ namespace CFixer.Views
return result;
}
/// <summary>
/// Downloads and installs checked plugins.
/// If force is true, existing files will be overwritten.
/// </summary>
private async Task InstallPlugins(bool force = false)
{
var checkedIndices = listBoxPlugins.CheckedIndices;
if (checkedIndices.Count == 0)
var checkedItems = listPlugins.CheckedItems.Cast<ListViewItem>().ToList();
if (checkedItems.Count == 0)
{
MessageBox.Show("Please check one or more plugins to download.");
return;
@@ -129,18 +162,22 @@ namespace CFixer.Views
progressBarDownload.Visible = true;
progressBarDownload.Value = 0;
progressBarDownload.Maximum = checkedIndices.Count;
progressBarDownload.Maximum = checkedItems.Count;
int done = 0;
using (var client = new WebClient())
{
foreach (int index in checkedIndices)
foreach (var item in checkedItems)
{
var plugin = plugins[index];
var plugin = item.Tag as PluginEntry;
if (plugin == null)
continue;
string file = Path.Combine(savePath, Path.GetFileName(plugin.Url));
if (!force && File.Exists(file)) // skip only if not in forcemode
// Skip download if file exists and not forcing overwrite
if (!force && File.Exists(file))
{
progressBarDownload.Value = ++done;
continue;
@@ -150,7 +187,8 @@ namespace CFixer.Views
{
await client.DownloadFileTaskAsync(new Uri(plugin.Url), file);
installedPlugins.Add(Path.GetFileName(plugin.Url));
listBoxPlugins.Items[index] = plugin.Name + " (Installed)";
item.SubItems[1].Text = "Yes"; // Update Installed column
//item.Checked = true; // Ensure checked
}
catch (Exception ex)
{
@@ -164,73 +202,190 @@ namespace CFixer.Views
progressBarDownload.Visible = false;
}
private async void btnPluginInstall_Click(object sender, EventArgs e)
{
await InstallPlugins(force: false); // skip installed
}
/// <summary>
/// Updates all plugins by selecting all and force-downloading them.
/// </summary>
private async void btnPluginUpdateAll_Click(object sender, EventArgs e)
{
// check every item
for (int i = 0; i < listBoxPlugins.Items.Count; i++)
listBoxPlugins.SetItemChecked(i, true);
// Check all items in the list
foreach (ListViewItem item in listPlugins.Items)
{
item.Checked = true;
}
// Force install (overwrite even if already installed)
await InstallPlugins(force: true);
// Update the status of all plugins to "Updated"
foreach (ListViewItem item in listPlugins.Items)
{
item.SubItems[1].Text = "Updated";
}
await InstallPlugins(force: true); // always overwrite
MessageBox.Show("All plugins updated.");
}
private void listBoxPlugins_SelectedIndexChanged(object sender, EventArgs e)
{
int index = listBoxPlugins.SelectedIndex;
if (index >= 0 && index < plugins.Count)
{
btnDescription.Text = plugins[index].Description;
}
}
private void btnPluginOpen_Click(object sender, EventArgs e)
{
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
if (Directory.Exists(pluginPath))
{
System.Diagnostics.Process.Start("explorer.exe", pluginPath);
}
else
{
MessageBox.Show("The plugins folder does not exist yet.");
}
}
private void btnPluginRemove_Click(object sender, EventArgs e)
{
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
var indices = listBoxPlugins.CheckedIndices.Cast<int>().ToList();
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
if (indices.Count == 0)
var checkedItems = listPlugins.CheckedItems.Cast<ListViewItem>().ToList();
if (checkedItems.Count == 0)
{
MessageBox.Show("No plugins selected.");
return;
}
foreach (int i in indices)
foreach (var item in checkedItems)
{
var plugin = plugins[i];
var plugin = item.Tag as PluginEntry;
if (plugin == null)
continue;
string path = Path.Combine(pluginPath, Path.GetFileName(plugin.Url));
if (File.Exists(path))
File.Delete(path);
listBoxPlugins.Items[i] = plugin.Name; // Remove (Installed) tag
listBoxPlugins.SetItemChecked(i, false); // Uncheck
installedPlugins.Remove(Path.GetFileName(plugin.Url));
item.SubItems[1].Text = "No";
item.Checked = false;
}
MessageBox.Show("Selected plugins removed.");
}
private void btnPluginEdit_Click(object sender, EventArgs e)
{
if (listPlugins.SelectedItems.Count == 0)
{
MessageBox.Show("Please select a plugin first.");
return;
}
var plugin = listPlugins.SelectedItems[0].Tag as PluginEntry;
if (plugin == null) return;
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins", Path.GetFileName(plugin.Url));
if (!File.Exists(path))
{
MessageBox.Show("Plugin file not found. Please install the plugin first.");
return;
}
try
{
var ext = Path.GetExtension(path).ToLower();
var editor = ext == ".ps1" ? "powershell_ise.exe" : "notepad.exe";
Process.Start(editor, $"\"{path}\"");
}
catch (Exception ex)
{
MessageBox.Show("Could not open plugin: " + ex.Message);
}
}
/// <summary>
/// Shows plugin information in a MessageBox.
/// </summary>
private void btnHelp_Click(object sender, EventArgs e)
{
if (listPlugins.SelectedItems.Count == 0)
{
MessageBox.Show("Please select a plugin first.");
return;
}
var plugin = listPlugins.SelectedItems[0].Tag as PluginEntry;
if (plugin != null)
{
MessageBox.Show(plugin.Description, $"Info: {plugin.Name}");
}
}
private void listPlugins_SelectedIndexChanged(object sender, EventArgs e)
{
if (listPlugins.SelectedItems.Count == 0)
return;
var plugin = listPlugins.SelectedItems[0].Tag as PluginEntry;
if (plugin != null)
{
btnDescription.Text = plugin.Description;
}
}
/// <summary>
/// Updates the ListView with filtered plugin entries,
/// including name, install status, and plugin type.
/// Type is determined by plugin name ("(NX)" means native plugin),
/// or file extension (.ps1 = Powershell; others = Other).
/// </summary>
private void UpdateVisiblePlugins(string query = "")
{
visiblePlugins = plugins
.Where(p =>
p.Name.ToLower().Contains(query) ||
(p.Description?.ToLower() ?? "").Contains(query))
.ToList();
listPlugins.Items.Clear();
foreach (var plugin in visiblePlugins)
{
var fileName = Path.GetFileName(plugin.Url);
bool isInstalled = installedPlugins.Contains(fileName);
// Determine plugin type
string type;
if (plugin.Name.Trim().EndsWith("(NX)", StringComparison.OrdinalIgnoreCase))
{
type = "NX";
}
else if (Path.GetExtension(plugin.Url).Equals(".ps1", StringComparison.OrdinalIgnoreCase))
{
type = "Powershell";
}
else
{
type = "Other";
}
var item = new ListViewItem(plugin.Name);
item.SubItems.Add(isInstalled ? "Yes" : "No");
item.SubItems.Add(type);
item.Tag = plugin;
item.Checked = isInstalled;
listPlugins.Items.Add(item);
}
// Auto-resize columns to fit header and content
foreach (ColumnHeader column in listPlugins.Columns)
{
column.Width = -2;
}
}
private void textSearch_TextChanged(object sender, EventArgs e)
{
string query = textSearch.Text.Trim().ToLower();
UpdateVisiblePlugins(query);
}
private void textSearch_Click(object sender, EventArgs e)
{
textSearch.Text = string.Empty;
}
private void btnPluginSubmit_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
@@ -239,5 +394,10 @@ namespace CFixer.Views
UseShellExecute = true
});
}
private void linkPluginUsage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Process.Start("https://github.com/builtbybel/CrapFixer/blob/main/plugins/DemoPluginPack.ps1");
}
}
}
+21 -10
View File
@@ -31,31 +31,29 @@
this.checkSaveToINI = new System.Windows.Forms.CheckBox();
this.checkBox2 = new System.Windows.Forms.CheckBox();
this.button1 = new System.Windows.Forms.Button();
this.checkInstallIcons = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// checkSaveToINI
//
this.checkSaveToINI.AutoSize = true;
this.checkSaveToINI.Checked = true;
this.checkSaveToINI.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkSaveToINI.Location = new System.Drawing.Point(15, 44);
this.checkSaveToINI.Location = new System.Drawing.Point(15, 48);
this.checkSaveToINI.Name = "checkSaveToINI";
this.checkSaveToINI.Size = new System.Drawing.Size(135, 17);
this.checkSaveToINI.Size = new System.Drawing.Size(148, 17);
this.checkSaveToINI.TabIndex = 0;
this.checkSaveToINI.Text = "Save settings to INI file";
this.checkSaveToINI.Text = "Save all settings to INI file";
this.checkSaveToINI.UseVisualStyleBackColor = true;
//
// checkBox2
//
this.checkBox2.AutoSize = true;
this.checkBox2.Checked = true;
this.checkBox2.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBox2.Enabled = false;
this.checkBox2.Location = new System.Drawing.Point(15, 67);
this.checkBox2.Location = new System.Drawing.Point(15, 71);
this.checkBox2.Name = "checkBox2";
this.checkBox2.Size = new System.Drawing.Size(211, 17);
this.checkBox2.Size = new System.Drawing.Size(236, 35);
this.checkBox2.TabIndex = 1;
this.checkBox2.Text = "Activate Plugins for PowerShell Tooling";
this.checkBox2.Text = "Activate Plugins for PowerShell Tooling (Super Plugins)";
this.checkBox2.UseVisualStyleBackColor = true;
//
// button1
@@ -74,11 +72,23 @@
this.button1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.button1.UseVisualStyleBackColor = false;
//
// checkInstallIcons
//
this.checkInstallIcons.AutoSize = true;
this.checkInstallIcons.Location = new System.Drawing.Point(15, 112);
this.checkInstallIcons.Name = "checkInstallIcons";
this.checkInstallIcons.Size = new System.Drawing.Size(265, 17);
this.checkInstallIcons.TabIndex = 4;
this.checkInstallIcons.Text = "Download optional icons to enhance navigation UI";
this.checkInstallIcons.UseVisualStyleBackColor = true;
this.checkInstallIcons.CheckedChanged += new System.EventHandler(this.checkInstallIcons_CheckedChanged);
//
// SettingsView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.White;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
this.Controls.Add(this.checkInstallIcons);
this.Controls.Add(this.button1);
this.Controls.Add(this.checkBox2);
this.Controls.Add(this.checkSaveToINI);
@@ -95,5 +105,6 @@
private System.Windows.Forms.CheckBox checkSaveToINI;
private System.Windows.Forms.CheckBox checkBox2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.CheckBox checkInstallIcons;
}
}
+71
View File
@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
namespace CFixer.Views
@@ -10,6 +13,7 @@ namespace CFixer.Views
{
InitializeComponent();
LoadSettings();
CheckIfIconsInstalled();
}
/// <summary>
@@ -38,5 +42,72 @@ namespace CFixer.Views
{
SaveSettings();
}
private void CheckIfIconsInstalled()
{
string iconFolder = Path.Combine(Application.StartupPath, "icons");
string[] requiredIcons = { "fixer.png", "options.png", "restore.png" };
bool allIconsExist = requiredIcons.All(icon => File.Exists(Path.Combine(iconFolder, icon)));
checkInstallIcons.Enabled = !allIconsExist;
}
private async void checkInstallIcons_CheckedChanged(object sender, EventArgs e)
{
var result = MessageBox.Show(
"By default, buttons have no icons to reduce app size. Enable this to download and display navigation icons." +
"\nWould you like to install it now?",
"Icons Pack Detected",
MessageBoxButtons.YesNo,
MessageBoxIcon.Information
);
if (result == DialogResult.Yes)
{
try
{
string iconFolder = Path.Combine(Application.StartupPath, "icons");
if (!Directory.Exists(iconFolder))
Directory.CreateDirectory(iconFolder);
string[] iconFiles = new string[]
{
"fixer.png",
"options.png",
"restore.png"
};
string baseUrl = "https://raw.githubusercontent.com/builtbybel/CrapFixer/main/icons/";
using (var wc = new WebClient())
{
foreach (string fileName in iconFiles)
{
string url = baseUrl + fileName;
string localPath = Path.Combine(iconFolder, fileName);
await wc.DownloadFileTaskAsync(new Uri(url), localPath);
}
}
MessageBox.Show(
"All icons have been successfully installed in the 'icons' folder!\n\n💖 Love CrapFixer? Consider supporting me with a small donation to keep this tool alive and improving!",
"Icons Installed",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
// Restart the application to apply changes
Application.Restart();
}
catch (Exception ex)
{
MessageBox.Show("❌ An error occurred while downloading the icons:\n" + ex.Message,
"Download Failed",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
}
}
+218
View File
@@ -0,0 +1,218 @@
namespace CFixer.Views
{
partial class ViveView
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Komponenten-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.dataGridView = new System.Windows.Forms.DataGridView();
this.EnabledColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.NameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.IdColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.StatusColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.InfoColumn = new System.Windows.Forms.DataGridViewLinkColumn();
this.btnApply = new System.Windows.Forms.Button();
this.btnDescription = new System.Windows.Forms.Button();
this.linkPluginUsage = new System.Windows.Forms.LinkLabel();
this.txtCustomIds = new System.Windows.Forms.TextBox();
this.lblCustomIds = new System.Windows.Forms.Label();
this.btnApplyCustom = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
this.SuspendLayout();
//
// dataGridView
//
this.dataGridView.AllowUserToAddRows = false;
this.dataGridView.AllowUserToDeleteRows = false;
this.dataGridView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.dataGridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dataGridView.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
this.dataGridView.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.dataGridView.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
this.dataGridView.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.EnabledColumn,
this.NameColumn,
this.IdColumn,
this.StatusColumn,
this.InfoColumn});
this.dataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
this.dataGridView.Location = new System.Drawing.Point(15, 46);
this.dataGridView.Name = "dataGridView";
this.dataGridView.RowHeadersVisible = false;
this.dataGridView.Size = new System.Drawing.Size(470, 305);
this.dataGridView.TabIndex = 0;
this.dataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellContentClick);
//
// EnabledColumn
//
this.EnabledColumn.FillWeight = 57.38248F;
this.EnabledColumn.HeaderText = "";
this.EnabledColumn.Name = "EnabledColumn";
this.EnabledColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.EnabledColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
//
// NameColumn
//
this.NameColumn.FillWeight = 203.0457F;
this.NameColumn.HeaderText = "Feature";
this.NameColumn.Name = "NameColumn";
//
// IdColumn
//
this.IdColumn.FillWeight = 79.85728F;
this.IdColumn.HeaderText = "ID";
this.IdColumn.Name = "IdColumn";
//
// StatusColumn
//
this.StatusColumn.FillWeight = 79.85728F;
this.StatusColumn.HeaderText = "Status";
this.StatusColumn.Name = "StatusColumn";
this.StatusColumn.ReadOnly = true;
//
// InfoColumn
//
this.InfoColumn.FillWeight = 79.85728F;
this.InfoColumn.HeaderText = "Info";
this.InfoColumn.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
this.InfoColumn.Name = "InfoColumn";
this.InfoColumn.ReadOnly = true;
this.InfoColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.InfoColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
//
// btnApply
//
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnApply.Location = new System.Drawing.Point(500, 47);
this.btnApply.Name = "btnApply";
this.btnApply.Size = new System.Drawing.Size(109, 29);
this.btnApply.TabIndex = 8;
this.btnApply.Text = "Apply selected";
this.btnApply.UseVisualStyleBackColor = true;
this.btnApply.Click += new System.EventHandler(this.btnViveApply_Click);
//
// btnDescription
//
this.btnDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.btnDescription.AutoEllipsis = true;
this.btnDescription.BackColor = System.Drawing.Color.WhiteSmoke;
this.btnDescription.FlatAppearance.BorderColor = System.Drawing.Color.Gainsboro;
this.btnDescription.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDescription.Location = new System.Drawing.Point(15, 10);
this.btnDescription.Name = "btnDescription";
this.btnDescription.Padding = new System.Windows.Forms.Padding(20, 0, 100, 0);
this.btnDescription.Size = new System.Drawing.Size(594, 25);
this.btnDescription.TabIndex = 9;
this.btnDescription.Text = "ViVe Tool";
this.btnDescription.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnDescription.UseVisualStyleBackColor = true;
//
// linkPluginUsage
//
this.linkPluginUsage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.linkPluginUsage.AutoSize = true;
this.linkPluginUsage.BackColor = System.Drawing.Color.WhiteSmoke;
this.linkPluginUsage.Location = new System.Drawing.Point(535, 16);
this.linkPluginUsage.Name = "linkPluginUsage";
this.linkPluginUsage.Size = new System.Drawing.Size(56, 13);
this.linkPluginUsage.TabIndex = 247;
this.linkPluginUsage.TabStop = true;
this.linkPluginUsage.Text = "More infos";
this.linkPluginUsage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkPluginUsage_LinkClicked);
//
// txtCustomIds
//
this.txtCustomIds.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtCustomIds.Location = new System.Drawing.Point(77, 357);
this.txtCustomIds.Multiline = true;
this.txtCustomIds.Name = "txtCustomIds";
this.txtCustomIds.Size = new System.Drawing.Size(408, 24);
this.txtCustomIds.TabIndex = 248;
//
// lblCustomIds
//
this.lblCustomIds.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.lblCustomIds.AutoSize = true;
this.lblCustomIds.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblCustomIds.Location = new System.Drawing.Point(12, 363);
this.lblCustomIds.Name = "lblCustomIds";
this.lblCustomIds.Size = new System.Drawing.Size(59, 13);
this.lblCustomIds.TabIndex = 249;
this.lblCustomIds.Text = "Custom Ids";
//
// btnApplyCustom
//
this.btnApplyCustom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnApplyCustom.Location = new System.Drawing.Point(500, 355);
this.btnApplyCustom.Name = "btnApplyCustom";
this.btnApplyCustom.Size = new System.Drawing.Size(109, 29);
this.btnApplyCustom.TabIndex = 250;
this.btnApplyCustom.Text = "Apply Custom";
this.btnApplyCustom.UseVisualStyleBackColor = true;
this.btnApplyCustom.Click += new System.EventHandler(this.btnApplyCustom_Click);
//
// ViveView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
this.Controls.Add(this.btnApplyCustom);
this.Controls.Add(this.lblCustomIds);
this.Controls.Add(this.txtCustomIds);
this.Controls.Add(this.linkPluginUsage);
this.Controls.Add(this.btnDescription);
this.Controls.Add(this.btnApply);
this.Controls.Add(this.dataGridView);
this.Name = "ViveView";
this.Size = new System.Drawing.Size(625, 395);
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.DataGridView dataGridView;
private System.Windows.Forms.Button btnApply;
private System.Windows.Forms.Button btnDescription;
private System.Windows.Forms.LinkLabel linkPluginUsage;
private System.Windows.Forms.TextBox txtCustomIds;
private System.Windows.Forms.Label lblCustomIds;
private System.Windows.Forms.Button btnApplyCustom;
private System.Windows.Forms.DataGridViewCheckBoxColumn EnabledColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn NameColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn IdColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn StatusColumn;
private System.Windows.Forms.DataGridViewLinkColumn InfoColumn;
}
}
+330
View File
@@ -0,0 +1,330 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CFixer.Views
{
public partial class ViveView : UserControl
{
private List<ViveFeature> featureList;
private string viveToolPath;
public ViveView()
{
InitializeComponent();
IsViveToolAvailable();
InitFeatureList();
LoadFeaturesToGrid();
// Fire and forget async call
_ = UpdateFeatureStatusFromSystem();
}
private void IsViveToolAvailable()
{
string pluginsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
var viveFolder = Directory.GetDirectories(pluginsDir)
.FirstOrDefault(dir => Path.GetFileName(dir).ToLower().StartsWith("vive"));
if (viveFolder == null)
{
viveToolPath = null;
btnDescription.Text = "Enable experimental and hidden features (Disabled)";
return;
}
string exePath = Path.Combine(viveFolder, "ViVeTool.exe");
if (File.Exists(exePath))
{
viveToolPath = exePath;
btnDescription.Text = "Enable experimental and hidden features (Enabled)";
}
}
/// <summary>
/// Initializes hardcoded feature list with names, IDs and default states.
/// </summary>
private void InitFeatureList()
{
featureList = new List<ViveFeature>
{
new ViveFeature
{
Ids = new List<int> {47205210, 49221331, 49381526, 49402389, 49820095, 55495322, 48433719},
Name = "Enable the redesigned Windows 11 Start menu",
InfoUrl = "https://www.neowin.net/guides/how-to-enable-the-redesigned-windows-11-start-menu/",
Enabled = false
},
new ViveFeature
{
Ids = new List<int> {52467192,53079680},
Name = "Enable Text extractor in Snipping Tool",
InfoUrl = "https://blogs.windows.com/windows-insider/2025/04/15/text-extractor-in-snipping-tool-begins-rolling-out-to-windows-insiders/",
Enabled = false
}
,new ViveFeature
{
Ids = new List<int> {45624564},
Name = "Enable Drag Tray Share UI",
InfoUrl = "https://www.neowin.net/news/windows-11-is-getting-a-quirky-new-way-to-share-files/",
Enabled = false
}
};
}
/// <summary>
/// Loads the feature list into the DataGridView UI.
/// </summary>
private void LoadFeaturesToGrid()
{
dataGridView.Rows.Clear();
foreach (var feature in featureList)
{
int rowIndex = dataGridView.Rows.Add();
var row = dataGridView.Rows[rowIndex];
row.Cells["EnabledColumn"].Value = feature.Enabled;
row.Cells["NameColumn"].Value = feature.Name;
row.Cells["IdColumn"].Value = feature.IdsAsString;
row.Cells["InfoColumn"].Value = feature.InfoUrl;
row.Cells["StatusColumn"].Value = "Unknown";
}
}
/// <summary>
/// Executes ViVeTool with given feature IDs and state.
/// </summary>
private void ApplyFeature(List<int> ids, bool enable)
{
if (string.IsNullOrEmpty(viveToolPath))
{
MessageBox.Show("ViVeTool not found. Please ensure it is installed in the plugins folder.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string action = enable ? "/enable" : "/disable";
string idArg = string.Join(",", ids);
string args = $"{action} /id:{idArg}";
Process.Start(new ProcessStartInfo
{
FileName = viveToolPath,
Arguments = args,
UseShellExecute = true,
CreateNoWindow = true,
Verb = "runas" // Run as administrator
});
}
/// <summary>
/// Applies the currently selected states from the DataGridView to the system using ViVeTool.
/// </summary>
private async void btnViveApply_Click(object sender, EventArgs e)
{
for (int i = 0; i < dataGridView.Rows.Count; i++)
{
var row = dataGridView.Rows[i];
if (row.IsNewRow) continue;
bool isEnabled = Convert.ToBoolean(row.Cells["EnabledColumn"].Value);
string idText = row.Cells["IdColumn"].Value.ToString();
List<int> ids = idText.Split(',').Select(s => int.Parse(s.Trim())).ToList();
ApplyFeature(ids, isEnabled);
}
Task.Delay(1000).Wait();
await UpdateFeatureStatusFromSystem(); // Refresh the status after applying changes
MessageBox.Show("Features have been applied.", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// Queries the current system state using ViVeTool and returns a map of ID => isEnabled.
/// </summary>
// Pro ID ein Query machen, um den Status exakt zu ermitteln
private Dictionary<int, bool> QueryCurrentFeatureStates()
{
var statusMap = new Dictionary<int, bool>();
if (string.IsNullOrEmpty(viveToolPath))
{
MessageBox.Show("ViVeTool not found. Please ensure it is installed in the plugins folder.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return statusMap;
}
var allIds = featureList.SelectMany(f => f.Ids).Distinct();
foreach (int id in allIds)
{
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = viveToolPath,
Arguments = $"/query /id:{id}",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
using (Process proc = Process.Start(psi))
{
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
bool enabled = output.Contains("Enabled");
statusMap[id] = enabled;
}
}
return statusMap;
}
/// <summary>
/// Asynchronously updates the grid checkboxes and status labels to reflect actual feature states on the system.
/// </summary>
private async Task UpdateFeatureStatusFromSystem()
{
// Run QueryCurrentFeatureStates on a background thread
var systemStatus = await Task.Run(() => QueryCurrentFeatureStates());
// Update UI on the UI thread
if (dataGridView.InvokeRequired)
{
dataGridView.Invoke(new Action(() =>
{
UpdateGridWithStatus(systemStatus);
}));
}
else
{
UpdateGridWithStatus(systemStatus);
}
}
/// <summary>
/// Updates the grid rows with the given status dictionary.
/// </summary>
private void UpdateGridWithStatus(Dictionary<int, bool> systemStatus)
{
foreach (DataGridViewRow row in dataGridView.Rows)
{
if (row.IsNewRow) continue;
string idText = row.Cells["IdColumn"].Value.ToString();
var ids = idText.Split(',').Select(s => int.Parse(s.Trim())).ToList();
int enabledCount = ids.Count(id => systemStatus.ContainsKey(id) && systemStatus[id]);
string status = "Disabled";
if (enabledCount == ids.Count)
status = "All Enabled";
else if (enabledCount > 0)
status = "Partially Enabled";
row.Cells["StatusColumn"].Value = status;
}
}
private void dataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == dataGridView.Columns["InfoColumn"].Index && e.RowIndex >= 0)
{
var url = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString();
if (!string.IsNullOrEmpty(url))
{
try
{
Process.Start(new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
}
catch (Exception ex)
{
MessageBox.Show($"Failed to open link:\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
/// <summary>
/// Represents a single ViVe feature group.
/// </summary>
public class ViveFeature
{
public List<int> Ids { get; set; }
public string Name { get; set; }
public bool Enabled { get; set; }
public string InfoUrl { get; set; }
public string IdsAsString => string.Join(",", Ids);
}
private void linkPluginUsage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
MessageBox.Show("This plugin uses ViVeTool to enable hidden Windows features.\n" +
"Please download ViVeTool (e.g. 'ViVeTool-v0.3.x-IntelAmd') from:\n" +
"https://github.com/thebookisclosed/ViVe/releases\n" +
"Extract it and place the contents into a subfolder inside the 'plugins' directory.\n\n");
}
private void btnApplyCustom_Click(object sender, EventArgs e)
{
string input = txtCustomIds.Text;
if (string.IsNullOrWhiteSpace(input))
{
MessageBox.Show("Please enter one or more feature IDs.", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// Parse input (e.g., "123,456,789")
var idList = new List<int>();
var parts = input.Split(',');
foreach (var part in parts)
{
if (int.TryParse(part.Trim(), out int id))
{
idList.Add(id);
}
else
{
MessageBox.Show($"Invalid ID: '{part}'", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
if (idList.Count == 0)
{
MessageBox.Show("No valid IDs found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// Ask whether to enable or disable
var result = MessageBox.Show(
$"Do you want to ENABLE these features?\n\n{string.Join(", ", idList)}\n\n" +
"Yes = Enable\nNo = Disable\nCancel = Abort",
"Confirm Action",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);
if (result == DialogResult.Cancel) return;
bool enable = (result == DialogResult.Yes);
ApplyFeature(idList, enable);
MessageBox.Show("Custom feature action sent to ViVeTool.", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
+150
View File
@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="EnabledColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="NameColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="IdColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="StatusColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="InfoColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="EnabledColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="NameColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="IdColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="StatusColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="InfoColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>
+5 -7
View File
@@ -1,11 +1,9 @@
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">it&#39;s called CrapFixer. let that clean in🧽<a href="https://t.co/UP2iLnAgif">https://t.co/UP2iLnAgif</a><a href="https://twitter.com/hashtag/CrapFixer?src=hash&amp;ref_src=twsrc%5Etfw">#CrapFixer</a> <a href="https://twitter.com/hashtag/Windows?src=hash&amp;ref_src=twsrc%5Etfw">#Windows</a> <a href="https://twitter.com/hashtag/Windows11?src=hash&amp;ref_src=twsrc%5Etfw">#Windows11</a> <a href="https://twitter.com/hashtag/app?src=hash&amp;ref_src=twsrc%5Etfw">#app</a> <a href="https://twitter.com/hashtag/microsoft?src=hash&amp;ref_src=twsrc%5Etfw">#microsoft</a> <a href="https://t.co/OMruEjvuUb">pic.twitter.com/OMruEjvuUb</a></p>&mdash; Belim (@builtbybel) <a href="https://twitter.com/builtbybel/status/1917594071582773272?ref_src=twsrc%5Etfw">April 30, 2025</a></blockquote>
# Crap F🧼xer
# Crap F🧼xer Fixes the crap Windows leaves behind.
# The tool that says what everyone's thinking
## The tool Microsoft would build if they hated bloatware as much as we do
## The tool that says what everyone's thinking
Remember the days when you'd run a registry cleaner even if you didn't really need it? (Or maybe we did need it? I was probably too young to figure that out - too young for that crap 😅) <br>Back then, cleaner tools like CCleaner were everywhere; it felt like every other tech forum had a "top 10 Windows Optimizers" list.
@@ -15,9 +13,9 @@ This is my personal little IT toolbox that I've been using for years to clean up
CrapFixer still looks like something straight out of the Windows XP era (maybe Crap Cleaner 😄) - and honestly, that's exactly the vibe I was going for. Sometimes simple just beats fancy. Two clicks: 'Analyze', check the results, 'Fix' - done. No drama, no bloat.
While cleaning up my GitHub (30+ repos down to 20 now), I also cleaned up thousands of lines of old code. Some projects come and go, but CrapFixer stays. It's fast, simple, and basically bulletproof. I haven't managed to break anything yet. 😉 <br>If you like old-school tools that just work, you're gonna feel right at home. <br>If there's enough interest, I'll also commit the updated code to GitHub soon.
While cleaning up my GitHub (30+ repos down to 20 now), I also cleaned up thousands of lines of old code. Some projects come and go, but CrapFixer stays. It's fast, simple, and basically bulletproof. I haven't managed to break anything yet. 😉 <br>If you like old-school tools that just work, you're gonna feel right at home. <br>
![explorer_xu59FtMUnG](https://github.com/user-attachments/assets/fe462326-ebfb-41ea-83b5-d4cf72659c2d)
![CrapFixer](https://github.com/user-attachments/assets/cff37456-5676-4e3a-85a7-0c71e39e2bd0)
<details>
@@ -41,7 +39,7 @@ If you're curious about the personal story behind this project and others...
- **Gray** items = Already optimized
3. **Apply Fixes**
Smash the **"Run CFixer!"** button to apply the recommended tweaks.
Smash the **"Run Fixer"** button to apply the recommended tweaks.
> ⚠️ **Tip:** To view what a tweak does you can **Right-Click** on an item and select **Help** or hit **F1**.
> The help system also includes an online lookup that will search the tweak online for you.
+90 -60
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CrapFixer Update Check</title>
<title>Crap Fixer Update Check</title>
<style>
:root {
--bg: #f3f6fd;
@@ -60,56 +60,53 @@
text-decoration: underline;
}
.donate {
margin-top: 2rem;
padding: 1.5rem;
background-color: #e7f5ec;
border-left: 6px solid #4caf50;
border-radius: var(--radius);
box-shadow: var(--shadow);
max-width: 500px;
width: 100%;
}
.donate-box {
font-family: Verdana, Geneva, sans-serif;
font-size: 13px;
background-color: #fffde5;
border: 1px solid #ccc;
padding: 15px;
max-width: 340px;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
margin-top: 2rem;
color: #333;
}
.donate strong {
display: block;
font-size: 1.2rem;
margin-bottom: 0.5rem;
}
.donate-box h3 {
margin-top: 0;
font-size: 14px;
color: #444;
}
.donate a {
margin-top: 1rem;
display: inline-block;
padding: 0.6rem 1.2rem;
background-color: #4caf50;
color: white;
border-radius: 8px;
transition: background 0.3s ease;
}
.donate-box a {
color: #0066cc;
text-decoration: none;
}
.donate a:hover {
background-color: #388e3c;
}
.donate-box a:hover {
text-decoration: underline;
}
.project-follow {
margin-top: 2rem;
text-align: center;
}
.project-follow {
margin-top: 2rem;
text-align: center;
}
.project-follow a {
padding: 0.8rem 1.5rem;
background: #24292f;
color: white;
border-radius: var(--radius);
text-decoration: none;
font-size: 1rem;
transition: background 0.3s ease;
display: inline-block;
}
.project-follow a {
padding: 0.8rem 1.5rem;
background: #24292f;
color: white;
border-radius: 12px;
text-decoration: none;
font-size: 1rem;
transition: background 0.3s ease;
display: inline-block;
}
.project-follow a:hover {
background: #0366d6;
}
.project-follow a:hover {
background: #0366d6;
}
@media (max-width: 600px) {
body {
@@ -129,21 +126,39 @@
<!-- Main Content -->
<p id="status">Checking version...</p>
<div class="donate">
<strong>💖 Support CrapFixer</strong>
Every donation helps me provide more updates. Thanks, Belim 🙏
<br /><br />
<a href="https://www.paypal.com/donate/?hosted_button_id=M9DW4VNKH9ECQ" target="_blank">💸 PayPal</a>
<a href="https://ko-fi.com/builtbybel" target="_blank" style="background-color: #ff5f5f;">☕ Ko-fi</a>
</div>
<div class="donate-box">
<h3>How can I help?</h3>
<p>
If you like this software, you can help by <a href="https://twitter.com/intent/tweet?text=Still%20cleaning%20up%20Windows%20like%20it%E2%80%99s%202005.%20CrapFixer%20fixes%20the%20crap%20Windows%20leaves%20behind.%20https%3A%2F%2Fgithub.com%2Fbuiltbybel%2FCrapFixer" target="_blank">tweeting about it</a> or <strong>supporting the project</strong> with a donation.
</p>
<p>
Although this software is free, any donations — large or small — are greatly appreciated :)
</p>
<form action="https://www.paypal.com/donate" method="post" target="_blank" style="margin-top: 10px;">
<input type="hidden" name="hosted_button_id" value="M9DW4VNKH9ECQ" />
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" name="submit" alt="Donate with PayPal" />
</form>
<p style="margin-top: 1rem;">
Or support me with a coffee: <a href="https://ko-fi.com/builtbybel" target="_blank">☕ Ko-fi</a>
</p>
<p style="margin-top: 1rem;">
Just like the good old tools from back in the day — built with care, running on caffeine and community support ☕💾
</p>
</div>
<div class="project-follow">
<a href="https://github.com/builtbybel/CrapFixer" target="_blank">🐙 Follow CrapFixer on GitHub</a>
</div>
<div class="project-follow">
<a href="https://github.com/builtbybel/CrapFixer" target="_blank">🐙 View on GitHub</a>
</div>
<!-- Update Logic Script -->
<script>
const latestVersion = "1.5.282";
const latestVersion = "1.30.243";
function compareVersions(v1, v2) {
const a = v1.split(".").map(Number);
@@ -154,7 +169,13 @@
}
return 0;
}
<!-- Changelog link -->
function openChangelog(version) {
const url = `https://github.com/builtbybel/CrapFixer/releases/tag/${version}`;
window.open(url, "changelogWindow", "width=800,height=600,resizable=yes,scrollbars=yes");
}
const params = new URLSearchParams(window.location.search);
const userVersion = params.get("version");
@@ -167,13 +188,22 @@
const result = compareVersions(userVersion, latestVersion);
if (result < 0) {
status.innerHTML = `⚠️ Your version (${userVersion}) is outdated.<br><strong>Latest version:</strong> ${latestVersion}<br><a href="https://github.com/builtbybel/CrapFixer/releases">⬇️ Download here</a>`;
status.innerHTML = `
⚠️ Your version (${userVersion}) is outdated.<br>
<strong>Latest version:</strong> ${latestVersion}<br>
<a href="https://github.com/builtbybel/CrapFixer/releases" target="_blank">⬇️ Download here</a>
&nbsp;|&nbsp;
<a href="#" onclick="openChangelog('${latestVersion}')">📄 View Changelog</a>
`;
} else if (result === 0) {
status.innerHTML = `✅ Your version (${userVersion}) is up to date.`;
status.innerHTML = `✅ Your version (${userVersion}) is up to date.<br>
<a href="#" onclick="openChangelog('${latestVersion}')">📄 View Changelog</a>`;
} else {
status.innerHTML = `✅ Your version (${userVersion}) is newer than the official release (${latestVersion}).<br><em>Note: You may be using a development build.</em>`;
status.innerHTML = `✅ Your version (${userVersion}) is newer than the official release (${latestVersion}).<br><em>Note: You may be using a development build.</em><br>
<a href="#" onclick="openChangelog('${latestVersion}')">📄 View Changelog</a>`;
}
}
</script>
</body>
</html>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+3
View File
@@ -1,6 +1,9 @@
# Whitelist entries (do not flag these)
!GetHelp
# Global hide via wildcard. Remove ! to unhide all.
!*.*
# Bloatware patterns
Solitaire
CandyCrush
+1
View File
@@ -12,6 +12,7 @@ url=https://raw.githubusercontent.com/builtbybel/Crapfixer/refs/heads/main/plugi
[Remove Windows AI]
description=Disables and removes AI-related features and integrations in Windows.
Developer: zoicware | Web: https://github.com/zoicware/RemoveWindowsAI
url=https://raw.githubusercontent.com/builtbybel/Crapfixer/refs/heads/main/plugins/Remove Windows AI.ps1
[Restart Explorer]