diff --git a/ZuneModCore/Mod.cs b/ZuneModCore/Mod.cs
index 6526cdf..5e4b31c 100644
--- a/ZuneModCore/Mod.cs
+++ b/ZuneModCore/Mod.cs
@@ -6,85 +6,82 @@ using System.IO;
using System.Threading.Tasks;
using ZuneModCore.Mods;
-namespace ZuneModCore
+namespace ZuneModCore;
+
+public abstract class Mod
{
- public abstract class Mod
+ ///
+ /// A list of all available mods
+ ///
+ public static readonly IReadOnlyList AvailableModTypes = new List
{
- ///
- /// A list of all available mods
- ///
- public static readonly IReadOnlyList AvailableModTypes = new List
+ typeof(FeaturesOverrideMod),
+ typeof(VideoSyncMod),
+ typeof(WebservicesMod),
+ typeof(BackgroundImageMod),
+ typeof(MbidLocatorMod),
+ }.AsReadOnly();
+
+ public static string DefaultZuneInstallDir { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Zune");
+
+ public string ZuneInstallDir { get; set; } = DefaultZuneInstallDir;
+
+ private static List? _mods;
+ public static IReadOnlyList AvailableMods
+ {
+ get
{
- typeof(FeaturesOverrideMod),
- typeof(VideoSyncMod),
- typeof(WebservicesMod),
- typeof(BackgroundImageMod),
- typeof(MbidLocatorMod),
- }.AsReadOnly();
-
- public static string DefaultZuneInstallDir { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Zune");
-
- public string ZuneInstallDir { get; set; } = DefaultZuneInstallDir;
-
- private static List? _mods;
- public static IReadOnlyList AvailableMods
- {
- get
+ if (_mods is null)
{
- if (_mods is null)
+ _mods = new(AvailableModTypes.Count);
+ var services = CommunityToolkit.Mvvm.DependencyInjection.Ioc.Default;
+ foreach (var modType in AvailableModTypes)
{
- _mods = new(AvailableModTypes.Count);
- var services = CommunityToolkit.Mvvm.DependencyInjection.Ioc.Default;
- foreach (var modType in AvailableModTypes)
- {
- var instance = ActivatorUtilities.CreateInstance(services, modType);
- if (instance is Mod mod)
- _mods.Add(mod);
- }
+ var instance = ActivatorUtilities.CreateInstance(services, modType);
+ if (instance is Mod mod)
+ _mods.Add(mod);
}
- return _mods;
}
+ return _mods;
}
-
- public abstract string Id { get; }
-
- public abstract string Title { get; }
-
- public abstract string Description { get; }
-
- public abstract string Author { get; }
-
- public virtual AbstractUICollection? GetDefaultOptionsUI() => null;
-
- public virtual Task Init() => Task.CompletedTask;
-
- public abstract Task Apply();
-
- public abstract Task Reset();
-
- private AbstractUICollection? _OptionsUI;
- public AbstractUICollection? OptionsUI
- {
- get
- {
- if (_OptionsUI == null)
- _OptionsUI = GetDefaultOptionsUI();
- return _OptionsUI;
- }
- set => _OptionsUI = value;
- }
-
- public string StorageDirectory
- {
- get
- {
- string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ZuneModCore", Id);
- // Create the directory just in case the consumer assumes the folder exists already
- Directory.CreateDirectory(dir);
- return dir;
- }
- }
-
- public abstract IReadOnlyList? DependentMods { get; }
}
+
+ public abstract string Id { get; }
+
+ public abstract string Title { get; }
+
+ public abstract string Description { get; }
+
+ public abstract string Author { get; }
+
+ public virtual AbstractUICollection? GetDefaultOptionsUI() => null;
+
+ public virtual Task Init() => Task.CompletedTask;
+
+ public abstract Task Apply();
+
+ public abstract Task Reset();
+
+ private AbstractUICollection? _OptionsUI;
+ public AbstractUICollection? OptionsUI
+ {
+ get
+ {
+ return _OptionsUI ??= GetDefaultOptionsUI();
+ }
+ set => _OptionsUI = value;
+ }
+
+ public string StorageDirectory
+ {
+ get
+ {
+ string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ZuneModCore", Id);
+ // Create the directory just in case the consumer assumes the folder exists already
+ Directory.CreateDirectory(dir);
+ return dir;
+ }
+ }
+
+ public abstract IReadOnlyList? DependentMods { get; }
}
diff --git a/ZuneModCore/Mods/BackgroundImageMod.cs b/ZuneModCore/Mods/BackgroundImageMod.cs
index 3365b64..804c384 100644
--- a/ZuneModCore/Mods/BackgroundImageMod.cs
+++ b/ZuneModCore/Mods/BackgroundImageMod.cs
@@ -7,126 +7,125 @@ using System.Threading.Tasks;
using Vestris.ResourceLib;
using ZuneModCore.Win32;
-namespace ZuneModCore.Mods
+namespace ZuneModCore.Mods;
+
+public class BackgroundImageMod : Mod
{
- public class BackgroundImageMod : Mod
+ public override string Id => nameof(BackgroundImageMod);
+
+ public override string Title => "Background Image";
+
+ public override string Description => "Replaces the \"Zero\" background with an image of your choice.";
+
+ public override string Author => "Joshua \"Yoshi\" Askharoun";
+
+ public override AbstractUICollection? GetDefaultOptionsUI()
{
- public override string Id => nameof(BackgroundImageMod);
-
- public override string Title => "Background Image";
-
- public override string Description => "Replaces the \"Zero\" background with an image of your choice.";
-
- public override string Author => "Joshua \"Yoshi\" Askharoun";
-
- public override AbstractUICollection? GetDefaultOptionsUI()
+ AbstractUICollection optionsUi = new(nameof(BackgroundImageMod))
{
- AbstractUICollection optionsUi = new(nameof(BackgroundImageMod))
- {
- new AbstractTextBox("fileBox", Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)),
- };
- optionsUi.Title = "select background";
- optionsUi.Subtitle = "CHOOSE A BACKGROUND IMAGE OF YOUR CHOICE.";
- return optionsUi;
+ new AbstractTextBox("fileBox", Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)),
+ };
+ optionsUi.Title = "select background";
+ optionsUi.Subtitle = "CHOOSE A BACKGROUND IMAGE OF YOUR CHOICE.";
+ return optionsUi;
+ }
+
+ public override IReadOnlyList? DependentMods => null;
+
+ public override async Task Apply()
+ {
+ string bgimgPath = ((AbstractTextBox)OptionsUI![0]).Value;
+ FileInfo bgimgInfo = new(bgimgPath);
+ if (!bgimgInfo.Exists)
+ {
+ return $"The file '{bgimgInfo.FullName}' does not exist.";
}
- public override IReadOnlyList? DependentMods => null;
-
- public override async Task Apply()
+ FileInfo zsrDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneShellResources.dll"));
+ if (!zsrDllInfo.Exists)
{
- string bgimgPath = ((AbstractTextBox)OptionsUI![0]).Value;
- FileInfo bgimgInfo = new(bgimgPath);
- if (!bgimgInfo.Exists)
+ return $"The file '{zsrDllInfo.FullName}' does not exist.";
+ }
+
+ // Make a backup if it doesn't already exist
+ FileInfo zsrDllBackupInfo = new(Path.Combine(StorageDirectory, "ZuneShellResources.original.dll"));
+ if (!zsrDllBackupInfo.Exists)
+ {
+ File.Copy(zsrDllInfo.FullName, zsrDllBackupInfo.FullName, true);
+ }
+
+ string zsrDllTempPath = Path.Combine(StorageDirectory, zsrDllInfo.Name);
+
+ // Take ownership of DLL
+ TokenManipulator.TakeOwnership(zsrDllInfo);
+
+ try
+ {
+ using (ResourceInfo vi = new())
{
- return $"The file '{bgimgInfo.FullName}' does not exist.";
- }
-
- FileInfo zsrDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneShellResources.dll"));
- if (!zsrDllInfo.Exists)
- {
- return $"The file '{zsrDllInfo.FullName}' does not exist.";
- }
-
- // Make a backup if it doesn't already exist
- FileInfo zsrDllBackupInfo = new(Path.Combine(StorageDirectory, "ZuneShellResources.original.dll"));
- if (!zsrDllBackupInfo.Exists)
- {
- File.Copy(zsrDllInfo.FullName, zsrDllBackupInfo.FullName, true);
- }
-
- string zsrDllTempPath = Path.Combine(StorageDirectory, zsrDllInfo.Name);
-
- // Take ownership of DLL
- TokenManipulator.TakeOwnership(zsrDllInfo);
-
- try
- {
- using (ResourceInfo vi = new())
+ // Load the RCDATA section
+ vi.Load(zsrDllInfo.FullName);
+ ResourceId? resId = vi.ResourceTypes.Find(id =>
{
- // Load the RCDATA section
- vi.Load(zsrDllInfo.FullName);
- ResourceId? resId = vi.ResourceTypes.Find(id =>
+ // This must be wrapped in a try-catch block,
+ // otherwise resourcelib will error when attempting
+ // to read the WAVE type (or any other non-default type).
+ try
{
- // This must be wrapped in a try-catch block,
- // otherwise resourcelib will error when attempting
- // to read the WAVE type (or any other non-default type).
- try
- {
- return id.ResourceType == Kernel32.ResourceTypes.RT_RCDATA;
- }
- catch
- {
- return false;
- }
- });
- if (resId == null)
- return $"Failed to locate image resources in Zune software.";
+ return id.ResourceType == Kernel32.ResourceTypes.RT_RCDATA;
+ }
+ catch
+ {
+ return false;
+ }
+ });
+ if (resId == null)
+ return $"Failed to locate image resources in Zune software.";
- // Locate the image resource
- // TODO: Allow users to specify which background they want to replace
- List RCDATA = vi.Resources[resId];
- int idx = RCDATA.FindIndex(r => r.Name.Name == "FRAMEBACKGROUND06.PNG");
- if (idx < 0)
- return $"Failed to locate background image resource in Zune software.";
- GenericResource ogRes = (GenericResource)RCDATA[idx];
+ // Locate the image resource
+ // TODO: Allow users to specify which background they want to replace
+ List RCDATA = vi.Resources[resId];
+ int idx = RCDATA.FindIndex(r => r.Name.Name == "FRAMEBACKGROUND06.PNG");
+ if (idx < 0)
+ return $"Failed to locate background image resource in Zune software.";
+ GenericResource ogRes = (GenericResource)RCDATA[idx];
- // Replace image
- byte[] data = await File.ReadAllBytesAsync(bgimgInfo.FullName);
- BitmapResource newRes = new(IntPtr.Zero, IntPtr.Zero, resId, ogRes.Name, ogRes.Language, data.Length);
- newRes.Bitmap = new(data);
- RCDATA[idx] = newRes;
- File.Copy(zsrDllInfo.FullName, zsrDllTempPath, true);
- newRes.SaveTo(zsrDllTempPath);
- }
- File.Copy(zsrDllTempPath, zsrDllInfo.FullName, true);
+ // Replace image
+ byte[] data = await File.ReadAllBytesAsync(bgimgInfo.FullName);
+ BitmapResource newRes = new(IntPtr.Zero, IntPtr.Zero, resId, ogRes.Name, ogRes.Language, data.Length);
+ newRes.Bitmap = new(data);
+ RCDATA[idx] = newRes;
+ File.Copy(zsrDllInfo.FullName, zsrDllTempPath, true);
+ newRes.SaveTo(zsrDllTempPath);
+ }
+ File.Copy(zsrDllTempPath, zsrDllInfo.FullName, true);
- return null;
- }
- catch (IOException)
- {
- return $"Unable to replace '{zsrDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
- }
- catch (Exception ex)
- {
- Debug.WriteLine(ex.ToString());
- return ex.Message;
- }
+ return null;
}
-
- public override Task Reset()
+ catch (IOException)
{
- try
- {
- // Copy backup to application folder
- File.Copy(Path.Combine(StorageDirectory, "ZuneShellResources.original.dll"),
- Path.Combine(ZuneInstallDir, "ZuneShellResources.dll"), true);
+ return $"Unable to replace '{zsrDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.ToString());
+ return ex.Message;
+ }
+ }
- return Task.FromResult(null);
- }
- catch (Exception ex)
- {
- return Task.FromResult(ex.Message)!;
- }
+ public override Task Reset()
+ {
+ try
+ {
+ // Copy backup to application folder
+ File.Copy(Path.Combine(StorageDirectory, "ZuneShellResources.original.dll"),
+ Path.Combine(ZuneInstallDir, "ZuneShellResources.dll"), true);
+
+ return Task.FromResult(null);
+ }
+ catch (Exception ex)
+ {
+ return Task.FromResult(ex.Message)!;
}
}
}
diff --git a/ZuneModCore/Mods/FeaturesOverrideMod.cs b/ZuneModCore/Mods/FeaturesOverrideMod.cs
index f7142cb..224590d 100644
--- a/ZuneModCore/Mods/FeaturesOverrideMod.cs
+++ b/ZuneModCore/Mods/FeaturesOverrideMod.cs
@@ -4,116 +4,115 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using ZuneModCore.Win32;
-namespace ZuneModCore.Mods
+namespace ZuneModCore.Mods;
+
+public class FeaturesOverrideMod : Mod
{
- public class FeaturesOverrideMod : Mod
+ private const string ZUNE_FEATURESOVERRIDE_REGKEY = RegEdit.ZUNE_REG_PATH + "FeaturesOverride";
+
+ public override string Id => nameof(FeaturesOverrideMod);
+
+ public override string Title => "Features Override";
+
+ public override string Description => "Re-enables access to some features disabled by Microsoft, such as the Social and Marketplace tabs.\r\n" +
+ "Does not restore functionality of those features, but shows them in the software.";
+
+ public override string Author => "Rafael Rivera";
+
+ public override AbstractUICollection? GetDefaultOptionsUI()
{
- private const string ZUNE_FEATURESOVERRIDE_REGKEY = RegEdit.ZUNE_REG_PATH + "FeaturesOverride";
-
- public override string Id => nameof(FeaturesOverrideMod);
-
- public override string Title => "Features Override";
-
- public override string Description => "Re-enables access to some features disabled by Microsoft, such as the Social and Marketplace tabs.\r\n" +
- "Does not restore functionality of those features, but shows them in the software.";
-
- public override string Author => "Rafael Rivera";
-
- public override AbstractUICollection? GetDefaultOptionsUI()
+ AbstractUICollection optionsUi = new(nameof(FeaturesOverrideMod))
{
- AbstractUICollection optionsUi = new(nameof(FeaturesOverrideMod))
- {
- // We don't know what some of these overrides do exactly, so hide them from the user.
- // The ID is the name of the registry key, the label is the display name
+ // We don't know what some of these overrides do exactly, so hide them from the user.
+ // The ID is the name of the registry key, the label is the display name
- new AbstractBoolean("Apps", "Apps"),
- new AbstractBoolean("Art", "Art"),
- new AbstractBoolean("Channels", "Channels"),
- new AbstractBoolean("FirstLaunchIntroVideo", "First Launch Intro Video"),
- new AbstractBoolean("Games", "Games"),
- new AbstractBoolean("Marketplace", "Marketplace"),
- new AbstractBoolean("MBRPreview", "[Marketplace] Media Preview"),
- new AbstractBoolean("MBRPurchase", "[Marketplace] Media Purchase"),
- new AbstractBoolean("MBRRental", "[Marketplace] Media Rental"),
- new AbstractBoolean("Music", "Music"),
- new AbstractBoolean("MusicVideos", "Music Videos"),
- new AbstractBoolean("Nowplaying", "Now Playing"),
- new AbstractBoolean("NowplayingArt", "Now Playing Art"),
- new AbstractBoolean("Picks", "Picks"),
- new AbstractBoolean("Podcasts", "Podcasts"),
- new AbstractBoolean("QuickMixLocal", "Quick Mix (Local)"),
- new AbstractBoolean("QuickMixZMP", "Quick Mix (ZMP)"),
- new AbstractBoolean("Quickplay", "Quickplay"),
- new AbstractBoolean("Sign In Available", "Sign In"),
- new AbstractBoolean("Social", "Social"),
- new AbstractBoolean("SocialMarketplace", "Social Marketplace"),
- new AbstractBoolean("SubscriptionFreeTracks", "Subscription Free Tracks"),
- new AbstractBoolean("Videos", "Videos"),
- };
- optionsUi.Title = "select features";
- optionsUi.Subtitle = "CHOOSE WHICH ZUNE FEATURES YOU WISH TO ENABLE.";
- return optionsUi;
- }
+ new AbstractBoolean("Apps", "Apps"),
+ new AbstractBoolean("Art", "Art"),
+ new AbstractBoolean("Channels", "Channels"),
+ new AbstractBoolean("FirstLaunchIntroVideo", "First Launch Intro Video"),
+ new AbstractBoolean("Games", "Games"),
+ new AbstractBoolean("Marketplace", "Marketplace"),
+ new AbstractBoolean("MBRPreview", "[Marketplace] Media Preview"),
+ new AbstractBoolean("MBRPurchase", "[Marketplace] Media Purchase"),
+ new AbstractBoolean("MBRRental", "[Marketplace] Media Rental"),
+ new AbstractBoolean("Music", "Music"),
+ new AbstractBoolean("MusicVideos", "Music Videos"),
+ new AbstractBoolean("Nowplaying", "Now Playing"),
+ new AbstractBoolean("NowplayingArt", "Now Playing Art"),
+ new AbstractBoolean("Picks", "Picks"),
+ new AbstractBoolean("Podcasts", "Podcasts"),
+ new AbstractBoolean("QuickMixLocal", "Quick Mix (Local)"),
+ new AbstractBoolean("QuickMixZMP", "Quick Mix (ZMP)"),
+ new AbstractBoolean("Quickplay", "Quickplay"),
+ new AbstractBoolean("Sign In Available", "Sign In"),
+ new AbstractBoolean("Social", "Social"),
+ new AbstractBoolean("SocialMarketplace", "Social Marketplace"),
+ new AbstractBoolean("SubscriptionFreeTracks", "Subscription Free Tracks"),
+ new AbstractBoolean("Videos", "Videos"),
+ };
+ optionsUi.Title = "select features";
+ optionsUi.Subtitle = "CHOOSE WHICH ZUNE FEATURES YOU WISH TO ENABLE.";
+ return optionsUi;
+ }
- public override IReadOnlyList? DependentMods => null;
+ public override IReadOnlyList? DependentMods => null;
- public override Task Init()
+ public override Task Init()
+ {
+ foreach (AbstractUIElement uiElem in OptionsUI!)
{
- foreach (AbstractUIElement uiElem in OptionsUI!)
+ if (uiElem is AbstractBoolean boolElem)
{
- if (uiElem is AbstractBoolean boolElem)
- {
- bool? featureOverride = GetFeatureOverride(boolElem.Id);
- boolElem.State = featureOverride ?? false;
- }
+ bool? featureOverride = GetFeatureOverride(boolElem.Id);
+ boolElem.State = featureOverride ?? false;
}
-
- return Task.CompletedTask;
}
- public override async Task Apply() => await Apply(false);
+ return Task.CompletedTask;
+ }
- public async Task Apply(bool applyAll = false)
+ public override async Task Apply() => await Apply(false);
+
+ public async Task Apply(bool applyAll = false)
+ {
+ // Use user choices from AbstractUI
+ foreach (AbstractUIElement uiElem in OptionsUI!)
{
- // Use user choices from AbstractUI
- foreach (AbstractUIElement uiElem in OptionsUI!)
+ if (uiElem is AbstractBoolean boolElem && (boolElem.State || applyAll))
{
- if (uiElem is AbstractBoolean boolElem && (boolElem.State || applyAll))
+ bool isSuccess = SetFeatureOverride(boolElem.Id, true);
+ if (!isSuccess)
{
- bool isSuccess = SetFeatureOverride(boolElem.Id, true);
- if (!isSuccess)
+ string? resetStatus = await Reset();
+ if (resetStatus != null)
{
- string? resetStatus = await Reset();
- if (resetStatus != null)
- {
- // The reset failed as well, return both errors
- return "Failed to set registry keys. Unable to clean up partial overrides:\r\n" + resetStatus;
- }
- else
- {
- return "Failed to set registry keys. Automatically cleaned up partial changes.";
- }
+ // The reset failed as well, return both errors
+ return "Failed to set registry keys. Unable to clean up partial overrides:\r\n" + resetStatus;
+ }
+ else
+ {
+ return "Failed to set registry keys. Automatically cleaned up partial changes.";
}
}
}
-
- return null;
}
- public override async Task Reset()
- {
- RegEdit.CurrentUserDeleteKey(ZUNE_FEATURESOVERRIDE_REGKEY);
-
- return null;
- }
-
- public static bool SetFeatureOverride(string feature, bool value) =>
- RegEdit.CurrentUserSetBoolValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature, value);
-
- public static bool? GetFeatureOverride(string feature) =>
- RegEdit.CurrentUserGetBoolValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature);
-
- public static void ResetFeatureOverride(string feature) =>
- RegEdit.CurrentUserDeleteValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature);
+ return null;
}
+
+ public override async Task Reset()
+ {
+ RegEdit.CurrentUserDeleteKey(ZUNE_FEATURESOVERRIDE_REGKEY);
+
+ return null;
+ }
+
+ public static bool SetFeatureOverride(string feature, bool value) =>
+ RegEdit.CurrentUserSetBoolValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature, value);
+
+ public static bool? GetFeatureOverride(string feature) =>
+ RegEdit.CurrentUserGetBoolValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature);
+
+ public static void ResetFeatureOverride(string feature) =>
+ RegEdit.CurrentUserDeleteValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature);
}
diff --git a/ZuneModCore/Mods/MbidLocatorMod.cs b/ZuneModCore/Mods/MbidLocatorMod.cs
index 514f23a..02db4df 100644
--- a/ZuneModCore/Mods/MbidLocatorMod.cs
+++ b/ZuneModCore/Mods/MbidLocatorMod.cs
@@ -5,167 +5,163 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
-namespace ZuneModCore.Mods
+namespace ZuneModCore.Mods;
+
+public class MbidLocatorMod : Mod
{
- public class MbidLocatorMod : Mod
+ public const string ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME = "ZuneAlbumArtistMediaID";
+ public const string ZUNE_ALBUM_MEDIA_ID_NAME = "ZuneAlbumMediaID";
+ public const string ZUNE_MEDIA_ID_NAME = "ZuneMediaID";
+ public const string ZUNE_COLLECTION_ID_NAME = "ZuneCollectionID";
+
+ private static readonly string[] KNOWN_EXTS = [".mp3", ".mp4", ".m4a", ".wav"];
+
+ public override string Id => nameof(MbidLocatorMod);
+
+ public override string Title => "MusicBrainz ID Locator";
+
+ public override string Description => "Puts MusicBrainz IDs added by MusicBrainz Picard where the Zune " +
+ "software can use it to show additional information provided by Community Webservices.\r\n" +
+ "Note that this will only have an effect if you have used MusicBrainz Picard on your music library.";
+
+ public override string Author => "Joshua \"Yoshi\" Askharoun";
+
+ public override AbstractUICollection? GetDefaultOptionsUI()
{
- public const string ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME = "ZuneAlbumArtistMediaID";
- public const string ZUNE_ALBUM_MEDIA_ID_NAME = "ZuneAlbumMediaID";
- public const string ZUNE_MEDIA_ID_NAME = "ZuneMediaID";
- public const string ZUNE_COLLECTION_ID_NAME = "ZuneCollectionID";
-
- private static readonly string[] KNOWN_EXTS = new[]
+ AbstractUICollection optionsUi = new(nameof(MbidLocatorMod))
{
- ".mp3", ".mp4", ".m4a", ".wav"
+ new AbstractTextBox("folderBox", Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)),
+ new AbstractBoolean("recursiveBox", "Search recursively")
};
+ optionsUi.Title = "select music";
+ optionsUi.Subtitle = "CHOOSE YOUR MUSIC FOLDER.";
+ return optionsUi;
+ }
- public override string Id => nameof(MbidLocatorMod);
+ public override IReadOnlyList? DependentMods => null;
- public override string Title => "MusicBrainz ID Locator";
+ public override async Task Apply()
+ {
+ // Use user choices from AbstractUI
+ string folderPath = ((AbstractTextBox)OptionsUI![0]).Value;
+ bool recursive = ((AbstractBoolean)OptionsUI[1]).State;
+ string errorString = string.Empty;
- public override string Description => "Puts MusicBrainz IDs added by MusicBrainz Picard where the Zune " +
- "software can use it to show additional information provided by Community Webservices.\r\n" +
- "Note that this will only have an effect if you have used MusicBrainz Picard on your music library.";
-
- public override string Author => "Joshua \"Yoshi\" Askharoun";
-
- public override AbstractUICollection? GetDefaultOptionsUI()
+ // Verify that the folder exists
+ DirectoryInfo folder = new(folderPath);
+ if (!folder.Exists)
{
- AbstractUICollection optionsUi = new(nameof(MbidLocatorMod))
- {
- new AbstractTextBox("folderBox", Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)),
- new AbstractBoolean("recursiveBox", "Search recursively")
- };
- optionsUi.Title = "select music";
- optionsUi.Subtitle = "CHOOSE YOUR MUSIC FOLDER.";
- return optionsUi;
+ return $"The folder '{folder.FullName}' does not exist.";
}
- public override IReadOnlyList? DependentMods => null;
-
- public override async Task Apply()
+ foreach (FileInfo file in folder.GetFiles("*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
{
- // Use user choices from AbstractUI
- string folderPath = ((AbstractTextBox)OptionsUI![0]).Value;
- bool recursive = ((AbstractBoolean)OptionsUI[1]).State;
- string errorString = string.Empty;
-
- // Verify that the folder exists
- DirectoryInfo folder = new(folderPath);
- if (!folder.Exists)
+ try
{
- return $"The folder '{folder.FullName}' does not exist.";
- }
-
- foreach (FileInfo file in folder.GetFiles("*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
- {
- try
- {
- if (KNOWN_EXTS.Contains(file.Extension))
- UpdateMbidInFile(file);
+ if (KNOWN_EXTS.Contains(file.Extension))
+ UpdateMbidInFile(file);
#if DEBUG
- System.Diagnostics.Debug.WriteLine(file);
+ System.Diagnostics.Debug.WriteLine(file);
#endif
- }
- catch (Exception ex)
- {
- errorString += ex.Message + "\r\n";
- continue;
- }
}
-
- if (errorString.Length != 0)
- return errorString;
- else
- return null;
- }
-
- public override Task Reset()
- {
- return Task.FromResult(null);
- }
-
- public static void UpdateMbidInFile(FileInfo file)
- {
- var tfile = TagLib.File.Create(file.FullName);
-
- if (tfile.Tag is TagLib.Asf.Tag asfTag)
+ catch (Exception ex)
{
- var albumArtistIdDesc = asfTag.ExtendedContentDescriptionObject
- .FirstOrDefault(cd => cd.Name == ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME);
- if (albumArtistIdDesc == null && asfTag.MusicBrainzReleaseArtistId != null)
- {
- asfTag.ExtendedContentDescriptionObject.AddDescriptor(new TagLib.Asf.ContentDescriptor(
- ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME, asfTag.MusicBrainzReleaseArtistId));
- }
-
- var albumIdDesc = asfTag.ExtendedContentDescriptionObject
- .FirstOrDefault(cd => cd.Name == ZUNE_ALBUM_MEDIA_ID_NAME);
- if (albumIdDesc == null && asfTag.MusicBrainzReleaseId != null)
- {
- asfTag.ExtendedContentDescriptionObject.AddDescriptor(new TagLib.Asf.ContentDescriptor(
- ZUNE_ALBUM_MEDIA_ID_NAME, asfTag.MusicBrainzReleaseId));
- }
-
- var trackIdDesc = asfTag.ExtendedContentDescriptionObject
- .FirstOrDefault(cd => cd.Name == ZUNE_MEDIA_ID_NAME);
- if (trackIdDesc == null && asfTag.MusicBrainzTrackId != null)
- {
- asfTag.ExtendedContentDescriptionObject.AddDescriptor(new TagLib.Asf.ContentDescriptor(
- ZUNE_MEDIA_ID_NAME, asfTag.MusicBrainzTrackId));
- }
+ errorString += ex.Message + "\r\n";
+ continue;
}
- else if (tfile.Tag is TagLib.NonContainer.Tag ncTag)
- {
- var tag = ncTag.Tags.FirstOrDefault(t => t.TagTypes == TagLib.TagTypes.Id3v2);
- if (tag is TagLib.Id3v2.Tag id3v2)
- {
- var frames = id3v2.GetFrames();
-
- // Note the use of .ToList(): this is because calling RemoveFrame() will
- // modify the underlying collection, causing an exception to be thrown
- // when attempting the next iteration of the for loop
-
- if (tag.MusicBrainzReleaseArtistId != null)
- {
- foreach (var oldAlbumArtistFrame in frames.Where(f => f.Owner == ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME).ToList())
- id3v2.RemoveFrame(oldAlbumArtistFrame);
-
- TagLib.Id3v2.PrivateFrame albumArtistFrame = new(ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME)
- {
- PrivateData = new(new Guid(tag.MusicBrainzReleaseArtistId).ToByteArray())
- };
- id3v2.AddFrame(albumArtistFrame);
- }
-
- if (tag.MusicBrainzReleaseId != null)
- {
- foreach (var oldAlbumFrame in frames.Where(f => f.Owner == ZUNE_ALBUM_MEDIA_ID_NAME).ToList())
- id3v2.RemoveFrame(oldAlbumFrame);
-
- TagLib.Id3v2.PrivateFrame albumFrame = new(ZUNE_ALBUM_MEDIA_ID_NAME)
- {
- PrivateData = new(new Guid(tag.MusicBrainzReleaseId).ToByteArray())
- };
- id3v2.AddFrame(albumFrame);
- }
-
- if (tag.MusicBrainzTrackId != null)
- {
- foreach (var oldTrackFrame in frames.Where(f => f.Owner == ZUNE_MEDIA_ID_NAME).ToList())
- id3v2.RemoveFrame(oldTrackFrame);
-
- TagLib.Id3v2.PrivateFrame trackFrame = new(ZUNE_MEDIA_ID_NAME)
- {
- PrivateData = new(new Guid(tag.MusicBrainzTrackId).ToByteArray())
- };
- id3v2.AddFrame(trackFrame);
- }
- }
- }
-
- tfile.Save();
}
+
+ if (errorString.Length != 0)
+ return errorString;
+ else
+ return null;
+ }
+
+ public override Task Reset()
+ {
+ return Task.FromResult(null);
+ }
+
+ public static void UpdateMbidInFile(FileInfo file)
+ {
+ var tfile = TagLib.File.Create(file.FullName);
+
+ if (tfile.Tag is TagLib.Asf.Tag asfTag)
+ {
+ var albumArtistIdDesc = asfTag.ExtendedContentDescriptionObject
+ .FirstOrDefault(cd => cd.Name == ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME);
+ if (albumArtistIdDesc == null && asfTag.MusicBrainzReleaseArtistId != null)
+ {
+ asfTag.ExtendedContentDescriptionObject.AddDescriptor(new TagLib.Asf.ContentDescriptor(
+ ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME, asfTag.MusicBrainzReleaseArtistId));
+ }
+
+ var albumIdDesc = asfTag.ExtendedContentDescriptionObject
+ .FirstOrDefault(cd => cd.Name == ZUNE_ALBUM_MEDIA_ID_NAME);
+ if (albumIdDesc == null && asfTag.MusicBrainzReleaseId != null)
+ {
+ asfTag.ExtendedContentDescriptionObject.AddDescriptor(new TagLib.Asf.ContentDescriptor(
+ ZUNE_ALBUM_MEDIA_ID_NAME, asfTag.MusicBrainzReleaseId));
+ }
+
+ var trackIdDesc = asfTag.ExtendedContentDescriptionObject
+ .FirstOrDefault(cd => cd.Name == ZUNE_MEDIA_ID_NAME);
+ if (trackIdDesc == null && asfTag.MusicBrainzTrackId != null)
+ {
+ asfTag.ExtendedContentDescriptionObject.AddDescriptor(new TagLib.Asf.ContentDescriptor(
+ ZUNE_MEDIA_ID_NAME, asfTag.MusicBrainzTrackId));
+ }
+ }
+ else if (tfile.Tag is TagLib.NonContainer.Tag ncTag)
+ {
+ var tag = ncTag.Tags.FirstOrDefault(t => t.TagTypes == TagLib.TagTypes.Id3v2);
+ if (tag is TagLib.Id3v2.Tag id3v2)
+ {
+ var frames = id3v2.GetFrames();
+
+ // Note the use of .ToList(): this is because calling RemoveFrame() will
+ // modify the underlying collection, causing an exception to be thrown
+ // when attempting the next iteration of the for loop
+
+ if (tag.MusicBrainzReleaseArtistId != null)
+ {
+ foreach (var oldAlbumArtistFrame in frames.Where(f => f.Owner == ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME).ToList())
+ id3v2.RemoveFrame(oldAlbumArtistFrame);
+
+ TagLib.Id3v2.PrivateFrame albumArtistFrame = new(ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME)
+ {
+ PrivateData = new(new Guid(tag.MusicBrainzReleaseArtistId).ToByteArray())
+ };
+ id3v2.AddFrame(albumArtistFrame);
+ }
+
+ if (tag.MusicBrainzReleaseId != null)
+ {
+ foreach (var oldAlbumFrame in frames.Where(f => f.Owner == ZUNE_ALBUM_MEDIA_ID_NAME).ToList())
+ id3v2.RemoveFrame(oldAlbumFrame);
+
+ TagLib.Id3v2.PrivateFrame albumFrame = new(ZUNE_ALBUM_MEDIA_ID_NAME)
+ {
+ PrivateData = new(new Guid(tag.MusicBrainzReleaseId).ToByteArray())
+ };
+ id3v2.AddFrame(albumFrame);
+ }
+
+ if (tag.MusicBrainzTrackId != null)
+ {
+ foreach (var oldTrackFrame in frames.Where(f => f.Owner == ZUNE_MEDIA_ID_NAME).ToList())
+ id3v2.RemoveFrame(oldTrackFrame);
+
+ TagLib.Id3v2.PrivateFrame trackFrame = new(ZUNE_MEDIA_ID_NAME)
+ {
+ PrivateData = new(new Guid(tag.MusicBrainzTrackId).ToByteArray())
+ };
+ id3v2.AddFrame(trackFrame);
+ }
+ }
+ }
+
+ tfile.Save();
}
}
diff --git a/ZuneModCore/Mods/VideoSyncMod.cs b/ZuneModCore/Mods/VideoSyncMod.cs
index e0a1292..d302577 100644
--- a/ZuneModCore/Mods/VideoSyncMod.cs
+++ b/ZuneModCore/Mods/VideoSyncMod.cs
@@ -4,92 +4,91 @@ using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
-namespace ZuneModCore.Mods
+namespace ZuneModCore.Mods;
+
+public class VideoSyncMod : Mod
{
- public class VideoSyncMod : Mod
+ private const int ZUNEENCENG_WMVCORA_OFFSET = 0x161E;
+
+ public override string Title => "Fix Video Sync";
+
+ public override string Description =>
+ "Resolves \"Error C00D11CD\" when attempting to sync video to a Zune device using Windows 10 1607 (Anniversary Update) or newer";
+
+ public override string Author => "sylvathemoth";
+
+ public override string Id => nameof(VideoSyncMod);
+
+ public override async Task Apply()
{
- private const int ZUNEENCENG_WMVCORA_OFFSET = 0x161E;
+ // Verify that ZuneEncEng.dll exists
+ FileInfo zeeDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneEncEng.dll"));
+ if (!zeeDllInfo.Exists)
+ return $"The file '{zeeDllInfo.FullName}' does not exist.";
- public override string Title => "Fix Video Sync";
+ // Make a backup if it doesn't already exist
+ FileInfo zeeDllBackupInfo = new(Path.Combine(StorageDirectory, "ZuneEncEng.original.dll"));
+ if (!zeeDllBackupInfo.Exists)
+ File.Copy(zeeDllInfo.FullName, zeeDllBackupInfo.FullName, true);
- public override string Description =>
- "Resolves \"Error C00D11CD\" when attempting to sync video to a Zune device using Windows 10 1607 (Anniversary Update) or newer";
-
- public override string Author => "sylvathemoth";
-
- public override string Id => nameof(VideoSyncMod);
-
- public override async Task Apply()
+ try
{
- // Verify that ZuneEncEng.dll exists
- FileInfo zeeDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneEncEng.dll"));
- if (!zeeDllInfo.Exists)
- return $"The file '{zeeDllInfo.FullName}' does not exist.";
+ // Verify that the DLL is from v4.8 (other versions not tested)
+ var zeeDllVersion = FileVersionInfo.GetVersionInfo(zeeDllInfo.FullName);
+ if (zeeDllVersion is null || zeeDllVersion.FileMajorPart != 4 || zeeDllVersion.FileMinorPart != 8)
+ return "This mod has not been tested on versions earlier than 4.8.";
- // Make a backup if it doesn't already exist
- FileInfo zeeDllBackupInfo = new(Path.Combine(StorageDirectory, "ZuneEncEng.original.dll"));
- if (!zeeDllBackupInfo.Exists)
- File.Copy(zeeDllInfo.FullName, zeeDllBackupInfo.FullName, true);
-
- try
+ // Open the file
+ using (FileStream zeeDll = zeeDllInfo.Open(FileMode.Open))
+ using (BinaryWriter zeeDllWriter = new(zeeDll))
{
- // Verify that the DLL is from v4.8 (other versions not tested)
- var zeeDllVersion = FileVersionInfo.GetVersionInfo(zeeDllInfo.FullName);
- if (zeeDllVersion is null || zeeDllVersion.FileMajorPart != 4 || zeeDllVersion.FileMinorPart != 8)
- return "This mod has not been tested on versions earlier than 4.8.";
+ // Patch ZuneEncEng.dll to point to the local WMVCORE.DLL
+ zeeDllWriter.Seek(ZUNEENCENG_WMVCORA_OFFSET, SeekOrigin.Begin);
+ zeeDllWriter.Write((byte)'a');
- // Open the file
- using (FileStream zeeDll = zeeDllInfo.Open(FileMode.Open))
- using (BinaryWriter zeeDllWriter = new(zeeDll))
- {
- // Patch ZuneEncEng.dll to point to the local WMVCORE.DLL
- zeeDllWriter.Seek(ZUNEENCENG_WMVCORA_OFFSET, SeekOrigin.Begin);
- zeeDllWriter.Write((byte)'a');
-
- zeeDllWriter.Flush();
- }
-
- // Get the working WMVCORE.dll
- byte[] wmvDllAniv = ModResources.WMVCORE;
-
- // Copy the WMVCore files to the Zune directory.
- // Only ZuneEncEng.dll searches in System32 first; all other dependent
- // DLLs will search the Zune folder.
- await File.WriteAllBytesAsync(Path.Combine(ZuneInstallDir, "wmvcora.dll"), wmvDllAniv);
- await File.WriteAllBytesAsync(Path.Combine(ZuneInstallDir, "wmvcore.dll"), wmvDllAniv);
-
- return null;
- }
- catch (IOException)
- {
- return $"Unable to replace '{zeeDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
- }
- catch (Exception ex)
- {
- return ex.Message;
+ zeeDllWriter.Flush();
}
+
+ // Get the working WMVCORE.dll
+ byte[] wmvDllAniv = ModResources.WMVCORE;
+
+ // Copy the WMVCore files to the Zune directory.
+ // Only ZuneEncEng.dll searches in System32 first; all other dependent
+ // DLLs will search the Zune folder.
+ await File.WriteAllBytesAsync(Path.Combine(ZuneInstallDir, "wmvcora.dll"), wmvDllAniv);
+ await File.WriteAllBytesAsync(Path.Combine(ZuneInstallDir, "wmvcore.dll"), wmvDllAniv);
+
+ return null;
}
-
- public override Task Reset()
+ catch (IOException)
{
- var zeeDllPath = Path.Combine(ZuneInstallDir, "ZuneEncEng.dll");
- try
- {
- // Copy backup to application folder
- File.Copy(Path.Combine(StorageDirectory, "ZuneEncEng.original.dll"), zeeDllPath, true);
-
- // Delete WMVCore files
- File.Delete(Path.Combine(ZuneInstallDir, "wmvcora.dll"));
- File.Delete(Path.Combine(ZuneInstallDir, "wmvcore.dll"));
-
- return Task.FromResult(null);
- }
- catch (Exception ex)
- {
- return Task.FromResult(ex.Message)!;
- }
+ return $"Unable to replace '{zeeDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
+ }
+ catch (Exception ex)
+ {
+ return ex.Message;
}
-
- public override IReadOnlyList? DependentMods => null;
}
+
+ public override Task Reset()
+ {
+ var zeeDllPath = Path.Combine(ZuneInstallDir, "ZuneEncEng.dll");
+ try
+ {
+ // Copy backup to application folder
+ File.Copy(Path.Combine(StorageDirectory, "ZuneEncEng.original.dll"), zeeDllPath, true);
+
+ // Delete WMVCore files
+ File.Delete(Path.Combine(ZuneInstallDir, "wmvcora.dll"));
+ File.Delete(Path.Combine(ZuneInstallDir, "wmvcore.dll"));
+
+ return Task.FromResult(null);
+ }
+ catch (Exception ex)
+ {
+ return Task.FromResult(ex.Message)!;
+ }
+ }
+
+ public override IReadOnlyList? DependentMods => null;
}
diff --git a/ZuneModCore/Mods/WebservicesMod.cs b/ZuneModCore/Mods/WebservicesMod.cs
index a9ef11c..5a3c9fe 100644
--- a/ZuneModCore/Mods/WebservicesMod.cs
+++ b/ZuneModCore/Mods/WebservicesMod.cs
@@ -7,288 +7,266 @@ using System.Threading;
using System.Threading.Tasks;
using static ZuneModCore.Mods.FeaturesOverrideMod;
-namespace ZuneModCore.Mods
+namespace ZuneModCore.Mods;
+
+public class WebservicesMod : Mod
{
- public class WebservicesMod : Mod
+ private const int ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET = 0x14D60;
+ private const int ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH = 0x884;
+ private const string WEBSERVICE_ICON_TESTING = "\uE72C";
+ private const string WEBSERVICE_ICON_SUCCESS = "\uE73E";
+ private const string WEBSERVICE_ICON_UNREACHABLE = "\uF384";
+ private const string WEBSERVICE_ICON_UNAVAILABLE = "\uE894";
+ private const string WEBSERVICE_SUBTITLE_TESTING = "Testing...";
+ private const string WEBSERVICE_SUBTITLE_SUCCESS = "OK";
+ private const string WEBSERVICE_SUBTITLE_UNREACHABLE = "Unreachable";
+
+ private static readonly string[] _affectedFeatures =
+ [
+ "Apps", "Channels", "Games", "Marketplace",
+ "MBRPreview", "MBRPurchase", "MBRRental",
+ "Music", "MusicVideos", "Picks", "Podcasts",
+ "Sign In Available", "Social", "Videos",
+ "SocialMarketplace", "SubscriptionFreeTracks",
+ ];
+
+ private HttpClient _client;
+ private CancellationTokenSource _cts = new();
+
+ public override string Id => nameof(WebservicesMod);
+
+ public override string Title => "Community Webservices";
+
+ public override string Description => "Partially restores online features such as the Marketplace by patching the Zune desktop software " +
+ "to use the community's recreation of Microsoft's Zune servers at zunes.me (instead of zune.net).";
+
+ public override string Author => "Joshua \"Yoshi\" Askharoun";
+
+ public override AbstractUICollection? GetDefaultOptionsUI()
{
- private const int ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET = 0x14D60;
- private const int ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH = 0x884;
- private const string WEBSERVICE_ICON_TESTING = "\uE72C";
- private const string WEBSERVICE_ICON_SUCCESS = "\uE73E";
- private const string WEBSERVICE_ICON_UNREACHABLE = "\uF384";
- private const string WEBSERVICE_ICON_UNAVAILABLE = "\uE894";
- private const string WEBSERVICE_SUBTITLE_TESTING = "Testing...";
- private const string WEBSERVICE_SUBTITLE_SUCCESS = "OK";
- private const string WEBSERVICE_SUBTITLE_UNREACHABLE = "Unreachable";
-
- private HttpClient _client;
- private CancellationTokenSource _cts = new();
-
- public override string Id => nameof(WebservicesMod);
-
- public override string Title => "Community Webservices";
-
- public override string Description => "Partially restores online features such as the Marketplace by patching the Zune desktop software " +
- "to use the community's recreation of Microsoft's Zune servers at zunes.me (instead of zune.net).";
-
- public override string Author => "Joshua \"Yoshi\" Askharoun";
-
- public override AbstractUICollection? GetDefaultOptionsUI()
+ AbstractUICollection optionsUi = new(nameof(FeaturesOverrideMod))
{
- AbstractUICollection optionsUi = new(nameof(FeaturesOverrideMod))
+ new AbstractTextBox("hostBox", string.Empty, "zune.net")
{
- new AbstractTextBox("hostBox", string.Empty, "zune.net")
+ Title = "host",
+ TooltipText = "The host where the replacement servers are located. Must be the same length as \"zune.net\"."
+ },
+ new AbstractDataList("hostsTest", new List()
{
- Title = "host",
- TooltipText = "The host where the replacement servers are located. Must be the same length as \"zune.net\"."
- },
- new AbstractDataList("hostsTest", new List()
- {
- GetWebserviceAvailabilityUI("Main website", "www"),
- GetWebserviceAvailabilityUI("Social website", "social"),
- GetWebserviceAvailabilityUI("Catalog", "catalog"),
- GetWebserviceAvailabilityUI("Image catalog", "image.catalog"),
- GetWebserviceAvailabilityUI("Social", "socialapi"),
- GetWebserviceAvailabilityUI("Social [Comments]", "comments"),
- GetWebserviceAvailabilityUI("Social [Inbox]", "inbox"),
- GetWebserviceAvailabilityUI("Commerce [Sign in]", "commerce"),
- GetWebserviceAvailabilityUI("Mix", "mix"),
- GetWebserviceAvailabilityUI("Resources [Firmware]", "resources"),
- GetWebserviceAvailabilityUI("Statistics", "stats"),
- }
- )
- {
- Subtitle = "TEST AVAILABILITY OF EACH KNOWN WEB SERVICE ON THE NEW HOST.".ToUpper(),
- IsUserEditingEnabled = false,
- PreferredDisplayMode = AbstractDataListPreferredDisplayMode.Grid,
+ GetWebserviceAvailabilityUI("Main website", "www"),
+ GetWebserviceAvailabilityUI("Social website", "social"),
+ GetWebserviceAvailabilityUI("Catalog", "catalog"),
+ GetWebserviceAvailabilityUI("Image catalog", "image.catalog"),
+ GetWebserviceAvailabilityUI("Social", "socialapi"),
+ GetWebserviceAvailabilityUI("Social [Comments]", "comments"),
+ GetWebserviceAvailabilityUI("Social [Inbox]", "inbox"),
+ GetWebserviceAvailabilityUI("Commerce [Sign in]", "commerce"),
+ GetWebserviceAvailabilityUI("Mix", "mix"),
+ GetWebserviceAvailabilityUI("Resources [Firmware]", "resources"),
+ GetWebserviceAvailabilityUI("Statistics", "stats"),
}
- };
- return optionsUi;
+ )
+ {
+ Subtitle = "TEST AVAILABILITY OF EACH KNOWN WEB SERVICE ON THE NEW HOST.".ToUpper(),
+ IsUserEditingEnabled = false,
+ PreferredDisplayMode = AbstractDataListPreferredDisplayMode.Grid,
+ }
+ };
+ return optionsUi;
+ }
+
+ private static AbstractUIMetadata GetWebserviceAvailabilityUI(string name, string subDomain)
+ {
+ return new("serviceTestUI_" + subDomain)
+ {
+ Title = name,
+ IconCode = WEBSERVICE_ICON_TESTING
+ };
+ }
+
+ public override IReadOnlyList? DependentMods => null;
+
+ public override Task Init()
+ {
+ _client = new()
+ {
+ Timeout = TimeSpan.FromSeconds(3)
+ };
+
+ AbstractTextBox newHostBox = (AbstractTextBox)OptionsUI![0];
+ newHostBox.ValueChanged += OnHostChanged;
+ newHostBox.Value = "zunes.me";
+
+ return Task.CompletedTask;
+ }
+
+ public override async Task Apply()
+ {
+ // Verify that ZuneServices.dll exists
+ FileInfo zsDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneService.dll"));
+ if (!zsDllInfo.Exists)
+ {
+ return $"The file '{zsDllInfo.FullName}' does not exist.";
}
- private static AbstractUIMetadata GetWebserviceAvailabilityUI(string name, string subDomain)
+ // Make a backup if it doesn't already exist
+ FileInfo zsDllBackupInfo = new(Path.Combine(StorageDirectory, "ZuneService.original.dll"));
+ if (!zsDllBackupInfo.Exists)
{
- return new("serviceTestUI_" + subDomain)
- {
- Title = name,
- IconCode = WEBSERVICE_ICON_TESTING
- };
+ File.Copy(zsDllInfo.FullName, zsDllBackupInfo.FullName, true);
}
- public override IReadOnlyList? DependentMods => null;
-
- public override Task Init()
+ try
{
- _client = new()
+ // Open the file
+ using FileStream zsDll = zsDllInfo.Open(FileMode.Open);
+ using BinaryWriter zsDllWriter = new(zsDll);
+ using BinaryReader zsDllReader = new(zsDll);
+
+ // Verify that the DLL is from v4.8 (other versions not tested)
+ zsDllReader.BaseStream.Position = 0x12C824;
+ var versionBytes = zsDllReader.ReadBytes(6);
+ if (versionBytes[0] != '4' || versionBytes[2] != '.' || versionBytes[4] != '8')
{
- Timeout = TimeSpan.FromSeconds(3)
- };
+ return "This mod has not been tested on versions earlier than 4.8.";
+ }
- AbstractTextBox newHostBox = (AbstractTextBox)OptionsUI![0];
- newHostBox.ValueChanged += OnHostChanged;
- newHostBox.Value = "zunes.me";
+ // Get and validate replacement host
+ string oldHost = "zune.net";
+ string newHost = ((AbstractTextBox)OptionsUI![0]).Value;
+ if (newHost.Length != oldHost.Length)
+ {
+ return $"The new host (\"{newHost}\") must have the same length as \"{oldHost}\".";
+ }
+ var ping = await new System.Net.NetworkInformation.Ping().SendPingAsync(newHost);
+ if (ping.Status != System.Net.NetworkInformation.IPStatus.Success)
+ {
+ return $"Failed to reach \"{newHost}\". Ping status: {ping.Status}";
+ }
- return Task.CompletedTask;
+ // Patch ZuneServices.dll to use the new host instead of zune.net
+ zsDllReader.BaseStream.Position = ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET;
+ string endpointBlock = System.Text.Encoding.Unicode.GetString(zsDllReader.ReadBytes(ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH));
+ endpointBlock = endpointBlock.Replace("resources." + oldHost, "www.zuneupdate.com"); // Use zuneupdate.com until resources.zunes.me is online
+ endpointBlock = endpointBlock.Replace(oldHost, newHost);
+ byte[] endpointBytes = System.Text.Encoding.Unicode.GetBytes(endpointBlock);
+ if (endpointBytes.Length != ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH)
+ {
+ return "Failed to safely overwrite strings in DLL.";
+ }
+ zsDllWriter.Seek(ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET, SeekOrigin.Begin);
+ zsDllWriter.Write(endpointBytes);
+
+
+ // Enable all feature overrides affected by new servers
+ bool setOverrideSuccess = true;
+ foreach (var feature in _affectedFeatures)
+ setOverrideSuccess &= SetFeatureOverride(feature, true);
+
+ if (setOverrideSuccess != true)
+ return "Unable to set feature overrides. The mod was successful, but you may not be able to see it in the Zune software.";
+
+ return null;
+ }
+ catch (IOException)
+ {
+ return $"Unable to replace '{zsDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
+ }
+ catch (Exception ex)
+ {
+ return ex.Message;
+ }
+ }
+
+ public override async Task Reset()
+ {
+ string zsDllPath = Path.Combine(ZuneInstallDir, "ZuneService.dll");
+ try
+ {
+ // Copy backup to application folder
+ File.Copy(Path.Combine(StorageDirectory, "ZuneService.original.dll"), zsDllPath, true);
+
+ // Disable all feature overrides affected by new servers
+ bool setOverrideSuccess = true;
+ foreach (var feature in _affectedFeatures)
+ setOverrideSuccess &= SetFeatureOverride(feature, false);
+
+ if (setOverrideSuccess != true)
+ return "Unable to reset feature overrides. The mod was successfully removed, but you may still be able to see it in the Zune software.";
+
+ return null;
+ }
+ catch (IOException)
+ {
+ return $"Unable to replace '{zsDllPath}'. Verify that the Zune software is not running and try again.";
+ }
+ catch (Exception ex)
+ {
+ return ex.Message;
+ }
+ }
+
+ async void OnHostChanged(object? sender, string newHost)
+ {
+ await _cts.CancelAsync();
+ _client.CancelPendingRequests();
+
+ _cts = new();
+
+ AbstractDataList list = (AbstractDataList)OptionsUI![1];
+
+ // Reset all statuses
+ foreach (AbstractUIMetadata metadata in list.Items)
+ {
+ metadata.IconCode = WEBSERVICE_ICON_TESTING;
+ metadata.Subtitle = WEBSERVICE_SUBTITLE_TESTING;
}
- public override async Task Apply()
+ // We want to update all the statuses, but we also need to be able
+ // to cancel it when the user enters a new host.
+ foreach (AbstractUIMetadata metadata in list.Items)
+ UpdateStatus(metadata, newHost, _cts.Token);
+ }
+
+ private async Task Ping(string url, CancellationToken token = default)
+ {
+ try
{
- // Verify that ZuneServices.dll exists
- FileInfo zsDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneService.dll"));
- if (!zsDllInfo.Exists)
- {
- return $"The file '{zsDllInfo.FullName}' does not exist.";
- }
-
- // Make a backup if it doesn't already exist
- FileInfo zsDllBackupInfo = new(Path.Combine(StorageDirectory, "ZuneService.original.dll"));
- if (!zsDllBackupInfo.Exists)
- {
- File.Copy(zsDllInfo.FullName, zsDllBackupInfo.FullName, true);
- }
-
- try
- {
- // Open the file
- using FileStream zsDll = zsDllInfo.Open(FileMode.Open);
- using BinaryWriter zsDllWriter = new(zsDll);
- using BinaryReader zsDllReader = new(zsDll);
-
- // Verify that the DLL is from v4.8 (other versions not tested)
- zsDllReader.BaseStream.Position = 0x12C824;
- var versionBytes = zsDllReader.ReadBytes(6);
- if (versionBytes[0] != '4' || versionBytes[2] != '.' || versionBytes[4] != '8')
- {
- return "This mod has not been tested on versions earlier than 4.8.";
- }
-
- // Get and validate replacement host
- string oldHost = "zune.net";
- string newHost = ((AbstractTextBox)OptionsUI![0]).Value;
- if (newHost.Length != oldHost.Length)
- {
- return $"The new host (\"{newHost}\") must have the same length as \"{oldHost}\".";
- }
- var ping = await new System.Net.NetworkInformation.Ping().SendPingAsync(newHost);
- if (ping.Status != System.Net.NetworkInformation.IPStatus.Success)
- {
- return $"Failed to reach \"{newHost}\". Ping status: {ping.Status}";
- }
-
- // Patch ZuneServices.dll to use the new host instead of zune.net
- zsDllReader.BaseStream.Position = ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET;
- string endpointBlock = System.Text.Encoding.Unicode.GetString(zsDllReader.ReadBytes(ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH));
- endpointBlock = endpointBlock.Replace("resources." + oldHost, "www.zuneupdate.com"); // Use zuneupdate.com until resources.zunes.me is online
- endpointBlock = endpointBlock.Replace(oldHost, newHost);
- byte[] endpointBytes = System.Text.Encoding.Unicode.GetBytes(endpointBlock);
- if (endpointBytes.Length != ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH)
- {
- return "Failed to safely overwrite strings in DLL.";
- }
- zsDllWriter.Seek(ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET, SeekOrigin.Begin);
- zsDllWriter.Write(endpointBytes);
-
-
- // Enable all feature overrides affected by new servers
- bool setOverrideSuccess = true;
- setOverrideSuccess &= SetFeatureOverride("Apps", true);
- setOverrideSuccess &= SetFeatureOverride("Channels", true);
- setOverrideSuccess &= SetFeatureOverride("Games", true);
- setOverrideSuccess &= SetFeatureOverride("Marketplace", true);
- setOverrideSuccess &= SetFeatureOverride("MBRPreview", true);
- setOverrideSuccess &= SetFeatureOverride("MBRPurchase", true);
- setOverrideSuccess &= SetFeatureOverride("MBRRental", true);
- setOverrideSuccess &= SetFeatureOverride("Music", true);
- setOverrideSuccess &= SetFeatureOverride("MusicVideos", true);
- setOverrideSuccess &= SetFeatureOverride("Picks", true);
- setOverrideSuccess &= SetFeatureOverride("Podcasts", true);
- setOverrideSuccess &= SetFeatureOverride("Sign In Available", true);
- setOverrideSuccess &= SetFeatureOverride("Social", true);
- setOverrideSuccess &= SetFeatureOverride("SocialMarketplace", true);
- setOverrideSuccess &= SetFeatureOverride("SubscriptionFreeTracks", true);
- setOverrideSuccess &= SetFeatureOverride("Videos", true);
- if (setOverrideSuccess != true)
- {
- return "Unable to set feature overrides. The mod was successful, but you may not be able to see it in the Zune software.";
- }
-
- return null;
- }
- catch (IOException)
- {
- return $"Unable to replace '{zsDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
- }
- catch (Exception ex)
- {
- return ex.Message;
- }
+ var response = await _client.GetAsync(url, token);
+ response.EnsureSuccessStatusCode();
+ return null;
}
-
- public override async Task Reset()
+ catch (HttpRequestException webEx)
{
- string zsDllPath = Path.Combine(ZuneInstallDir, "ZuneService.dll");
- try
- {
- // Copy backup to application folder
- File.Copy(Path.Combine(StorageDirectory, "ZuneService.original.dll"), zsDllPath, true);
-
- // Disable all feature overrides affected by new servers
- bool setOverrideSuccess = true;
- setOverrideSuccess &= SetFeatureOverride("Apps", false);
- setOverrideSuccess &= SetFeatureOverride("Channels", false);
- setOverrideSuccess &= SetFeatureOverride("Games", false);
- setOverrideSuccess &= SetFeatureOverride("Marketplace", false);
- setOverrideSuccess &= SetFeatureOverride("MBRPreview", false);
- setOverrideSuccess &= SetFeatureOverride("MBRPurchase", false);
- setOverrideSuccess &= SetFeatureOverride("MBRRental", false);
- setOverrideSuccess &= SetFeatureOverride("Music", false);
- setOverrideSuccess &= SetFeatureOverride("MusicVideos", false);
- setOverrideSuccess &= SetFeatureOverride("Picks", false);
- setOverrideSuccess &= SetFeatureOverride("Podcasts", false);
- setOverrideSuccess &= SetFeatureOverride("Sign In Available", false);
- setOverrideSuccess &= SetFeatureOverride("Social", false);
- setOverrideSuccess &= SetFeatureOverride("SocialMarketplace", false);
- setOverrideSuccess &= SetFeatureOverride("SubscriptionFreeTracks", false);
- setOverrideSuccess &= SetFeatureOverride("Videos", false);
- if (setOverrideSuccess != true)
- {
- return "Unable to reset feature overrides. The mod was successfully removed, but you may still be able to see it in the Zune software.";
- }
-
- return null;
- }
- catch (IOException)
- {
- return $"Unable to replace '{zsDllPath}'. Verify that the Zune software is not running and try again.";
- }
- catch (Exception ex)
- {
- return ex.Message;
- }
+ if (webEx.InnerException?.InnerException != null)
+ return webEx.InnerException.InnerException.Message;
+ return webEx?.Message ?? string.Empty;
}
-
- async void OnHostChanged(object? sender, string newHost)
+ catch (Exception ex)
{
- await _cts.CancelAsync();
- _client.CancelPendingRequests();
-
- _cts = new();
-
- AbstractDataList list = (AbstractDataList)OptionsUI![1];
-
- // Reset all statuses
- foreach (AbstractUIMetadata metadata in list.Items)
- {
- metadata.IconCode = WEBSERVICE_ICON_TESTING;
- metadata.Subtitle = WEBSERVICE_SUBTITLE_TESTING;
- }
-
- // We want to update all the statuses, but we also need to be able
- // to cancel it when the user enters a new host.
- foreach (AbstractUIMetadata metadata in list.Items)
- UpdateStatus(metadata, newHost, _cts.Token);
+ return ex?.Message ?? string.Empty;
}
+ }
- private async Task Ping(string url, CancellationToken token = default)
+ private async Task UpdateStatus(AbstractUIMetadata metadata, string newHost, CancellationToken token = default)
+ {
+ string url = "http://" + (metadata.Id.Split('_')[1] + '.' + newHost).Replace("www.", string.Empty);
+ string? pingResult = await Ping(url, token);
+
+ if (pingResult == null)
{
- try
- {
- var response = await _client.GetAsync(url, token);
- response.EnsureSuccessStatusCode();
- return null;
- }
- catch (HttpRequestException webEx)
- {
- if (webEx.InnerException?.InnerException != null)
- return webEx.InnerException.InnerException.Message;
- return webEx?.Message ?? string.Empty;
- }
- catch (Exception ex)
- {
- return ex?.Message ?? string.Empty;
- }
+ metadata.IconCode = WEBSERVICE_ICON_SUCCESS;
+ metadata.Subtitle = WEBSERVICE_SUBTITLE_SUCCESS;
}
-
- private async Task UpdateStatus(AbstractUIMetadata metadata, string newHost, CancellationToken token = default)
+ else if (pingResult != string.Empty)
{
- string url = "http://" + (metadata.Id.Split('_')[1] + '.' + newHost).Replace("www.", string.Empty);
- string? pingResult = await Ping(url, token);
-
- if (pingResult == null)
- {
- metadata.IconCode = WEBSERVICE_ICON_SUCCESS;
- metadata.Subtitle = WEBSERVICE_SUBTITLE_SUCCESS;
- }
- else if (pingResult != string.Empty)
- {
- metadata.IconCode = WEBSERVICE_ICON_UNAVAILABLE;
- metadata.Subtitle = pingResult;
- }
- else
- {
- metadata.IconCode = WEBSERVICE_ICON_UNREACHABLE;
- metadata.Subtitle = WEBSERVICE_SUBTITLE_UNREACHABLE;
- }
+ metadata.IconCode = WEBSERVICE_ICON_UNAVAILABLE;
+ metadata.Subtitle = pingResult;
+ }
+ else
+ {
+ metadata.IconCode = WEBSERVICE_ICON_UNREACHABLE;
+ metadata.Subtitle = WEBSERVICE_SUBTITLE_UNREACHABLE;
}
}
}
diff --git a/ZuneModCore/Services/IModCoreConfig.cs b/ZuneModCore/Services/IModCoreConfig.cs
index e402270..028b11e 100644
--- a/ZuneModCore/Services/IModCoreConfig.cs
+++ b/ZuneModCore/Services/IModCoreConfig.cs
@@ -1,7 +1,6 @@
-namespace ZuneModCore.Services
+namespace ZuneModCore.Services;
+
+public interface IModCoreConfig
{
- public interface IModCoreConfig
- {
- string ZuneInstallDir { get; }
- }
+ string ZuneInstallDir { get; }
}
diff --git a/ZuneModCore/Win32/FileUtil.cs b/ZuneModCore/Win32/FileUtil.cs
index b224c4e..5b9a476 100644
--- a/ZuneModCore/Win32/FileUtil.cs
+++ b/ZuneModCore/Win32/FileUtil.cs
@@ -1,151 +1,143 @@
-using System;
+namespace ZuneModCore.Win32;
+
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-namespace ZuneModCore.Win32
+public static partial class FileUtil
{
- using System.Runtime.InteropServices;
- using System.Diagnostics;
- using System;
- using System.Collections.Generic;
-
- static public class FileUtil
+ [StructLayout(LayoutKind.Sequential)]
+ struct RM_UNIQUE_PROCESS
{
- [StructLayout(LayoutKind.Sequential)]
- struct RM_UNIQUE_PROCESS
+ public int dwProcessId;
+ public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
+ }
+
+ const int RmRebootReasonNone = 0;
+ const int CCH_RM_MAX_APP_NAME = 255;
+ const int CCH_RM_MAX_SVC_NAME = 63;
+
+ enum RM_APP_TYPE
+ {
+ RmUnknownApp = 0,
+ RmMainWindow = 1,
+ RmOtherWindow = 2,
+ RmService = 3,
+ RmExplorer = 4,
+ RmConsole = 5,
+ RmCritical = 1000
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ struct RM_PROCESS_INFO
+ {
+ public RM_UNIQUE_PROCESS Process;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
+ public string strAppName;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
+ public string strServiceShortName;
+
+ public RM_APP_TYPE ApplicationType;
+ public uint AppStatus;
+ public uint TSSessionId;
+ [MarshalAs(UnmanagedType.Bool)]
+ public bool bRestartable;
+ }
+
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
+ static extern int RmRegisterResources(uint pSessionHandle,
+ uint nFiles,
+ string[] rgsFilenames,
+ uint nApplications,
+ [In] RM_UNIQUE_PROCESS[] rgApplications,
+ uint nServices,
+ string[] rgsServiceNames);
+
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
+ static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
+
+ [LibraryImport("rstrtmgr.dll")]
+ private static partial int RmEndSession(uint pSessionHandle);
+
+ [DllImport("rstrtmgr.dll")]
+ static extern int RmGetList(uint dwSessionHandle,
+ out uint pnProcInfoNeeded,
+ ref uint pnProcInfo,
+ [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
+ ref uint lpdwRebootReasons);
+
+ ///
+ /// Find out what process(es) have a lock on the specified file.
+ ///
+ /// Path of the file.
+ /// Processes locking the file
+ /// See also:
+ /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
+ /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
+ ///
+ ///
+ static public List WhoIsLocking(string path)
+ {
+ string key = Guid.NewGuid().ToString();
+ List processes = [];
+
+ int res = RmStartSession(out uint handle, 0, key);
+ if (res != 0)
+ throw new Exception("Could not begin restart session. Unable to determine file locker.");
+
+ try
{
- public int dwProcessId;
- public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
- }
+ const int ERROR_MORE_DATA = 234;
+ uint pnProcInfo = 0,
+ lpdwRebootReasons = RmRebootReasonNone;
- const int RmRebootReasonNone = 0;
- const int CCH_RM_MAX_APP_NAME = 255;
- const int CCH_RM_MAX_SVC_NAME = 63;
+ string[] resources = [path]; // Just checking on one resource.
- enum RM_APP_TYPE
- {
- RmUnknownApp = 0,
- RmMainWindow = 1,
- RmOtherWindow = 2,
- RmService = 3,
- RmExplorer = 4,
- RmConsole = 5,
- RmCritical = 1000
- }
+ res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- struct RM_PROCESS_INFO
- {
- public RM_UNIQUE_PROCESS Process;
+ if (res != 0) throw new Exception("Could not register resource.");
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
- public string strAppName;
+ //Note: there's a race condition here -- the first call to RmGetList() returns
+ // the total number of process. However, when we call RmGetList() again to get
+ // the actual processes this number may have increased.
+ res = RmGetList(handle, out uint pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
- public string strServiceShortName;
-
- public RM_APP_TYPE ApplicationType;
- public uint AppStatus;
- public uint TSSessionId;
- [MarshalAs(UnmanagedType.Bool)]
- public bool bRestartable;
- }
-
- [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
- static extern int RmRegisterResources(uint pSessionHandle,
- UInt32 nFiles,
- string[] rgsFilenames,
- UInt32 nApplications,
- [In] RM_UNIQUE_PROCESS[] rgApplications,
- UInt32 nServices,
- string[] rgsServiceNames);
-
- [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
- static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
-
- [DllImport("rstrtmgr.dll")]
- static extern int RmEndSession(uint pSessionHandle);
-
- [DllImport("rstrtmgr.dll")]
- static extern int RmGetList(uint dwSessionHandle,
- out uint pnProcInfoNeeded,
- ref uint pnProcInfo,
- [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
- ref uint lpdwRebootReasons);
-
- ///
- /// Find out what process(es) have a lock on the specified file.
- ///
- /// Path of the file.
- /// Processes locking the file
- /// See also:
- /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
- /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
- ///
- ///
- static public List WhoIsLocking(string path)
- {
- uint handle;
- string key = Guid.NewGuid().ToString();
- List processes = new List();
-
- int res = RmStartSession(out handle, 0, key);
- if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker.");
-
- try
+ if (res == ERROR_MORE_DATA)
{
- const int ERROR_MORE_DATA = 234;
- uint pnProcInfoNeeded = 0,
- pnProcInfo = 0,
- lpdwRebootReasons = RmRebootReasonNone;
+ // Create an array to store the process results
+ RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
+ pnProcInfo = pnProcInfoNeeded;
- string[] resources = new string[] { path }; // Just checking on one resource.
-
- res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
-
- if (res != 0) throw new Exception("Could not register resource.");
-
- //Note: there's a race condition here -- the first call to RmGetList() returns
- // the total number of process. However, when we call RmGetList() again to get
- // the actual processes this number may have increased.
- res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);
-
- if (res == ERROR_MORE_DATA)
+ // Get the list
+ res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
+ if (res == 0)
{
- // Create an array to store the process results
- RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
- pnProcInfo = pnProcInfoNeeded;
+ processes = new List((int)pnProcInfo);
- // Get the list
- res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
- if (res == 0)
+ // Enumerate all of the results and add them to the
+ // list to be returned
+ for (int i = 0; i < pnProcInfo; i++)
{
- processes = new List((int)pnProcInfo);
-
- // Enumerate all of the results and add them to the
- // list to be returned
- for (int i = 0; i < pnProcInfo; i++)
+ try
{
- try
- {
- processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
- }
- // catch the error -- in case the process is no longer running
- catch (ArgumentException) { }
+ processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
}
+ // catch the error -- in case the process is no longer running
+ catch (ArgumentException) { }
}
- else throw new Exception("Could not list processes locking resource.");
}
- else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
+ else throw new Exception("Could not list processes locking resource.");
}
- finally
- {
- RmEndSession(handle);
- }
-
- return processes;
+ else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
}
+ finally
+ {
+ RmEndSession(handle);
+ }
+
+ return processes;
}
}
diff --git a/ZuneModCore/Win32/RegEdit.cs b/ZuneModCore/Win32/RegEdit.cs
index 6f75735..4ae1c2a 100644
--- a/ZuneModCore/Win32/RegEdit.cs
+++ b/ZuneModCore/Win32/RegEdit.cs
@@ -1,73 +1,65 @@
using Microsoft.Win32;
-namespace ZuneModCore.Win32
+namespace ZuneModCore.Win32;
+
+public class RegEdit
{
+ public const string ZUNE_REG_PATH = @"SOFTWARE\Microsoft\Zune\";
-#pragma warning disable CA1416 // Validate platform compatibility
-
- public class RegEdit
+ public static bool CurrentUserSetBoolValue(string key, string name, bool value)
{
- public const string ZUNE_REG_PATH = @"SOFTWARE\Microsoft\Zune\";
+ RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
+ regKey ??= Registry.CurrentUser.CreateSubKey(key, true);
- public static bool CurrentUserSetBoolValue(string key, string name, bool value)
- {
- RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
- if (regKey == null)
- regKey = Registry.CurrentUser.CreateSubKey(key, true);
+ regKey.SetValue(name, value, RegistryValueKind.DWord);
+ regKey.Close();
+ regKey.Dispose();
- regKey.SetValue(name, value, RegistryValueKind.DWord);
- regKey.Close();
- regKey.Dispose();
-
- // Read the key to make sure it was set properly
- if (CurrentUserGetBoolValue(key, name) == null)
- return false;
- return true;
- }
-
- public static bool? CurrentUserGetBoolValue(string key, string name)
- {
- using RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
- if (regKey == null)
- return false;
-
- // Return null if a boolean value couldn't be read from the key
- int? value = regKey.GetValue(name, false) as int?;
- if (!value.HasValue)
- return null;
- return value != 0;
- }
-
- public static void CurrentUserDeleteKey(string key)
- {
- using RegistryKey? targetKey = Registry.CurrentUser.OpenSubKey(key, true);
- if (targetKey == null)
- // Key is already deleted
- return;
-
- // Delete target subkeys
- if (targetKey.SubKeyCount > 0)
- targetKey.DeleteSubKeyTree(key, false);
-
- // Delete target values
- string[] values = targetKey.GetValueNames();
- foreach (string value in values)
- targetKey.DeleteValue(value, false);
-
- // Delete target key
- Registry.CurrentUser.DeleteSubKey(key);
- }
-
- public static void CurrentUserDeleteValue(string key, string name)
- {
- using RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
- if (regKey == null)
- return;
-
- regKey.DeleteValue(name, false);
- }
+ // Read the key to make sure it was set properly
+ if (CurrentUserGetBoolValue(key, name) == null)
+ return false;
+ return true;
}
-#pragma warning restore CA1416 // Validate platform compatibility
+ public static bool? CurrentUserGetBoolValue(string key, string name)
+ {
+ using RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
+ if (regKey == null)
+ return false;
+ // Return null if a boolean value couldn't be read from the key
+ int? value = regKey.GetValue(name, false) as int?;
+ if (!value.HasValue)
+ return null;
+ return value != 0;
+ }
+
+ public static void CurrentUserDeleteKey(string key)
+ {
+ using RegistryKey? targetKey = Registry.CurrentUser.OpenSubKey(key, true);
+ if (targetKey == null)
+ // Key is already deleted
+ return;
+
+ // Delete target subkeys
+ if (targetKey.SubKeyCount > 0)
+ targetKey.DeleteSubKeyTree(key, false);
+
+ // Delete target values
+ string[] values = targetKey.GetValueNames();
+ foreach (string value in values)
+ targetKey.DeleteValue(value, false);
+
+ // Delete target key
+ Registry.CurrentUser.DeleteSubKey(key);
+ }
+
+ public static void CurrentUserDeleteValue(string key, string name)
+ {
+ using RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
+ if (regKey == null)
+ return;
+
+ regKey.DeleteValue(name, false);
+ }
}
diff --git a/ZuneModCore/Win32/TokenManipulator.cs b/ZuneModCore/Win32/TokenManipulator.cs
index a0146d5..f4e2194 100644
--- a/ZuneModCore/Win32/TokenManipulator.cs
+++ b/ZuneModCore/Win32/TokenManipulator.cs
@@ -1,123 +1,119 @@
using System;
using System.IO;
-using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using Vanara.PInvoke;
-namespace ZuneModCore.Win32
+namespace ZuneModCore.Win32;
+
+public class TokenManipulator
{
- public class TokenManipulator
+ public static bool AddPrivilege(string privilege)
{
- public static bool AddPrivilege(string privilege)
+ try
{
- try
- {
- bool retVal;
- var hproc = Kernel32.GetCurrentProcess();
+ bool retVal;
+ var hproc = Kernel32.GetCurrentProcess();
- retVal = AdvApi32.OpenProcessToken(hproc,
- AdvApi32.TokenAccess.TOKEN_ADJUST_PRIVILEGES | AdvApi32.TokenAccess.TOKEN_QUERY, out var htok);
+ retVal = AdvApi32.OpenProcessToken(hproc,
+ AdvApi32.TokenAccess.TOKEN_ADJUST_PRIVILEGES | AdvApi32.TokenAccess.TOKEN_QUERY, out var htok);
- retVal = AdvApi32.LookupPrivilegeValue(null, privilege, out var tpLuid);
- AdvApi32.TOKEN_PRIVILEGES tp = new(tpLuid, AdvApi32.PrivilegeAttributes.SE_PRIVILEGE_ENABLED);
+ retVal = AdvApi32.LookupPrivilegeValue(null, privilege, out var tpLuid);
+ AdvApi32.TOKEN_PRIVILEGES tp = new(tpLuid, AdvApi32.PrivilegeAttributes.SE_PRIVILEGE_ENABLED);
- AdvApi32.AdjustTokenPrivileges(htok, false, in tp, out _).ThrowIfFailed();
+ AdvApi32.AdjustTokenPrivileges(htok, false, in tp, out _).ThrowIfFailed();
- return retVal;
- }
- catch
- {
- throw;
- }
+ return retVal;
}
- public static bool RemovePrivilege(string privilege)
+ catch
{
- try
- {
- bool retVal;
- var hproc = Kernel32.GetCurrentProcess();
-
- retVal = AdvApi32.OpenProcessToken(hproc,
- AdvApi32.TokenAccess.TOKEN_ADJUST_PRIVILEGES | AdvApi32.TokenAccess.TOKEN_QUERY, out var htok);
-
- retVal = AdvApi32.LookupPrivilegeValue(null, privilege, out var tpLuid);
- AdvApi32.TOKEN_PRIVILEGES tp = new(tpLuid, AdvApi32.PrivilegeAttributes.SE_PRIVILEGE_DISABLED);
-
- AdvApi32.AdjustTokenPrivileges(htok, false, in tp, out _).ThrowIfFailed();
-
- return retVal;
- }
- catch
- {
- throw;
- }
- }
-
-#pragma warning disable CA1416 // Validate platform compatibility
- public static void TakeOwnership(FileInfo file)
- {
- EscalateToAdmin();
-
- // Get access control
- FileSecurity security = file.GetAccessControl();
- SecurityIdentifier? cu = WindowsIdentity.GetCurrent().User;
-
- // Set owner to current user
- security.SetOwner(cu);
- security.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.Modify, AccessControlType.Allow));
-
- // Update the Access Control on the original file
- file.SetAccessControl(security);
- }
-
- public static void TakeOwnership(DirectoryInfo dir)
- {
- EscalateToAdmin();
-
- // Get access control
- DirectorySecurity security = dir.GetAccessControl();
- SecurityIdentifier? cu = WindowsIdentity.GetCurrent().User;
-
- // Set owner to current user
- security.SetOwner(cu);
- security.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.Modify, AccessControlType.Allow));
-
- // Update the Access Control on the original file
- dir.SetAccessControl(security);
- }
-
- public static void TakeOwnership(FileSystemInfo info)
- {
- if (info is FileInfo file)
- TakeOwnership(file);
- else if (info is DirectoryInfo dir)
- TakeOwnership(dir);
- }
-#pragma warning restore CA1416 // Validate platform compatibility
-
- public static bool TryTakeOwnership(FileInfo file, out Exception? exception)
- {
- try
- {
- TakeOwnership(file);
-
- exception = null;
- return true;
- }
- catch (Exception ex)
- {
- exception = ex;
- return false;
- }
- }
-
- public static void EscalateToAdmin()
- {
- // Activate necessary admin privileges to make changes without NTFS perms
- AddPrivilege("SeRestorePrivilege"); // Necessary to set Owner Permissions
- AddPrivilege("SeBackupPrivilege"); // Necessary to bypass Traverse Checking
- AddPrivilege("SeTakeOwnershipPrivilege"); // Necessary to override FilePermissions
+ throw;
}
}
+ public static bool RemovePrivilege(string privilege)
+ {
+ try
+ {
+ bool retVal;
+ var hproc = Kernel32.GetCurrentProcess();
+
+ retVal = AdvApi32.OpenProcessToken(hproc,
+ AdvApi32.TokenAccess.TOKEN_ADJUST_PRIVILEGES | AdvApi32.TokenAccess.TOKEN_QUERY, out var htok);
+
+ retVal = AdvApi32.LookupPrivilegeValue(null, privilege, out var tpLuid);
+ AdvApi32.TOKEN_PRIVILEGES tp = new(tpLuid, AdvApi32.PrivilegeAttributes.SE_PRIVILEGE_DISABLED);
+
+ AdvApi32.AdjustTokenPrivileges(htok, false, in tp, out _).ThrowIfFailed();
+
+ return retVal;
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ public static void TakeOwnership(FileInfo file)
+ {
+ EscalateToAdmin();
+
+ // Get access control
+ FileSecurity security = file.GetAccessControl();
+ SecurityIdentifier? cu = WindowsIdentity.GetCurrent().User;
+
+ // Set owner to current user
+ security.SetOwner(cu);
+ security.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.Modify, AccessControlType.Allow));
+
+ // Update the Access Control on the original file
+ file.SetAccessControl(security);
+ }
+
+ public static void TakeOwnership(DirectoryInfo dir)
+ {
+ EscalateToAdmin();
+
+ // Get access control
+ DirectorySecurity security = dir.GetAccessControl();
+ SecurityIdentifier? cu = WindowsIdentity.GetCurrent().User;
+
+ // Set owner to current user
+ security.SetOwner(cu);
+ security.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.Modify, AccessControlType.Allow));
+
+ // Update the Access Control on the original file
+ dir.SetAccessControl(security);
+ }
+
+ public static void TakeOwnership(FileSystemInfo info)
+ {
+ if (info is FileInfo file)
+ TakeOwnership(file);
+ else if (info is DirectoryInfo dir)
+ TakeOwnership(dir);
+ }
+
+ public static bool TryTakeOwnership(FileInfo file, out Exception? exception)
+ {
+ try
+ {
+ TakeOwnership(file);
+
+ exception = null;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ return false;
+ }
+ }
+
+ public static void EscalateToAdmin()
+ {
+ // Activate necessary admin privileges to make changes without NTFS perms
+ AddPrivilege("SeRestorePrivilege"); // Necessary to set Owner Permissions
+ AddPrivilege("SeBackupPrivilege"); // Necessary to bypass Traverse Checking
+ AddPrivilege("SeTakeOwnershipPrivilege"); // Necessary to override FilePermissions
+ }
}
diff --git a/ZuneModCore/ZuneModCore.csproj b/ZuneModCore/ZuneModCore.csproj
index 42a0fe1..2de2ee6 100644
--- a/ZuneModCore/ZuneModCore.csproj
+++ b/ZuneModCore/ZuneModCore.csproj
@@ -1,8 +1,8 @@
- net8.0
- 9
+ net8.0-windows
+ 12
enable
AnyCPU;x64;x86
true