From 6172c4358fe60cb1272f37615cf6830253656a42 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:16:22 +0330 Subject: [PATCH 01/12] Build script now searches for all versions of VS2017's MSBuild15 --- SharpShell/build.ps1 | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/SharpShell/build.ps1 b/SharpShell/build.ps1 index 19f9384b..bda70770 100644 --- a/SharpShell/build.ps1 +++ b/SharpShell/build.ps1 @@ -1,7 +1,25 @@ +$agentPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\msbuild.exe" +$devPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe" +$proPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe" +$communityPath = "${env:ProgramFiles(x86)}Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe" + +$msbuild = "" + +If (Test-Path $agentPath) { + $msbuild = $agentPath +} ElseIf (Test-Path $devPath) { + $msbuild = $devPath +} ElseIf (Test-Path $proPath) { + $msbuild = $proPath +} ElseIf (Test-Path $communityPath) { + $msbuild = $communityPath +} Else { + throw "Unable to find msbuild" +} + # Run msbuild on the solution, in release mode. -$msbuild ="${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" -$args = "SharpShell.sln /t:Rebuild /p:Configuration=Release" +$args = "/p:Configuration=Release /t:Clean,Build SharpShell.sln" # Run the command. Write-Host "Running: ""$msbuild"" $args" -& "$msbuild" /p:Configuration=Release /t:Clean,Build SharpShell.sln \ No newline at end of file +& "$msbuild" /p:Configuration=Release /t:Clean,Build SharpShell.sln From 989258d0cc971cf590362bfd6d22b5b791625d20 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:19:51 +0330 Subject: [PATCH 02/12] All server registration methods moved to the ServerRegistrationManager --- .../ServerRegistrationManager.cs | 166 +++++++++++++++--- SharpShell/SharpShell/SharpShellServer.cs | 93 ++-------- 2 files changed, 153 insertions(+), 106 deletions(-) diff --git a/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs b/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs index 4a73b10b..96703663 100644 --- a/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs +++ b/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs @@ -1,10 +1,15 @@ using System; using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Security.AccessControl; using Microsoft.Win32; using SharpShell.Attributes; +using SharpShell.Diagnostics; using SharpShell.Extensions; +using SharpShell.Interop; using SharpShell.Registry; @@ -98,11 +103,35 @@ public static void InstallServer(ISharpShellServer server, RegistrationType regi /// Type of the registration. /// True if the server WAS installed and has been uninstalled, false if the server was not found. public static bool UninstallServer(ISharpShellServer server, RegistrationType registrationType) + { + return UninstallServer(server.ServerClsid, registrationType); + } + + /// + /// Uninstalls the server. + /// + /// The server's registration information. + /// Type of the registration. + /// True if the server WAS installed and has been uninstalled, false if the server was not found. + public static bool UninstallServer( + ShellExtensionRegistrationInfo registrationInfo, + RegistrationType registrationType) + { + return UninstallServer(registrationInfo.ServerCLSID, registrationType); + } + + /// + /// Uninstalls the server. + /// + /// The server's class id. + /// Type of the registration. + /// True if the server WAS installed and has been uninstalled, false if the server was not found. + private static bool UninstallServer(Guid classId, RegistrationType registrationType) { // Open classes. using (var classesKey = OpenClassesKey(registrationType, RegistryKeyPermissionCheck.ReadWriteSubTree)) { - var subKeyTreeName = server.ServerClsid.ToRegistryString(); + var subKeyTreeName = classId.ToRegistryString(); // If the subkey doesn't exist, we can return false - we're already uninstalled. if (classesKey.GetSubKeyNames().Any(skn => skn.Equals(subKeyTreeName, StringComparison.OrdinalIgnoreCase)) == false) @@ -124,12 +153,51 @@ public static void RegisterServer(ISharpShellServer server, RegistrationType reg { // Pass the server type to the SharpShellServer internal registration function and let it // take over from there. - SharpShellServer.DoRegister(server.GetType(), registrationType); + RegisterServerType(server.GetType(), registrationType); // Approve the extension. ApproveExtension(server, registrationType); } + /// + /// Actually performs registration. The ComRegisterFunction decorated method will call this function + /// internally with the flag appropriate for the operating system processor architecture. + /// However, this function can also be called manually if needed. + /// + /// The type of object to register, this must be a SharpShellServer derived class. + /// Type of the registration. + internal static void RegisterServerType(Type type, RegistrationType registrationType) + { + Logging.Log($"Preparing to register SharpShell Server {type.Name} as {registrationType}"); + + // Get the association data. + var associationAttributes = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) + .OfType().ToList(); + + // Get the server type and the registration name. + var serverType = ServerTypeAttribute.GetServerType(type); + var registrationName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(type); + + // Register the server associations, if there are any. + if (associationAttributes.Any()) + { + RegisterServerAssociations( + type.GUID, serverType, registrationName, associationAttributes, registrationType); + } + + // If a DisplayName attribute has been set, then set the display name of the COM server. + var displayName = DisplayNameAttribute.GetDisplayName(type); + if (!string.IsNullOrEmpty(displayName)) + SetServerDisplayName(type.GUID, displayName, registrationType); + + // Execute the custom register function, if there is one. + CustomRegisterFunctionAttribute.ExecuteIfExists(type, registrationType); + + // Notify the shell we've updated associations. + Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); + Logging.Log($"Registration of {type.Name} completed"); + } + /// /// Unregisters a SharpShell server. This will remove the associations defined by the /// server's COMServerAssociation attribute. @@ -139,20 +207,53 @@ public static void RegisterServer(ISharpShellServer server, RegistrationType reg public static void UnregisterServer(ISharpShellServer server, RegistrationType registrationType) { // Unapprove the extension. - UnapproveExtension(server, registrationType); + UnapproveExtension(server.ServerClsid, registrationType); // Pass the server type to the SharpShellServer internal unregistration function and let it // take over from there. - SharpShellServer.DoUnregister(server.GetType(), registrationType); + UnregisterServerType(server.GetType(), registrationType); } + /// + /// Actually performs unregistration. The ComUnregisterFunction decorated method will call this function + /// internally with the flag appropriate for the operating system processor architecture. + /// However, this function can also be called manually if needed. + /// + /// The type of object to unregister, this must be a SharpShellServer derived class. + /// Type of the registration to unregister. + internal static void UnregisterServerType(Type type, RegistrationType registrationType) + { + Logging.Log($"Preparing to unregister SharpShell Server {type.Name} as {registrationType}"); + + // Get the association data. + var associationAttributes = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) + .OfType().ToList(); + + // Get the server type and the registration name. + var serverType = ServerTypeAttribute.GetServerType(type); + var serverName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(type); + + // Unregister the server associations, if there are any. + if (associationAttributes.Any()) + { + UnregisterServerAssociations(serverType, serverName, associationAttributes, registrationType); + } + + // Execute the custom unregister function, if there is one. + CustomUnregisterFunctionAttribute.ExecuteIfExists(type, registrationType); + + // Notify the shell we've updated associations. + Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); + Logging.Log($"Unregistration of {type.Name} completed"); + } + /// /// Enumerates Shell extensions. /// /// Type of the registration. /// The shell extension types. /// - public static IEnumerable EnumerateExtensions(RegistrationType registrationType, ShellExtensionType shellExtensionTypes) + public static IEnumerable EnumerateExtensions(RegistrationType registrationType) { var shellExtensionsGuidMap = new Dictionary(); @@ -191,7 +292,7 @@ public static IEnumerable EnumerateExtensions(Re Guid guid; if (Guid.TryParse(guidVal, out guid) == false) continue; - System.Diagnostics.Trace.WriteLine(string.Format("{0} has {3} {1} guid {2}", className, + Trace.WriteLine(string.Format("{0} has {3} {1} guid {2}", className, shellExtensionType.ToString(), guid, entry)); // If we do not have a shell extension info for this extension, create one. @@ -224,7 +325,7 @@ public static IEnumerable EnumerateExtensions(Re Guid guid; if (Guid.TryParse(guidVal, out guid) == false) continue; - System.Diagnostics.Trace.WriteLine(string.Format("{0} has {1} guid {2}", className, + Trace.WriteLine(string.Format("{0} has {1} guid {2}", className, shellExtensionType.ToString(), guid)); // If we do not have a shell extension info for this extension, create one. @@ -499,12 +600,11 @@ private static void UnsetIconHandlerDefaultIcon(IRegistryKey classesKey, string /// /// Unregisters the server associations. /// - /// The server CLSID. /// Type of the server. /// Name of the server. /// The association attributes. /// Type of the registration. - internal static void UnregisterServerAssociations(Guid serverClsid, ServerType serverType, string serverName, + private static void UnregisterServerAssociations(ServerType serverType, string serverName, IEnumerable associationAttributes, RegistrationType registrationType) { // Go through each association attribute. @@ -514,22 +614,38 @@ internal static void UnregisterServerAssociations(Guid serverClsid, ServerType s var associationClassNames = CreateClassNamesForAssociations(associationAttribute.AssociationType, associationAttribute.Associations, registrationType); - // Open the classes key... - using (var classesKey = OpenClassesRoot(registrationType)) + UnregisterServerAssociations(serverType, serverName, associationClassNames, registrationType); + } + } + + /// + /// Unregisters the server associations. + /// + /// Type of the server. + /// Name of the server. + /// The association class names. + /// Type of the registration. + private static void UnregisterServerAssociations( + ServerType serverType, + string serverName, + IEnumerable associationClassNames, + RegistrationType registrationType) + { + // Open the classes key... + using (var classesKey = OpenClassesRoot(registrationType)) + { + // ...then go through each association class. + foreach (var associationClassName in associationClassNames) { - // ...then go through each association class. - foreach (var associationClassName in associationClassNames) - { - // Get the key for the association. - var associationKeyPath = GetKeyForServerType(associationClassName, serverType, serverName); + // Get the key for the association. + var associationKeyPath = GetKeyForServerType(associationClassName, serverType, serverName); - // Delete it if it exists. - classesKey.DeleteSubKeyTree(associationKeyPath, false); + // Delete it if it exists. + classesKey.DeleteSubKeyTree(associationKeyPath, false); - // If we're a shell icon handler, we must also unset the defaulticon. - if (serverType == ServerType.ShellIconHandler) - UnsetIconHandlerDefaultIcon(classesKey, associationClassName); - } + // If we're a shell icon handler, we must also unset the defaulticon. + if (serverType == ServerType.ShellIconHandler) + UnsetIconHandlerDefaultIcon(classesKey, associationClassName); } } } @@ -750,10 +866,10 @@ private static bool IsExtensionApproved(Guid serverClsid, RegistrationType regis /// /// Unapproves an extension. /// - /// The server. + /// The server's class id. /// Type of the registration. /// Failed to open the Approved Extensions key. - private static void UnapproveExtension(ISharpShellServer server, RegistrationType registrationType) + private static void UnapproveExtension(Guid serverClassId, RegistrationType registrationType) { // Open the approved extensions key. using (var approvedKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, @@ -765,7 +881,7 @@ private static void UnapproveExtension(ISharpShellServer server, RegistrationTyp throw new InvalidOperationException("Failed to open the Approved Extensions key."); // Delete the value if it's there. - approvedKey.DeleteValue(server.ServerClsid.ToRegistryString(), false); + approvedKey.DeleteValue(serverClassId.ToRegistryString(), false); } } diff --git a/SharpShell/SharpShell/SharpShellServer.cs b/SharpShell/SharpShell/SharpShellServer.cs index 7b4de1f3..54a3ba5e 100644 --- a/SharpShell/SharpShell/SharpShellServer.cs +++ b/SharpShell/SharpShell/SharpShellServer.cs @@ -1,11 +1,9 @@ using System; using System.ComponentModel.Composition; -using System.Linq; using System.Runtime.InteropServices; using SharpShell.Attributes; using SharpShell.Diagnostics; using SharpShell.ServerRegistration; -using SharpShell.Interop; namespace SharpShell { @@ -32,11 +30,14 @@ public abstract class SharpShellServer : ISharpShellServer [ComRegisterFunction] internal static void Register(Type type) { - Logging.Log("Registering server for type " + type.Name); - - // Register the type, use the operating system architecture to determine + Logging.Log("Registering server for type " + type.Name); + + // Register the type, use the operating system architecture to determine // what registration type to perform. - DoRegister(type, Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit); + ServerRegistrationManager.UnregisterServerType( + type, + Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit + ); } /// @@ -52,82 +53,12 @@ internal static void Unregister(Type type) // Unregister the type, use the operating system architecture to determine // what registration type to unregister. - DoUnregister(type, Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit); - } - - /// - /// Actually performs registration. The ComRegisterFunction decorated method will call this function - /// internally with the flag appropriate for the operating system processor architecture. - /// However, this function can also be called manually if needed. - /// - /// The type of object to register, this must be a SharpShellServer derived class. - /// Type of the registration. - internal static void DoRegister(Type type, RegistrationType registrationType) - { - Logging.Log($"Preparing to register SharpShell Server {type.Name} as {registrationType}"); - - // Get the association data. - var associationAttributes = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) - .OfType().ToList(); - - // Get the server type and the registration name. - var serverType = ServerTypeAttribute.GetServerType(type); - var registrationName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(type); - - // Register the server associations, if there are any. - if (associationAttributes.Any()) - { - ServerRegistrationManager.RegisterServerAssociations( - type.GUID, serverType, registrationName, associationAttributes, registrationType); - } - - // If a DisplayName attribute has been set, then set the display name of the COM server. - var displayName = DisplayNameAttribute.GetDisplayName(type); - if (!string.IsNullOrEmpty(displayName)) - ServerRegistrationManager.SetServerDisplayName(type.GUID, displayName, registrationType); - - // Execute the custom register function, if there is one. - CustomRegisterFunctionAttribute.ExecuteIfExists(type, registrationType); - - // Notify the shell we've updated associations. - Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); - Logging.Log($"Registration of {type.Name} completed"); + ServerRegistrationManager.RegisterServerType( + type, + Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit + ); } - - /// - /// Actually performs unregistration. The ComUnregisterFunction decorated method will call this function - /// internally with the flag appropriate for the operating system processor architecture. - /// However, this function can also be called manually if needed. - /// - /// The type of object to unregister, this must be a SharpShellServer derived class. - /// Type of the registration to unregister. - internal static void DoUnregister(Type type, RegistrationType registrationType) - { - Logging.Log($"Preparing to unregister SharpShell Server {type.Name} as {registrationType}"); - - // Get the association data. - var associationAttributes = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) - .OfType().ToList(); - - // Get the server type and the registration name. - var serverType = ServerTypeAttribute.GetServerType(type); - var registrationName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(type); - - // Unregister the server associations, if there are any. - if (associationAttributes.Any()) - { - ServerRegistrationManager.UnregisterServerAssociations( - type.GUID, serverType, registrationName, associationAttributes, registrationType); - } - - // Execute the custom unregister function, if there is one. - CustomUnregisterFunctionAttribute.ExecuteIfExists(type, registrationType); - - // Notify the shell we've updated associations. - Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); - Logging.Log($"Unregistration of {type.Name} completed"); - } - + /// /// Logs the specified message to the SharpShell log, with the name of the type. /// From a14e11b9960d4a740c022490f7471e33deec8067 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:20:28 +0330 Subject: [PATCH 03/12] New method to retrieve a list of Servers from an assembly added --- .../ServerRegistrationManager.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs b/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs index 96703663..7db1c8ac 100644 --- a/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs +++ b/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs @@ -247,6 +247,55 @@ internal static void UnregisterServerType(Type type, RegistrationType registrati Logging.Log($"Unregistration of {type.Name} completed"); } + /// + /// Loads all SharpShell servers from an assembly. + /// + /// The path to the assembly. + /// A ISharpShellServer for each SharpShell server in the assembly. + public static IEnumerable EnumerateFromFile(string path) + { + // Storage for the servers. + Lazy[] serverTypes; + + try + { + // Create an assembly catalog for the assembly and a container from it. + var catalog = new AssemblyCatalog(Path.GetFullPath(path)); + var container = new CompositionContainer(catalog); + + // Get all exports of type ISharpShellServer. + serverTypes = container.GetExports().ToArray(); + } + catch (Exception exception) + { + // It's almost certainly not a COM server. + Logging.Error("ServerManager: Failed to load SharpShell server", exception); + + throw new BadImageFormatException("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", exception); + } + + // Go through each servertype (creating the instance from the lazy). + foreach (var serverType in serverTypes) + { + ISharpShellServer server = null; + + try + { + server = serverType.Value; + } + catch (Exception exception) + { + Trace.TraceError($"An exception occurred loading a server: ${exception}"); + } + + if (server != null) + { + // Yield a server entry for the server type. + yield return server; + } + } + } + /// /// Enumerates Shell extensions. /// From 5ca4af8188ae053b380eb1ee746c4f243d74a4f2 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:22:05 +0330 Subject: [PATCH 04/12] ServerManagerApi class removed and replaced by the ServerRegistrationManager --- .../Tools/ServerManager/ServerManager.csproj | 1 - .../Tools/ServerManager/ServerManagerApi.cs | 84 ------------------- .../Tools/ServerManager/ServerManagerForm.cs | 40 ++++++++- 3 files changed, 36 insertions(+), 89 deletions(-) delete mode 100644 SharpShell/Tools/ServerManager/ServerManagerApi.cs diff --git a/SharpShell/Tools/ServerManager/ServerManager.csproj b/SharpShell/Tools/ServerManager/ServerManager.csproj index 2352c7ff..4563ebab 100644 --- a/SharpShell/Tools/ServerManager/ServerManager.csproj +++ b/SharpShell/Tools/ServerManager/ServerManager.csproj @@ -149,7 +149,6 @@ ServerDetailsView.cs - Form diff --git a/SharpShell/Tools/ServerManager/ServerManagerApi.cs b/SharpShell/Tools/ServerManager/ServerManagerApi.cs deleted file mode 100644 index 5681f395..00000000 --- a/SharpShell/Tools/ServerManager/ServerManagerApi.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition.Hosting; -using System.IO; -using System.Linq; -using System.Windows.Forms; -using SharpShell; -using SharpShell.SharpPropertySheet; -using System.Diagnostics; -using SharpShell.Diagnostics; - -namespace ServerManager -{ - /// - /// Helper class for dealing with servers. - /// - public static class ServerManagerApi - { - /// - /// Loads all SharpShell servers from an assembly. - /// - /// The path to the assembly. - /// A ServerEntry for each SharpShell server in the assembly. - public static IEnumerable LoadServers(string path) - { - // Storage for the servers. - var servers = new List(); - - try - { - // Create an assembly catalog for the assembly and a container from it. - var catalog = new AssemblyCatalog(Path.GetFullPath(path)); - var container = new CompositionContainer(catalog); - - // Get all exports of type ISharpShellServer. - var serverTypes = container.GetExports(); - - // Go through each servertype (creating the instance from the lazy). - foreach(var serverType in serverTypes) - { - ISharpShellServer server = null; - try - { - server = serverType.Value; - } - catch (Exception exception) - { - Trace.TraceError($"An exception occurred loading a server: ${exception.ToString()}"); - servers.Add(new ServerEntry - { - ServerName = "Invalid", - ServerPath = path, - ServerType = ServerType.None, - ClassId = new Guid(), - Server = null, - IsInvalid = true - }); - continue; - } - - // Yield a server entry for the server type. - servers.Add(new ServerEntry - { - ServerName = server.DisplayName, - ServerPath = path, - ServerType = server.ServerType, - ClassId = server.ServerClsid, - Server = server - }); - - } - } - catch (Exception exception) - { - // It's almost certainly not a COM server. - Logging.Error("ServerManager: Failed to load SharpShell server", exception); - MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning"); - } - - // Return the servers. - return servers; - } - } -} diff --git a/SharpShell/Tools/ServerManager/ServerManagerForm.cs b/SharpShell/Tools/ServerManager/ServerManagerForm.cs index 2b2af8d5..0fbc111a 100644 --- a/SharpShell/Tools/ServerManager/ServerManagerForm.cs +++ b/SharpShell/Tools/ServerManager/ServerManagerForm.cs @@ -51,12 +51,44 @@ public void AddServer(string path, bool addToMostRecentlyUsedFiles) { if (ServerEntries.Any(se => se.ServerPath == path)) return; + + try + { + // Load any servers from the assembly. + var serverEntries = ServerRegistrationManager.EnumerateFromFile(path); - // Load any servers from the assembly. - var serverEntries = ServerManagerApi.LoadServers(path); - foreach(var serverEntry in serverEntries) + foreach (var serverEntry in serverEntries) + { + try + { + AddServerEntryToList(new ServerEntry + { + ClassId = serverEntry.ServerClsid, + Server = serverEntry, + ServerName = serverEntry.DisplayName, + ServerPath = path, + ServerType = serverEntry.ServerType, + IsInvalid = false + }); + } + catch + { + AddServerEntryToList(new ServerEntry + { + ServerName = "Invalid", + ServerPath = path, + ServerType = ServerType.None, + ClassId = new Guid(), + Server = null, + IsInvalid = true + }); + } + } + } + catch { - AddServerEntryToList(serverEntry); + addToMostRecentlyUsedFiles = false; + MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning"); } if (addToMostRecentlyUsedFiles && Properties.Settings.Default.RecentlyUsedFiles.Contains(path) == false) From 3f44aa9fb55ff5b121c52c791185dca9e562b790 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:22:57 +0330 Subject: [PATCH 05/12] Fixed a problem with `Uninstall` and `Install` still being enable when no item is selected --- SharpShell/Tools/ServerManager/ServerManagerForm.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SharpShell/Tools/ServerManager/ServerManagerForm.cs b/SharpShell/Tools/ServerManager/ServerManagerForm.cs index 0fbc111a..a4de4922 100644 --- a/SharpShell/Tools/ServerManager/ServerManagerForm.cs +++ b/SharpShell/Tools/ServerManager/ServerManagerForm.cs @@ -387,6 +387,8 @@ private void UpdateUserInterfaceCommands() unregisterServerx64ToolStripMenuItem.Enabled = SelectedServerEntry != null; uninstallServerx86ToolStripMenuItem.Enabled = SelectedServerEntry != null; uninstallServerx64ToolStripMenuItem.Enabled = SelectedServerEntry != null; + uninstallToolStripMenuItem.Enabled = SelectedServerEntry != null; + installToolStripMenuItem.Enabled = SelectedServerEntry != null; // Test functions only available for specific servers. testServerToolStripMenuItem.Enabled = From 12306d262239e0fa2a0d8028f0ffac7b7a9c9e38 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:23:34 +0330 Subject: [PATCH 06/12] Install and Uninstall actions now use ServerRegistrationManager instead of RegAsm --- .../Tools/ServerManager/ServerManagerForm.cs | 102 +++++++++++++++--- 1 file changed, 89 insertions(+), 13 deletions(-) diff --git a/SharpShell/Tools/ServerManager/ServerManagerForm.cs b/SharpShell/Tools/ServerManager/ServerManagerForm.cs index a4de4922..efffd40d 100644 --- a/SharpShell/Tools/ServerManager/ServerManagerForm.cs +++ b/SharpShell/Tools/ServerManager/ServerManagerForm.cs @@ -6,12 +6,9 @@ using System.IO; using System.Linq; using System.Windows.Forms; -using Apex.WinForms.Interop; -using Apex.WinForms.Shell; using ServerManager.ShellDebugger; using ServerManager.TestShell; using SharpShell; -using SharpShell.Attributes; using SharpShell.Diagnostics; using SharpShell.Helpers; using SharpShell.ServerRegistration; @@ -21,7 +18,6 @@ using SharpShell.SharpIconOverlayHandler; using SharpShell.SharpInfoTipHandler; using SharpShell.SharpPreviewHandler; -using SharpShell.SharpPropertySheet; using SharpShell.SharpThumbnailHandler; namespace ServerManager @@ -143,6 +139,17 @@ public ServerEntry SelectedServerEntry get { return listViewServers.SelectedItems.Count > 0 ? (ServerEntry)listViewServers.SelectedItems[0].Tag : null; } } + public ServerEntry[] AllServerEntries + { + get + { + return listViewServers.Items + .Cast() + .Select(item => item.Tag as ServerEntry) + .Where(entry => entry != null).ToArray(); + } + } + private void ServerManagerForm_Load(object sender, EventArgs e) { // Setup the statusbar. @@ -323,6 +330,19 @@ private void CheckIfRegisterOrUnregisterRequiresExplorerRestart(ISharpShellServe } } + private void CheckIfRegisterOrUnregisterRequiresExplorerRestart(ISharpShellServer[] servers) + { + if (servers.Any(server => server.ServerType == ServerType.ShellIconOverlayHandler)) + { + if (MessageBox.Show(this, "This change will not take effect until Windows Explorer is restarted. Would you " + + "like to restart Windows Explorer now?", "Restart Explorer?", MessageBoxButtons.YesNo, + MessageBoxIcon.Question) == DialogResult.Yes) + { + ExplorerManager.RestartExplorer(); + } + } + } + private void registerServerx86ToolStripMenuItem_Click(object sender, EventArgs e) { // Bail if we have no server selected. @@ -482,13 +502,41 @@ private void toolStripButtonAttachDebugger_Click(object sender, EventArgs e) private void installToolStripMenuItem_Click(object sender, EventArgs e) { // Bail if we have no server selected. - if (SelectedServerEntry == null) + if (string.IsNullOrWhiteSpace(SelectedServerEntry?.ServerPath)) return; - // Create a regasm instance and register the server. - var regasm = new RegAsm(); - var success = Environment.Is64BitOperatingSystem ? regasm.Register64(SelectedServerEntry.ServerPath, true) : regasm.Register32(SelectedServerEntry.ServerPath, true); - + // Get all server types + var serverEntries = AllServerEntries.Where(entry => + !string.IsNullOrWhiteSpace(entry.ServerPath) && + Path.GetFullPath(entry.ServerPath).Equals( + Path.GetFullPath(SelectedServerEntry.ServerPath), + StringComparison.InvariantCultureIgnoreCase + ) + ).ToArray(); + + var registrationType = + Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit; + + var success = true; + + foreach (var serverEntry in serverEntries) + { + try + { + ServerRegistrationManager.InstallServer(serverEntry.Server, registrationType, true); + ServerRegistrationManager.RegisterServer(serverEntry.Server, registrationType); + } + catch (Exception exception) + { + Logging.Error($"Failed to install and register a server. [{serverEntry.ServerName}]", exception); + success = false; + } + + serverDetailsView1.Initialise(serverEntry); + } + + CheckIfRegisterOrUnregisterRequiresExplorerRestart(serverEntries.Select(entry => entry.Server).ToArray()); + // Inform the user of the result. if (success) { @@ -505,12 +553,40 @@ private void installToolStripMenuItem_Click(object sender, EventArgs e) private void uninstallToolStripMenuItem_Click(object sender, EventArgs e) { // Bail if we have no server selected. - if (SelectedServerEntry == null) + if (string.IsNullOrWhiteSpace(SelectedServerEntry?.ServerPath)) return; - // Create a regasm instance and register the server. - var regasm = new RegAsm(); - var success = Environment.Is64BitOperatingSystem ? regasm.Unregister64(SelectedServerEntry.ServerPath) : regasm.Unregister32(SelectedServerEntry.ServerPath); + // Get all server types + var serverEntries = AllServerEntries.Where(entry => + !string.IsNullOrWhiteSpace(entry.ServerPath) && + Path.GetFullPath(entry.ServerPath).Equals( + Path.GetFullPath(SelectedServerEntry.ServerPath), + StringComparison.InvariantCultureIgnoreCase + ) + ).ToArray(); + + var registrationType = + Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit; + + var success = true; + + foreach (var serverEntry in serverEntries) + { + try + { + ServerRegistrationManager.UnregisterServer(serverEntry.Server, registrationType); + ServerRegistrationManager.UninstallServer(serverEntry.Server, registrationType); + } + catch (Exception exception) + { + Logging.Error($"Failed to uninstall and unregister a server. [{serverEntry.ServerName}]", exception); + success = false; + } + + serverDetailsView1.Initialise(serverEntry); + } + + CheckIfRegisterOrUnregisterRequiresExplorerRestart(serverEntries.Select(entry => entry.Server).ToArray()); // Inform the user of the result. if (success) From f355b647459f8f042ddab60936406500e966482b Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:24:38 +0330 Subject: [PATCH 07/12] ShellExtensionManager Project updated to be compatible with the current API --- .../ShellExtensions/ShellExtensionsViewModel.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs b/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs index e1934637..bcd104a1 100644 --- a/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs +++ b/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; +using System.Collections.ObjectModel; using Apex.MVVM; using SharpShell.ServerRegistration; @@ -26,7 +22,7 @@ public ShellExtensionsViewModel() private void DoRefreshExtensionsCommand(object parameter) { // Get all servers. - var servers = ServerRegistrationManager.EnumerateExtensions(RegistrationType.OS64Bit, ShellExtensionType.IconHandler); + var servers = ServerRegistrationManager.EnumerateExtensions(RegistrationType.OS64Bit); foreach (var server in servers) { var extensionViewModel = new ExtensionViewModel(); From 67cd8a988ad322f520aaa7581dbbe7f4769db19e Mon Sep 17 00:00:00 2001 From: s_falahati Date: Thu, 3 Jan 2019 23:27:09 +0330 Subject: [PATCH 08/12] ServerRegistrationManager is now updated to use ServerRegistrationManager class instead of RegAsm. A new parameter is now available to force the use of RegAsm; just like before --- .../ServerRegistrationManager/Application.cs | 156 ++++++++++++++++-- 1 file changed, 145 insertions(+), 11 deletions(-) diff --git a/SharpShell/Tools/ServerRegistrationManager/Application.cs b/SharpShell/Tools/ServerRegistrationManager/Application.cs index 8ab725ec..e613dc36 100644 --- a/SharpShell/Tools/ServerRegistrationManager/Application.cs +++ b/SharpShell/Tools/ServerRegistrationManager/Application.cs @@ -3,6 +3,7 @@ using System.Linq; using ServerRegistrationManager.Actions; using ServerRegistrationManager.OutputService; +using SharpShell; using SharpShell.Diagnostics; using SharpShell.Helpers; using SharpShell.ServerRegistration; @@ -64,11 +65,20 @@ public void Run(string[] args) registrationType = RegistrationType.OS64Bit; } + var viaRegAsm = parameters.Any(p => p.Equals(ParameterRegAsm, StringComparison.InvariantCultureIgnoreCase)); + var codebase = parameters.Any(p => p.Equals(ParameterCodebase, StringComparison.InvariantCultureIgnoreCase)); + // Based on the verb, perform the action. if (verb == VerbInstall) - InstallServer(target, registrationType, parameters.Any(p => p == ParameterCodebase)); + if (viaRegAsm) + InstallServerViaRegAsm(target, registrationType, codebase); + else + InstallServer(target, registrationType, codebase); else if (verb == VerbUninstall) - UninstallServer(target, registrationType); + if (viaRegAsm) + UninstallServerViaRegAsm(target, registrationType); + else + UninstallServer(target, registrationType); else if (verb == VerbConfig) ConfigAction.Execute(outputService, parameters); else if (verb == VerbEnableEventLog) @@ -86,24 +96,82 @@ public void Run(string[] args) private void InstallServer(string path, RegistrationType registrationType, bool codeBase) { // Validate the path. - if (File.Exists(path) == false) + if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) { outputService.WriteError("File '" + path + "' does not exist.", true); return; } - var regasm = new RegAsm(); - var success = registrationType == RegistrationType.OS32Bit ? regasm.Register32(path, codeBase) : regasm.Register64(path, codeBase); + bool success = true; + try + { + // Load any servers from the assembly. + var servers = SharpShell.ServerRegistration.ServerRegistrationManager.EnumerateFromFile(path); + foreach (var server in servers) + { + var name = server.GetType().Name; + try + { + name = server.DisplayName; + SharpShell.ServerRegistration.ServerRegistrationManager.InstallServer(server, registrationType, codeBase); + SharpShell.ServerRegistration.ServerRegistrationManager.RegisterServer(server, registrationType); + } + catch (Exception e) + { + success = false; + outputService.WriteError(e.ToString()); + outputService.WriteError($"Failed to install and register a server. [{name}]", true); + } + } + } + catch (Exception e) + { + success = false; + outputService.WriteError(e.ToString()); + } + if (success) { outputService.WriteSuccess($" {path} installed and registered.", true); - outputService.WriteMessage(regasm.StandardOutput); } else { outputService.WriteError($" {path} failed to register.", true); - outputService.WriteError(regasm.StandardError); + } + } + + /// + /// Installs a SharpShell server at the specified path via RegAsm. + /// + /// The path to the SharpShell server. + /// Type of the registration. + /// if set to true install from codebase rather than GAC. + private void InstallServerViaRegAsm(string path, RegistrationType registrationType, bool codeBase) + { + // Validate the path. + if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) + { + outputService.WriteError("File '" + path + "' does not exist.", true); + return; + } + + var regAsm = new RegAsm(); + + var success = + registrationType == RegistrationType.OS32Bit + ? regAsm.Register32(path, codeBase) + : regAsm.Register64(path, codeBase); + + if (success) + { + outputService.WriteSuccess($" {path} installed and registered.", true); + outputService.WriteMessage(regAsm.StandardOutput); + } + else + { + outputService.WriteError($" {path} failed to register.", true); + outputService.WriteError(regAsm.StandardError); } } @@ -114,18 +182,82 @@ private void InstallServer(string path, RegistrationType registrationType, bool /// Type of the registration. private void UninstallServer(string path, RegistrationType registrationType) { - var regasm = new RegAsm(); - var success = registrationType == RegistrationType.OS32Bit ? regasm.Unregister32(path) : regasm.Unregister64(path); + // Validate the path. + if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) + { + outputService.WriteError("File '" + path + "' does not exist.", true); + return; + } + + bool success = true; + try + { + // Load any servers from the assembly. + var servers = SharpShell.ServerRegistration.ServerRegistrationManager.EnumerateFromFile(path); + + foreach (var server in servers) + { + var name = server.GetType().Name; + try + { + name = server.DisplayName; + SharpShell.ServerRegistration.ServerRegistrationManager.UninstallServer(server, registrationType); + SharpShell.ServerRegistration.ServerRegistrationManager.UnregisterServer(server, registrationType); + } + catch (Exception e) + { + success = false; + outputService.WriteError(e.ToString()); + outputService.WriteError($"Failed to uninstall and unregister a server. [{name}]", true); + } + } + } + catch (Exception e) + { + success = false; + outputService.WriteError(e.ToString()); + } if (success) { outputService.WriteSuccess($" {path} uninstalled.", true); - outputService.WriteMessage(regasm.StandardOutput); } else { outputService.WriteError($" {path} failed to uninstall.", true); - outputService.WriteError(regasm.StandardError); + } + } + + /// + /// Uninstalls a SharpShell server located at 'path' vis RegAsm. + /// + /// The path to the SharpShell server. + /// Type of the registration. + private void UninstallServerViaRegAsm(string path, RegistrationType registrationType) + { + // Validate the path. + if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) + { + outputService.WriteError("File '" + path + "' does not exist.", true); + return; + } + + var regAsm = new RegAsm(); + + var success = + registrationType == RegistrationType.OS32Bit + ? regAsm.Unregister32(path) + : regAsm.Unregister64(path); + + if (success) + { + outputService.WriteSuccess($" {path} uninstalled.", true); + outputService.WriteMessage(regAsm.StandardOutput); + } + else + { + outputService.WriteError($" {path} failed to uninstall.", true); + outputService.WriteError(regAsm.StandardError); } } @@ -151,5 +283,7 @@ private void ShowWelcome() private const string ParameterOS32 = @"-os32"; private const string ParameterOS64 = @"-os64"; + + private const string ParameterRegAsm = @"-regasm"; } } From 724d3eb0422fead8a53a1df59f14533d696edfda Mon Sep 17 00:00:00 2001 From: s_falahati Date: Fri, 4 Jan 2019 10:29:30 +0330 Subject: [PATCH 09/12] Fixed a problem with last commits regarding invalid behavior with COM registration --- SharpShell/SharpShell/SharpShellServer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpShell/SharpShell/SharpShellServer.cs b/SharpShell/SharpShell/SharpShellServer.cs index 54a3ba5e..63a282db 100644 --- a/SharpShell/SharpShell/SharpShellServer.cs +++ b/SharpShell/SharpShell/SharpShellServer.cs @@ -34,7 +34,7 @@ internal static void Register(Type type) // Register the type, use the operating system architecture to determine // what registration type to perform. - ServerRegistrationManager.UnregisterServerType( + ServerRegistrationManager.RegisterServerType( type, Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit ); @@ -53,7 +53,7 @@ internal static void Unregister(Type type) // Unregister the type, use the operating system architecture to determine // what registration type to unregister. - ServerRegistrationManager.RegisterServerType( + ServerRegistrationManager.UnregisterServerType( type, Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit ); From 795e597b05adb613c7714f11784309d1d85ec4b2 Mon Sep 17 00:00:00 2001 From: s_falahati Date: Wed, 9 Jan 2019 03:45:58 +0330 Subject: [PATCH 10/12] All projects updated to C# 7.3 --- .../AdvancedContextMenuExtension.csproj | 2 ++ .../CopyDirectoryLocationHandler.csproj | 2 ++ .../CountLinesExtension/CountLinesExtension.csproj | 2 ++ .../Samples/ContextMenu/DynamicSubMenu/DynamicSubMenus.csproj | 2 ++ .../CopyPathDataHandler/CopyPathDataHandler.csproj | 2 ++ .../DeskBand/WebSearchDeskBand/WebSearchDeskBand.csproj | 2 ++ .../Samples/DropHandler/XsdDropHandler/XsdDropHandler.csproj | 2 ++ .../Samples/IconHandler/DllIconHandler/DllIconHandler.csproj | 2 ++ .../LockedFileIconOverlayHandler.csproj | 2 ++ .../ReadOnlyFileIconOverlayHandler.csproj | 2 ++ .../FolderInfoTipHandler/FolderInfoTipHandler.csproj | 2 ++ .../EnvironmentVariablesNamespaceExtension.csproj | 2 ++ .../GitHubNamespaceExtension/GitHubNamespaceExtension.csproj | 2 ++ .../RegistryNamespaceExtension.csproj | 2 ++ .../PreviewHandler/AbcPreviewHandler/AbcPreviewHandler.csproj | 2 ++ .../IconPreviewHandler/IconPreviewHandler.csproj | 2 ++ .../FileTimesPropertySheet/FileTimesPropertySheet.csproj | 2 ++ .../ResourcesPropertySheet.Tests.csproj | 2 ++ .../ResourcesPropertySheet/ResourcesPropertySheet.csproj | 2 ++ .../TxtThumbnailHandler/TxtThumbnailHandler.csproj | 2 ++ SharpShell/SharpShell.Tests/SharpShell.Tests.csproj | 2 ++ SharpShell/SharpShell/SharpShell.csproj | 2 ++ SharpShell/Tools/ServerManager/ServerManager.csproj | 4 ++++ .../ServerRegistrationManager.csproj | 2 ++ .../Tools/ShellExtensionManager/ShellExtensionManager.csproj | 2 ++ 25 files changed, 52 insertions(+) diff --git a/SharpShell/Samples/ContextMenu/AdvancedContextMenuExtension/AdvancedContextMenuExtension.csproj b/SharpShell/Samples/ContextMenu/AdvancedContextMenuExtension/AdvancedContextMenuExtension.csproj index 4e636a3b..4964a388 100644 --- a/SharpShell/Samples/ContextMenu/AdvancedContextMenuExtension/AdvancedContextMenuExtension.csproj +++ b/SharpShell/Samples/ContextMenu/AdvancedContextMenuExtension/AdvancedContextMenuExtension.csproj @@ -28,6 +28,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -36,6 +37,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/ContextMenu/CopyDirectoryLocationHandler/CopyDirectoryLocationHandler.csproj b/SharpShell/Samples/ContextMenu/CopyDirectoryLocationHandler/CopyDirectoryLocationHandler.csproj index b9c7d6e7..b1872d15 100644 --- a/SharpShell/Samples/ContextMenu/CopyDirectoryLocationHandler/CopyDirectoryLocationHandler.csproj +++ b/SharpShell/Samples/ContextMenu/CopyDirectoryLocationHandler/CopyDirectoryLocationHandler.csproj @@ -28,6 +28,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -36,6 +37,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/ContextMenu/CountLinesExtension/CountLinesExtension.csproj b/SharpShell/Samples/ContextMenu/CountLinesExtension/CountLinesExtension.csproj index 987b69df..ef4ec696 100644 --- a/SharpShell/Samples/ContextMenu/CountLinesExtension/CountLinesExtension.csproj +++ b/SharpShell/Samples/ContextMenu/CountLinesExtension/CountLinesExtension.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/ContextMenu/DynamicSubMenu/DynamicSubMenus.csproj b/SharpShell/Samples/ContextMenu/DynamicSubMenu/DynamicSubMenus.csproj index b909991e..f8de19b2 100644 --- a/SharpShell/Samples/ContextMenu/DynamicSubMenu/DynamicSubMenus.csproj +++ b/SharpShell/Samples/ContextMenu/DynamicSubMenu/DynamicSubMenus.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -28,6 +29,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/DataHandler/CopyPathDataHandler/CopyPathDataHandler.csproj b/SharpShell/Samples/DataHandler/CopyPathDataHandler/CopyPathDataHandler.csproj index 49d1a28a..0969756b 100644 --- a/SharpShell/Samples/DataHandler/CopyPathDataHandler/CopyPathDataHandler.csproj +++ b/SharpShell/Samples/DataHandler/CopyPathDataHandler/CopyPathDataHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/DeskBand/WebSearchDeskBand/WebSearchDeskBand.csproj b/SharpShell/Samples/DeskBand/WebSearchDeskBand/WebSearchDeskBand.csproj index a26d4cc1..b0f145c9 100644 --- a/SharpShell/Samples/DeskBand/WebSearchDeskBand/WebSearchDeskBand.csproj +++ b/SharpShell/Samples/DeskBand/WebSearchDeskBand/WebSearchDeskBand.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -30,6 +31,7 @@ 4 false AnyCPU + 7.3 true diff --git a/SharpShell/Samples/DropHandler/XsdDropHandler/XsdDropHandler.csproj b/SharpShell/Samples/DropHandler/XsdDropHandler/XsdDropHandler.csproj index 00bdb76a..610b06ac 100644 --- a/SharpShell/Samples/DropHandler/XsdDropHandler/XsdDropHandler.csproj +++ b/SharpShell/Samples/DropHandler/XsdDropHandler/XsdDropHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/IconHandler/DllIconHandler/DllIconHandler.csproj b/SharpShell/Samples/IconHandler/DllIconHandler/DllIconHandler.csproj index 51ceae43..31906394 100644 --- a/SharpShell/Samples/IconHandler/DllIconHandler/DllIconHandler.csproj +++ b/SharpShell/Samples/IconHandler/DllIconHandler/DllIconHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/IconOverlayHandler/LockedFileIconOverlayHandler/LockedFileIconOverlayHandler.csproj b/SharpShell/Samples/IconOverlayHandler/LockedFileIconOverlayHandler/LockedFileIconOverlayHandler.csproj index e7819f6c..6cd61810 100644 --- a/SharpShell/Samples/IconOverlayHandler/LockedFileIconOverlayHandler/LockedFileIconOverlayHandler.csproj +++ b/SharpShell/Samples/IconOverlayHandler/LockedFileIconOverlayHandler/LockedFileIconOverlayHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/IconOverlayHandler/ReadOnlyFileIconOverlayHandler/ReadOnlyFileIconOverlayHandler.csproj b/SharpShell/Samples/IconOverlayHandler/ReadOnlyFileIconOverlayHandler/ReadOnlyFileIconOverlayHandler.csproj index 425e5ffd..07a640f3 100644 --- a/SharpShell/Samples/IconOverlayHandler/ReadOnlyFileIconOverlayHandler/ReadOnlyFileIconOverlayHandler.csproj +++ b/SharpShell/Samples/IconOverlayHandler/ReadOnlyFileIconOverlayHandler/ReadOnlyFileIconOverlayHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/InfoTipHandler/FolderInfoTipHandler/FolderInfoTipHandler.csproj b/SharpShell/Samples/InfoTipHandler/FolderInfoTipHandler/FolderInfoTipHandler.csproj index 7f3fa2f0..da95b2d3 100644 --- a/SharpShell/Samples/InfoTipHandler/FolderInfoTipHandler/FolderInfoTipHandler.csproj +++ b/SharpShell/Samples/InfoTipHandler/FolderInfoTipHandler/FolderInfoTipHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/NamespaceExtension/EnvironmentVariablesNamespaceExtension/EnvironmentVariablesNamespaceExtension.csproj b/SharpShell/Samples/NamespaceExtension/EnvironmentVariablesNamespaceExtension/EnvironmentVariablesNamespaceExtension.csproj index 1d2401f1..44ebfb97 100644 --- a/SharpShell/Samples/NamespaceExtension/EnvironmentVariablesNamespaceExtension/EnvironmentVariablesNamespaceExtension.csproj +++ b/SharpShell/Samples/NamespaceExtension/EnvironmentVariablesNamespaceExtension/EnvironmentVariablesNamespaceExtension.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -28,6 +29,7 @@ TRACE prompt 4 + 7.3 diff --git a/SharpShell/Samples/NamespaceExtension/GitHubNamespaceExtension/GitHubNamespaceExtension.csproj b/SharpShell/Samples/NamespaceExtension/GitHubNamespaceExtension/GitHubNamespaceExtension.csproj index 2c38cb16..03deab01 100644 --- a/SharpShell/Samples/NamespaceExtension/GitHubNamespaceExtension/GitHubNamespaceExtension.csproj +++ b/SharpShell/Samples/NamespaceExtension/GitHubNamespaceExtension/GitHubNamespaceExtension.csproj @@ -22,6 +22,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -30,6 +31,7 @@ TRACE prompt 4 + 7.3 diff --git a/SharpShell/Samples/NamespaceExtension/RegistryNamespaceExtension/RegistryNamespaceExtension.csproj b/SharpShell/Samples/NamespaceExtension/RegistryNamespaceExtension/RegistryNamespaceExtension.csproj index c614393f..21406552 100644 --- a/SharpShell/Samples/NamespaceExtension/RegistryNamespaceExtension/RegistryNamespaceExtension.csproj +++ b/SharpShell/Samples/NamespaceExtension/RegistryNamespaceExtension/RegistryNamespaceExtension.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -28,6 +29,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/PreviewHandler/AbcPreviewHandler/AbcPreviewHandler.csproj b/SharpShell/Samples/PreviewHandler/AbcPreviewHandler/AbcPreviewHandler.csproj index cfb18e4f..e2390499 100644 --- a/SharpShell/Samples/PreviewHandler/AbcPreviewHandler/AbcPreviewHandler.csproj +++ b/SharpShell/Samples/PreviewHandler/AbcPreviewHandler/AbcPreviewHandler.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -28,6 +29,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/PreviewHandler/IconPreviewHandler/IconPreviewHandler.csproj b/SharpShell/Samples/PreviewHandler/IconPreviewHandler/IconPreviewHandler.csproj index f162de99..b48873b9 100644 --- a/SharpShell/Samples/PreviewHandler/IconPreviewHandler/IconPreviewHandler.csproj +++ b/SharpShell/Samples/PreviewHandler/IconPreviewHandler/IconPreviewHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/PropertySheet/FileTimesPropertySheet/FileTimesPropertySheet.csproj b/SharpShell/Samples/PropertySheet/FileTimesPropertySheet/FileTimesPropertySheet.csproj index ff71f2bd..fdc71ceb 100644 --- a/SharpShell/Samples/PropertySheet/FileTimesPropertySheet/FileTimesPropertySheet.csproj +++ b/SharpShell/Samples/PropertySheet/FileTimesPropertySheet/FileTimesPropertySheet.csproj @@ -28,6 +28,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -36,6 +37,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/PropertySheet/ResourcesPropertySheet.Tests/ResourcesPropertySheet.Tests.csproj b/SharpShell/Samples/PropertySheet/ResourcesPropertySheet.Tests/ResourcesPropertySheet.Tests.csproj index 868bb366..7f103670 100644 --- a/SharpShell/Samples/PropertySheet/ResourcesPropertySheet.Tests/ResourcesPropertySheet.Tests.csproj +++ b/SharpShell/Samples/PropertySheet/ResourcesPropertySheet.Tests/ResourcesPropertySheet.Tests.csproj @@ -24,6 +24,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -32,6 +33,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/PropertySheet/ResourcesPropertySheet/ResourcesPropertySheet.csproj b/SharpShell/Samples/PropertySheet/ResourcesPropertySheet/ResourcesPropertySheet.csproj index c0585847..a1ce0bfa 100644 --- a/SharpShell/Samples/PropertySheet/ResourcesPropertySheet/ResourcesPropertySheet.csproj +++ b/SharpShell/Samples/PropertySheet/ResourcesPropertySheet/ResourcesPropertySheet.csproj @@ -21,6 +21,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -29,6 +30,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Samples/ThumbnailHandler/TxtThumbnailHandler/TxtThumbnailHandler.csproj b/SharpShell/Samples/ThumbnailHandler/TxtThumbnailHandler/TxtThumbnailHandler.csproj index 25d421fa..50e468f5 100644 --- a/SharpShell/Samples/ThumbnailHandler/TxtThumbnailHandler/TxtThumbnailHandler.csproj +++ b/SharpShell/Samples/ThumbnailHandler/TxtThumbnailHandler/TxtThumbnailHandler.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -37,6 +38,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/SharpShell.Tests/SharpShell.Tests.csproj b/SharpShell/SharpShell.Tests/SharpShell.Tests.csproj index 31f2bdb8..b0748e02 100644 --- a/SharpShell/SharpShell.Tests/SharpShell.Tests.csproj +++ b/SharpShell/SharpShell.Tests/SharpShell.Tests.csproj @@ -26,6 +26,7 @@ DEBUG;TRACE prompt 4 + 7.3 pdbonly @@ -34,6 +35,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/SharpShell/SharpShell.csproj b/SharpShell/SharpShell/SharpShell.csproj index af6d156b..36be2b8a 100644 --- a/SharpShell/SharpShell/SharpShell.csproj +++ b/SharpShell/SharpShell/SharpShell.csproj @@ -34,6 +34,7 @@ true + 7.3 pdbonly @@ -44,6 +45,7 @@ 4 bin\Release\SharpShell.xml true + 7.3 true diff --git a/SharpShell/Tools/ServerManager/ServerManager.csproj b/SharpShell/Tools/ServerManager/ServerManager.csproj index 4563ebab..05f467cc 100644 --- a/SharpShell/Tools/ServerManager/ServerManager.csproj +++ b/SharpShell/Tools/ServerManager/ServerManager.csproj @@ -33,6 +33,8 @@ DEBUG;TRACE prompt 4 + 7.3 + false x86 @@ -42,6 +44,8 @@ TRACE prompt 4 + 7.3 + false true diff --git a/SharpShell/Tools/ServerRegistrationManager/ServerRegistrationManager.csproj b/SharpShell/Tools/ServerRegistrationManager/ServerRegistrationManager.csproj index 276ab6e0..f55c5a51 100644 --- a/SharpShell/Tools/ServerRegistrationManager/ServerRegistrationManager.csproj +++ b/SharpShell/Tools/ServerRegistrationManager/ServerRegistrationManager.csproj @@ -29,6 +29,7 @@ DEBUG;TRACE prompt 4 + 7.3 AnyCPU @@ -38,6 +39,7 @@ TRACE prompt 4 + 7.3 true diff --git a/SharpShell/Tools/ShellExtensionManager/ShellExtensionManager.csproj b/SharpShell/Tools/ShellExtensionManager/ShellExtensionManager.csproj index 75b1bdc5..b4cd1108 100644 --- a/SharpShell/Tools/ShellExtensionManager/ShellExtensionManager.csproj +++ b/SharpShell/Tools/ShellExtensionManager/ShellExtensionManager.csproj @@ -35,6 +35,7 @@ DEBUG;TRACE prompt 4 + 7.3 x86 @@ -44,6 +45,7 @@ TRACE prompt 4 + 7.3 true From f6d9c1c174d045548eb39cffbdd4218ac8ef702b Mon Sep 17 00:00:00 2001 From: s_falahati Date: Wed, 9 Jan 2019 04:02:17 +0330 Subject: [PATCH 11/12] Complete redone of SRM as long with some major changed to SR projects and multiple class-wide and project-wide cleanups List of changes: * SRM no longer loads assemblies with MEF but rather with Reflection and in sand boxed application domain * SR and SRM no longer keep assemblies open * SR updated to .Net4.62.2 * SRM now supports installation of older versions * It is now possible to get server information without loading a server * Installation and Registration information are not available separately * SR updated to allow manipulation of all registered extensions including managed extensions * Multiple `enum` types are strongly valued to act as a reminder to not change the value of items for backward compatibility * Executing CustomRegisterFunction and CustomUnregisterFunction now respects the compiled version of SharpShell * Public `Attribute`s are no longer need to be strongly typed to the assembly to retrieve information * RegistrationType enum renamed to RegistrationScope * SharpShellInfo now contains information about the used SharpShell assembly used by a SharpShellServer * SR ShellDebugger now redraws on resize * SR TestShell functionality temporarily disabled --- .../ServerRegistrationManagerTests.cs | 63 +- SharpShell/SharpShell.sln.DotSettings | 4 + .../SharpShell/Attributes/AssociationType.cs | 24 +- .../COMServerAssociationAttribute.cs | 66 +- .../CustomRegisterFunctionAttribute.cs | 20 +- .../CustomUnregisterFunctionAttribute.cs | 20 +- .../Attributes/DisplayNameAttribute.cs | 30 +- .../Attributes/HandlerSubkeyAttribute.cs | 27 +- .../PredefinedShellObjectAttribute.cs | 29 +- .../Attributes/RegistrationNameAttribute.cs | 64 +- .../Attributes/ServerTypeAttribute.cs | 73 +- .../Attributes/SpecialClassKeyAttribute.cs | 24 +- .../ExplorerConfigurationManager.cs | 4 +- .../SharpShell/Extensions/EnumExtensions.cs | 39 +- SharpShell/SharpShell/ISharpShellServer.cs | 2 +- .../ServerRegistration/ClassRegistration.cs | 48 +- .../ServerRegistration/ManagedAssemblyInfo.cs | 156 ++ .../ServerRegistration/RegistrationScope.cs | 18 + .../ServerRegistration/RegistrationType.cs | 23 - .../ServerInstallationInfo.cs | 83 + .../ServerInstallationType.cs | 23 + .../ServerRegistationType.cs | 23 - .../ServerRegistrationManager.cs | 1543 +++++++++-------- .../ServerRegistration/ServerSandBox.cs | 418 +++++ .../SharpShellServerInfo.cs | 257 +++ ...ShellExtensionRegisteredAssociationInfo.cs | 92 + .../ShellExtensionRegistrationInfo.cs | 104 +- .../ServerRegistration/ShellExtensionType.cs | 233 ++- .../SpecialRegistryClass.cs | 6 +- SharpShell/SharpShell/ServerType.cs | 46 +- .../SharpShell/SharpDeskBand/SharpDeskBand.cs | 20 +- .../SharpIconOverlayHandler.cs | 26 +- .../SharpNamespaceExtension.cs | 15 +- .../ShellFolderImpl.cs | 2 +- .../SharpPreviewHandler/PreviewHandlerHost.cs | 1 - .../PreviewHandlerRegistrar.cs | 14 +- .../SharpPreviewHandler.cs | 14 +- SharpShell/SharpShell/SharpShell.csproj | 16 +- SharpShell/SharpShell/SharpShellServer.cs | 31 +- .../Tools/ServerManager/ObjectExtensions.cs | 13 +- SharpShell/Tools/ServerManager/Program.cs | 3 - .../Properties/Resources.Designer.cs | 4 +- .../Properties/Settings.Designer.cs | 4 +- .../ServerDetailsView.Designer.cs | 347 ---- .../ServerDetails/ServerDetailsView.cs | 83 - SharpShell/Tools/ServerManager/ServerEntry.cs | 69 - .../Tools/ServerManager/ServerManager.csproj | 21 +- .../ServerManagerForm.Designer.cs | 348 ++-- .../Tools/ServerManager/ServerManagerForm.cs | 954 +++++----- .../ServerManager/ServerManagerForm.resx | 217 ++- .../ShellDebuggerForm.Designer.cs | 30 +- .../ShellDebugger/ShellDebuggerForm.cs | 22 +- .../ShellDebugger/ShellTreeView.cs | 120 +- .../ServerManager/ShellExtensionEntry.cs | 419 +++++ .../ServerManager/TestShell/TestShellForm.cs | 172 +- .../Views/ServerDetailsView.Designer.cs | 537 ++++++ .../ServerManager/Views/ServerDetailsView.cs | 151 ++ .../ServerDetailsView.resx | 0 .../ServerManager/Views/ServerListViewItem.cs | 121 ++ SharpShell/Tools/ServerManager/app.config | 3 + .../ServerRegistrationManager/Application.cs | 46 +- .../ShellExtensions/ExtensionViewModel.cs | 6 +- .../ShellExtensionsViewModel.cs | 22 +- 63 files changed, 4831 insertions(+), 2582 deletions(-) create mode 100644 SharpShell/SharpShell.sln.DotSettings create mode 100644 SharpShell/SharpShell/ServerRegistration/ManagedAssemblyInfo.cs create mode 100644 SharpShell/SharpShell/ServerRegistration/RegistrationScope.cs delete mode 100644 SharpShell/SharpShell/ServerRegistration/RegistrationType.cs create mode 100644 SharpShell/SharpShell/ServerRegistration/ServerInstallationInfo.cs create mode 100644 SharpShell/SharpShell/ServerRegistration/ServerInstallationType.cs delete mode 100644 SharpShell/SharpShell/ServerRegistration/ServerRegistationType.cs create mode 100644 SharpShell/SharpShell/ServerRegistration/ServerSandBox.cs create mode 100644 SharpShell/SharpShell/ServerRegistration/SharpShellServerInfo.cs create mode 100644 SharpShell/SharpShell/ServerRegistration/ShellExtensionRegisteredAssociationInfo.cs delete mode 100644 SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.Designer.cs delete mode 100644 SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.cs delete mode 100644 SharpShell/Tools/ServerManager/ServerEntry.cs create mode 100644 SharpShell/Tools/ServerManager/ShellExtensionEntry.cs create mode 100644 SharpShell/Tools/ServerManager/Views/ServerDetailsView.Designer.cs create mode 100644 SharpShell/Tools/ServerManager/Views/ServerDetailsView.cs rename SharpShell/Tools/ServerManager/{ServerDetails => Views}/ServerDetailsView.resx (100%) create mode 100644 SharpShell/Tools/ServerManager/Views/ServerListViewItem.cs create mode 100644 SharpShell/Tools/ServerManager/app.config diff --git a/SharpShell/SharpShell.Tests/ServerRegistration/ServerRegistrationManagerTests.cs b/SharpShell/SharpShell.Tests/ServerRegistration/ServerRegistrationManagerTests.cs index b68b438e..f4374f83 100644 --- a/SharpShell/SharpShell.Tests/ServerRegistration/ServerRegistrationManagerTests.cs +++ b/SharpShell/SharpShell.Tests/ServerRegistration/ServerRegistrationManagerTests.cs @@ -1,12 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.AccessControl; using Microsoft.Win32; using NUnit.Framework; -using NUnit.Framework.Internal.Execution; using SharpShell.Attributes; -using SharpShell.Extensions; using SharpShell.Registry; using SharpShell.ServerRegistration; @@ -49,11 +44,18 @@ public void Register_Server_Associations_Uses_Appropriate_Class_Id_For_Class_Of_ // Register a context menu with an *.exe association. var clsid = new Guid("00000000-1111-2222-3333-444444444444"); - var serverType = ServerType.ShellContextMenu; + var extensionType = ShellExtensionType.ShellContextMenu; var serverName = "TestContextMenu"; - var associations = new[] { new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".exe") }; - var registrationType = RegistrationType.OS64Bit; - ServerRegistrationManager.RegisterServerAssociations(clsid, serverType, serverName, associations, registrationType); + var registrationType = RegistrationScope.OS64Bit; + var associationClassNames = + new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".exe").GetAssociationClassNames( + registrationType); + + foreach (var associationClassName in associationClassNames) + { + ServerRegistrationManager.RegisterShellExtensionAssociation(clsid, extensionType, serverName, associationClassName, registrationType); + } + // Assert we have the new extention. var print = _registry.Print(RegistryView.Registry64); @@ -83,11 +85,17 @@ public void Register_Server_Associations_Creates_Class_Ids_For_Extension_Of_Clas // Register a file association. Given that this registry is empty, it a new program id and then set an association. var clsid = new Guid("00000000-1111-2222-3333-444444444444"); - var serverType = ServerType.ShellContextMenu; + var extensionType = ShellExtensionType.ShellContextMenu; var serverName = "TestContextMenu"; - var associations = new[] { new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".myfile") }; - var registrationType = RegistrationType.OS64Bit; - ServerRegistrationManager.RegisterServerAssociations(clsid, serverType, serverName, associations, registrationType); + var registrationType = RegistrationScope.OS64Bit; + var associationClassNames = + new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".myfile").GetAssociationClassNames( + registrationType); + + foreach (var associationClassName in associationClassNames) + { + ServerRegistrationManager.RegisterShellExtensionAssociation(clsid, extensionType, serverName, associationClassName, registrationType); + } // Assert we have the new extention. var print = _registry.Print(RegistryView.Registry64); @@ -127,11 +135,18 @@ public void Register_Server_Associations_Fails_If_Class_Ids_For_Extension_Of_Cla { // Register a server. var clsid = new Guid("00000000-1111-2222-3333-444444444444"); - var serverType = ServerType.ShellContextMenu; + var extensionType = ShellExtensionType.ShellContextMenu; var serverName = "TestContextMenu"; - var associations = new[] { new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".myfile") }; - var registrationType = RegistrationType.OS64Bit; - ServerRegistrationManager.RegisterServerAssociations(clsid, serverType, serverName, associations, registrationType); + var registrationType = RegistrationScope.OS64Bit; + var associationClassNames = + new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".myfile").GetAssociationClassNames( + registrationType); + + foreach (var associationClassName in associationClassNames) + { + ServerRegistrationManager.RegisterShellExtensionAssociation(clsid, extensionType, serverName, associationClassName, registrationType); + } + Assert.Fail(@"Server registration should fail"); } catch (Exception exception) @@ -150,11 +165,17 @@ public void Register_Server_Associations_Creates_File_Id_And_Class_Ids_For_Exten { // Register a file association. Given that this registry is empty, it a new program id and then set an association. var clsid = new Guid("00000000-1111-2222-3333-444444444444"); - var serverType = ServerType.ShellContextMenu; + var extensionType = ShellExtensionType.ShellContextMenu; var serverName = "TestContextMenu"; - var associations = new[] {new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".myfile")}; - var registrationType = RegistrationType.OS64Bit; - ServerRegistrationManager.RegisterServerAssociations(clsid, serverType, serverName, associations, registrationType); + var registrationType = RegistrationScope.OS64Bit; + var associationClassNames = + new COMServerAssociationAttribute(AssociationType.ClassOfExtension, ".myfile").GetAssociationClassNames( + registrationType); + + foreach (var associationClassName in associationClassNames) + { + ServerRegistrationManager.RegisterShellExtensionAssociation(clsid, extensionType, serverName, associationClassName, registrationType); + } // Assert we have the new extention. var print = _registry.Print(RegistryView.Registry64); diff --git a/SharpShell/SharpShell.sln.DotSettings b/SharpShell/SharpShell.sln.DotSettings new file mode 100644 index 00000000..eaa28aa9 --- /dev/null +++ b/SharpShell/SharpShell.sln.DotSettings @@ -0,0 +1,4 @@ + + CD + DVD + PIDL \ No newline at end of file diff --git a/SharpShell/SharpShell/Attributes/AssociationType.cs b/SharpShell/SharpShell/Attributes/AssociationType.cs index 90f63719..822ac75f 100644 --- a/SharpShell/SharpShell/Attributes/AssociationType.cs +++ b/SharpShell/SharpShell/Attributes/AssociationType.cs @@ -15,7 +15,7 @@ public enum AssociationType /// /// No server association. /// - None, + None = 0, /// /// Create an association to a specific file extension. @@ -23,64 +23,64 @@ public enum AssociationType /// but on the class of the extension. /// [Obsolete("FileExtension is deprecated. Use 'ClassOfExtension' instead.")] - FileExtension, + FileExtension = 1, /// /// Create an association to the class of a specific file extension. /// - ClassOfExtension, + ClassOfExtension = 2, /// /// Create an association to a class. /// - Class, + Class = 3, /// /// Create an association to the 'all files' class. /// [PredefinedShellObject(@"*")] - AllFiles, + AllFiles = 4, /// /// Create an association to the 'all files and folders' class. /// [PredefinedShellObject(@"AllFileSystemObjects")] - AllFilesAndFolders, + AllFilesAndFolders = 5, /// /// Create an association to the 'directory' class, i.e. file-system folders. /// [PredefinedShellObject(@"Directory")] - Directory, + Directory = 6, /// /// Create an association to the background of folders and the desktop /// [PredefinedShellObject(@"Directory\Background")] - DirectoryBackground, + DirectoryBackground = 7, /// /// Create an association to the background of the desktop (Windows 7 and higher) /// [PredefinedShellObject(@"DesktopBackground")] - DesktopBackground, + DesktopBackground = 8, /// /// Create an association to the drive class. /// [PredefinedShellObject(@"Drive")] - Drive, + Drive = 9, /// /// Create an association to the 'folder' class, i.e. all containers. /// [PredefinedShellObject(@"Folder")] - Folder, + Folder = 10, /// /// Create an association to the unknown files class. /// [PredefinedShellObject(@"Unknown")] - UnknownFiles + UnknownFiles = 11 } } diff --git a/SharpShell/SharpShell/Attributes/COMServerAssociationAttribute.cs b/SharpShell/SharpShell/Attributes/COMServerAssociationAttribute.cs index d179f50b..4ec398b6 100644 --- a/SharpShell/SharpShell/Attributes/COMServerAssociationAttribute.cs +++ b/SharpShell/SharpShell/Attributes/COMServerAssociationAttribute.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Collections.Generic; +using SharpShell.ServerRegistration; namespace SharpShell.Attributes { @@ -8,6 +9,7 @@ namespace SharpShell.Attributes /// Attribute to associate a SharpShell server with a file extension. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + [Serializable] public class COMServerAssociationAttribute : Attribute { /// @@ -17,23 +19,21 @@ public class COMServerAssociationAttribute : Attribute /// The associations. public COMServerAssociationAttribute(AssociationType associationType, params string[] associations) { - // Set the assocation type. - this.associationType = associationType; + // Set the association type. + AssociationType = associationType; // Set the associations. - this.associations = associations; + Associations = associations; } /// /// Gets the file extension associations for a specified type. /// /// The type. - /// The set of file extension assocations. + /// The set of file extension associations. public static IEnumerable GetAssociations(Type type) { - var attribute = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) - .OfType().FirstOrDefault(); - return attribute != null ? attribute.Associations : new string[] {}; + return GetAssociationAttributes(type).SelectMany(attribute => attribute.Associations ?? new string[0]); } /// @@ -41,22 +41,50 @@ public static IEnumerable GetAssociations(Type type) /// /// The type. /// - public static AssociationType GetAssociationType(Type type) + public static IEnumerable GetAssociationTypes(Type type) { - var attribute = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) - .OfType().FirstOrDefault(); - return attribute != null ? attribute.AssociationType : AssociationType.None; + return GetAssociationAttributes(type)? + .Select(attribute => attribute?.AssociationType ?? AssociationType.None) + .Where(associationType => associationType != AssociationType.None); } /// - /// The association type. + /// Gets all COMServerAssociationAttribute attributes of this class /// - private readonly AssociationType associationType; + /// The type. + /// + public static IEnumerable GetAssociationAttributes(Type type) + { + var attributes = ServerSandBox.GetAttributesSafe(type, nameof(COMServerAssociationAttribute), true); - /// - /// The extensions. - /// - private readonly string[] associations; + if (attributes == null) + { + yield break; + } + + foreach (var attribute in attributes) + { + var associationType = ServerSandBox.GetByValPropertySafe( + attribute, + nameof(AssociationType) + ); + + var associations = ServerSandBox.GetByRefPropertySafe>( + attribute, + nameof(Associations) + ); + + if (associationType != null && associations != null) + { + yield return new COMServerAssociationAttribute(associationType.Value, associations.ToArray()); + } + } + } + + public IEnumerable GetAssociationClassNames(RegistrationScope registrationScope) + { + return ServerRegistrationManager.GetAssociationClassNames(AssociationType, Associations, registrationScope); + } /// /// Gets the type of the association. @@ -64,11 +92,11 @@ public static AssociationType GetAssociationType(Type type) /// /// The type of the association. /// - public AssociationType AssociationType { get { return associationType; } } + public AssociationType AssociationType { get; } /// /// Gets the associations. /// - public IEnumerable Associations { get { return associations; } } + public IEnumerable Associations { get; } } } diff --git a/SharpShell/SharpShell/Attributes/CustomRegisterFunctionAttribute.cs b/SharpShell/SharpShell/Attributes/CustomRegisterFunctionAttribute.cs index 4be0a875..1f2cd88e 100644 --- a/SharpShell/SharpShell/Attributes/CustomRegisterFunctionAttribute.cs +++ b/SharpShell/SharpShell/Attributes/CustomRegisterFunctionAttribute.cs @@ -12,19 +12,21 @@ namespace SharpShell.Attributes public class CustomRegisterFunctionAttribute : Attribute { /// - /// Executes the CustomRegisterFunction if it exists for a type. + /// Gets the name of CustomRegisterFunction if it exists for a type. /// /// The type. - /// Type of the registration. - public static void ExecuteIfExists(Type type, RegistrationType registrationType) + public static string GetMethodName(Type type) { // Does the type have the attribute? - var methodWithAttribute = type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy) - .FirstOrDefault(m => m.GetCustomAttributes(typeof(CustomRegisterFunctionAttribute), false).Any()); - - // Do we have a method? If so, invoke it. - if (methodWithAttribute != null) - methodWithAttribute.Invoke(null, new object[] {type, registrationType}); + return type + .GetMethods( + BindingFlags.Static | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.FlattenHierarchy + ).FirstOrDefault(m => + ServerSandBox.GetAttributesSafe(m, nameof(CustomRegisterFunctionAttribute), false).Any() + )?.Name; } } } diff --git a/SharpShell/SharpShell/Attributes/CustomUnregisterFunctionAttribute.cs b/SharpShell/SharpShell/Attributes/CustomUnregisterFunctionAttribute.cs index 216a8037..69f4e549 100644 --- a/SharpShell/SharpShell/Attributes/CustomUnregisterFunctionAttribute.cs +++ b/SharpShell/SharpShell/Attributes/CustomUnregisterFunctionAttribute.cs @@ -12,19 +12,21 @@ namespace SharpShell.Attributes public class CustomUnregisterFunctionAttribute : Attribute { /// - /// Executes the CustomUnregisterFunction if it exists for a type. + /// Gets the name of CustomUnregisterFunction if it exists for a type. /// /// The type. - /// Type of the registration. - public static void ExecuteIfExists(Type type, RegistrationType registrationType) + public static string GetMethodName(Type type) { // Does the type have the attribute? - var methodWithAttribute = type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy) - .FirstOrDefault(m => m.GetCustomAttributes(typeof (CustomUnregisterFunctionAttribute), false).Any()); - - // Do we have a method? If so, invoke it. - if (methodWithAttribute != null) - methodWithAttribute.Invoke(null, new object[] { type, registrationType }); + return type + .GetMethods( + BindingFlags.Static | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.FlattenHierarchy + ).FirstOrDefault(m => + ServerSandBox.GetAttributesSafe(m, nameof(CustomUnregisterFunctionAttribute), false).Any() + )?.Name; } } } diff --git a/SharpShell/SharpShell/Attributes/DisplayNameAttribute.cs b/SharpShell/SharpShell/Attributes/DisplayNameAttribute.cs index 6dcca3df..62af9949 100644 --- a/SharpShell/SharpShell/Attributes/DisplayNameAttribute.cs +++ b/SharpShell/SharpShell/Attributes/DisplayNameAttribute.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; +using SharpShell.ServerRegistration; namespace SharpShell.Attributes { @@ -9,6 +8,7 @@ namespace SharpShell.Attributes /// The name attribute can be used to give a class display name. /// [AttributeUsage(AttributeTargets.Class)] + [Serializable] public class DisplayNameAttribute : Attribute { /// @@ -28,9 +28,7 @@ public DisplayNameAttribute(string displayName) /// The display name of the type, if defined. public static string GetDisplayName(Type type) { - var attribute = type.GetCustomAttributes(typeof (DisplayNameAttribute), true) - .OfType().FirstOrDefault(); - return attribute != null ? attribute.DisplayName : null; + return GetDisplayNameAttribute(type)?.DisplayName; } /// @@ -43,12 +41,32 @@ public static string GetDisplayNameOrTypeName(Type type) { // Return the display name if it is set, otherwise the type name. var displayName = GetDisplayName(type); + return string.IsNullOrEmpty(displayName) ? type.Name : displayName; } + public static DisplayNameAttribute GetDisplayNameAttribute(Type type) + { + var attribute = ServerSandBox.GetAttributesSafe(type, nameof(DisplayNameAttribute), true).FirstOrDefault(); + + if (attribute == null) + { + return null; + } + + var displayName = ServerSandBox.GetStringPropertySafe(attribute, nameof(DisplayName)); + + if (displayName != null) + { + return new DisplayNameAttribute(displayName); + } + + return null; + } + /// /// Gets the display name. /// - public string DisplayName { get; private set; } + public string DisplayName { get; } } } diff --git a/SharpShell/SharpShell/Attributes/HandlerSubkeyAttribute.cs b/SharpShell/SharpShell/Attributes/HandlerSubkeyAttribute.cs index 7851c214..1dd38346 100644 --- a/SharpShell/SharpShell/Attributes/HandlerSubkeyAttribute.cs +++ b/SharpShell/SharpShell/Attributes/HandlerSubkeyAttribute.cs @@ -1,27 +1,30 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using SharpShell.Extensions; namespace SharpShell.Attributes { /// - /// Attribute to describe handler subkey config. + /// Attribute to describe handler sub-key config. /// [AttributeUsage(AttributeTargets.Field)] - public class HandlerSubkeyAttribute : Attribute + internal class HandlerSubKeyAttribute : Attribute { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// + /// The handler sub-key name. /// if set to true [allow multiple entries]. - /// The handler subkey. - public HandlerSubkeyAttribute(bool allowMultipleEntries, string handlerSubkey) + public HandlerSubKeyAttribute(string handlerSubKey, bool allowMultipleEntries) { AllowMultipleEntries = allowMultipleEntries; - HandlerSubkey = handlerSubkey; + HandlerSubKey = handlerSubKey; } + public static HandlerSubKeyAttribute GetHandlerSubKeyAttribute(T value) where T : Enum + { + return value.GetAttribute(); + } /// /// Gets a value indicating whether multiple entries are allowed. @@ -29,14 +32,14 @@ public HandlerSubkeyAttribute(bool allowMultipleEntries, string handlerSubkey) /// /// true if multiple entries are allowed; otherwise, false. /// - public bool AllowMultipleEntries { get; private set; } + public bool AllowMultipleEntries { get; } /// - /// Gets the handler subkey. + /// Gets the handler sub-key. /// /// - /// The handler subkey. + /// The handler sub-key. /// - public string HandlerSubkey { get; private set; } + public string HandlerSubKey { get; } } } diff --git a/SharpShell/SharpShell/Attributes/PredefinedShellObjectAttribute.cs b/SharpShell/SharpShell/Attributes/PredefinedShellObjectAttribute.cs index 8768da12..37ae8871 100644 --- a/SharpShell/SharpShell/Attributes/PredefinedShellObjectAttribute.cs +++ b/SharpShell/SharpShell/Attributes/PredefinedShellObjectAttribute.cs @@ -9,26 +9,31 @@ namespace SharpShell.Attributes [AttributeUsage(AttributeTargets.Field)] internal class PredefinedShellObjectAttribute : Attribute { - /// - /// Initializes a new instance of the class. - /// - /// Name of the class in the registry for this object. + /// + /// Initializes a new instance of the class. + /// + /// Name of the class in the registry for this object. public PredefinedShellObjectAttribute(string className) { ClassName = className; } - /// - /// Gets the class name for a type with a set, or null if none is set. - /// - /// The value. - /// - public static string GetClassName(Enum value) + /// + /// Gets the attribute for a enum type field with a set, or null if none is set. + /// + /// The value. + /// + public static PredefinedShellObjectAttribute GetPredefinedShellObjectAttribute(Enum value) { var enumType = value.GetType(); var enumValueInfo = enumType.GetField(Enum.GetName(enumType, value)); - var predefinedShellObject = enumValueInfo.GetCustomAttributes(false).OfType().FirstOrDefault(); - return predefinedShellObject?.ClassName; + + var predefinedShellObject = enumValueInfo + .GetCustomAttributes(false) + .OfType() + .FirstOrDefault(); + + return predefinedShellObject; } /// diff --git a/SharpShell/SharpShell/Attributes/RegistrationNameAttribute.cs b/SharpShell/SharpShell/Attributes/RegistrationNameAttribute.cs index 998faa63..3e560376 100644 --- a/SharpShell/SharpShell/Attributes/RegistrationNameAttribute.cs +++ b/SharpShell/SharpShell/Attributes/RegistrationNameAttribute.cs @@ -1,51 +1,67 @@ using System; +using System.Linq; +using SharpShell.ServerRegistration; namespace SharpShell.Attributes { /// - /// Specify the registry key name under which a SharpShell server should be registered. - /// By default (without this attribute) a server is registered under the classname. - /// Since each server needs its own registry key name, this attribute does not inherit. + /// Specify the registry key name under which a SharpShell server should be registered. + /// By default (without this attribute) a server is registered under the classname. + /// Since each server needs its own registry key name, this attribute does not inherit. /// [AttributeUsage(AttributeTargets.Class)] + [Serializable] public class RegistrationNameAttribute : Attribute { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The registry key name under which the SharpShell server should be registered. Cannot be null or whitespace. + /// + /// The registry key name under which the SharpShell server should be registered. Cannot be + /// null or whitespace. + /// public RegistrationNameAttribute(string registrationName) { if (string.IsNullOrWhiteSpace(registrationName)) - throw new ArgumentException("registrationName"); + { + throw new ArgumentException(nameof(registrationName)); + } + RegistrationName = registrationName; } /// - /// Gets the registry key name under which to register the SharpShell server. + /// Gets the registry key name under which to register the SharpShell server. /// - public string RegistrationName { get; private set; } + public string RegistrationName { get; } /// - /// Gets the registration name for a type if defined. + /// Gets the registration name attribute for a type if defined, otherwise returns null. /// /// The type. - /// The registration name of the type if defined, or null otherwise. - public static string GetRegistrationName(Type type) + /// The registration name of the type if defined, or + /// null + /// otherwise. + /// + public static RegistrationNameAttribute GetRegistrationNameAttribute(Type type) { - foreach (RegistrationNameAttribute attribute in type.GetCustomAttributes(typeof(RegistrationNameAttribute), false)) - return attribute.RegistrationName; - return null; - } + var attribute = ServerSandBox + .GetAttributesSafe(type, nameof(RegistrationNameAttribute), false) + .FirstOrDefault(); - /// - /// Gets the registration name for a type. - /// - /// The type. - /// The registration name of the type if defined, or type.Name otherwise. - public static string GetRegistrationNameOrTypeName(Type type) - { - return GetRegistrationName(type) ?? type.Name; + if (attribute == null) + { + return null; + } + + var registrationName = ServerSandBox.GetStringPropertySafe(attribute, nameof(RegistrationName)); + + if (registrationName != null) + { + return new RegistrationNameAttribute(registrationName); + } + + return null; } } -} +} \ No newline at end of file diff --git a/SharpShell/SharpShell/Attributes/ServerTypeAttribute.cs b/SharpShell/SharpShell/Attributes/ServerTypeAttribute.cs index cc9362aa..d00f4b9d 100644 --- a/SharpShell/SharpShell/Attributes/ServerTypeAttribute.cs +++ b/SharpShell/SharpShell/Attributes/ServerTypeAttribute.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using SharpShell.ServerRegistration; namespace SharpShell.Attributes { @@ -9,7 +10,8 @@ namespace SharpShell.Attributes /// classes derived from the decorated class will be able to use /// the COMServerAssociationAttribute without any extra configuration. /// - internal class ServerTypeAttribute : Attribute + [Serializable] + public class ServerTypeAttribute : Attribute { /// /// Initializes a new instance of the class. @@ -22,15 +24,70 @@ public ServerTypeAttribute(ServerType serverType) } /// - /// Gets the server type of a type of the association. + /// Gets the server type attribute of a type of the association. /// /// The type. - /// The ServerType of the type, or None if not set. - public static ServerType GetServerType(Type type) + /// The ServerTypeAttribute of the type, or null if not set. + public static ServerTypeAttribute GetServerTypeAttribute(Type type) { - var attribute = type.GetCustomAttributes(typeof(ServerTypeAttribute), true) - .OfType().FirstOrDefault(); - return attribute != null ? attribute.ServerType : ServerType.None; + var attribute = ServerSandBox + .GetAttributesSafe(type, nameof(ServerTypeAttribute), true) + .FirstOrDefault(); + + if (attribute == null) + { + return null; + } + + var serverType = ServerSandBox.GetByValPropertySafe(attribute, nameof(ServerType)); + + if (serverType != null) + { + return new ServerTypeAttribute(serverType.Value); + } + + return null; + } + + public ShellExtensionType ShellExtensionType + { + get + { + switch (ServerType) + { + case ServerType.ShellContextMenu: + + return ShellExtensionType.ShellContextMenu; + case ServerType.ShellPropertySheet: + + return ShellExtensionType.ShellPropertySheet; + case ServerType.ShellIconHandler: + + return ShellExtensionType.ShellIconHandler; + case ServerType.ShellInfoTipHandler: + + return ShellExtensionType.ShellInfoTipHandler; + case ServerType.ShellDropHandler: + + return ShellExtensionType.ShellDropHandler; + case ServerType.ShellPreviewHandler: + + return ShellExtensionType.ShellPreviewHandler; + case ServerType.ShellDataHandler: + + return ShellExtensionType.ShellDataHandler; + case ServerType.ShellThumbnailHandler: + + return ShellExtensionType.ShellThumbnailHandler; + case ServerType.None: + case ServerType.ShellIconOverlayHandler: + case ServerType.ShellNamespaceExtension: + case ServerType.ShellDeskBand: + default: + + return ShellExtensionType.None; + } + } } /// @@ -39,6 +96,6 @@ public static ServerType GetServerType(Type type) /// /// The type of the server. /// - public ServerType ServerType { get; private set; } + public ServerType ServerType { get; } } } diff --git a/SharpShell/SharpShell/Attributes/SpecialClassKeyAttribute.cs b/SharpShell/SharpShell/Attributes/SpecialClassKeyAttribute.cs index 8f8bb641..1d1406c1 100644 --- a/SharpShell/SharpShell/Attributes/SpecialClassKeyAttribute.cs +++ b/SharpShell/SharpShell/Attributes/SpecialClassKeyAttribute.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; namespace SharpShell.Attributes { @@ -9,7 +7,7 @@ namespace SharpShell.Attributes /// Allows the special class key to be defined. /// [AttributeUsage(AttributeTargets.Field)] - public class SpecialClassKeyAttribute : Attribute + internal class SpecialClassKeyAttribute : Attribute { /// /// Initializes a new instance of the class. @@ -20,12 +18,30 @@ public SpecialClassKeyAttribute(string key) SpecialClassKey = key; } + /// + /// Gets the attribute for a enum type field with a set, or null if none is set. + /// + /// The value. + /// + public static SpecialClassKeyAttribute GetPredefinedShellObjectAttribute(Enum value) + { + var enumType = value.GetType(); + var enumValueInfo = enumType.GetField(Enum.GetName(enumType, value)); + + var specialClassKeyAttribute = enumValueInfo + .GetCustomAttributes(false) + .OfType() + .FirstOrDefault(); + + return specialClassKeyAttribute; + } + /// /// Gets the special class key. /// /// /// The special class key. /// - public string SpecialClassKey { get; private set; } + public string SpecialClassKey { get; } } } diff --git a/SharpShell/SharpShell/Diagnostics/ExplorerConfigurationManager.cs b/SharpShell/SharpShell/Diagnostics/ExplorerConfigurationManager.cs index 8a0a0f53..f656395f 100644 --- a/SharpShell/SharpShell/Diagnostics/ExplorerConfigurationManager.cs +++ b/SharpShell/SharpShell/Diagnostics/ExplorerConfigurationManager.cs @@ -28,9 +28,9 @@ private static bool CheckAlwaysUnloadDll() var registry = ServiceRegistry.ServiceRegistry.GetService(); using (var localMachine = registry.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default)) - using (var alwaysUnloadDLLKey = localMachine.OpenSubKey(KeyName_AlwaysUnloadDll)) + using (var alwaysUnloadDllKey = localMachine.OpenSubKey(KeyName_AlwaysUnloadDll)) { - return alwaysUnloadDLLKey != null; + return alwaysUnloadDllKey != null; } } diff --git a/SharpShell/SharpShell/Extensions/EnumExtensions.cs b/SharpShell/SharpShell/Extensions/EnumExtensions.cs index aa6fe2fc..181b50a4 100644 --- a/SharpShell/SharpShell/Extensions/EnumExtensions.cs +++ b/SharpShell/SharpShell/Extensions/EnumExtensions.cs @@ -1,31 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace SharpShell.Extensions +using System; +using System.Linq; + +namespace SharpShell.Extensions { /// /// Extension methods for enumerations. /// - public static class EnumExtensions - { + public static class EnumExtensions + { /// /// Gets the first value of an attribute of the given type, or null. /// /// The attribute type. /// The enum value. /// The first value of the given type, or null. - public static T GetAttribute(this Enum enumValue) where T : Attribute - { - var memberInfo = enumValue.GetType().GetMember(enumValue.ToString()) - .FirstOrDefault(); - - if (memberInfo == null) return null; - - var attribute = (T)memberInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault(); - return attribute; - } - } -} + public static T GetAttribute(this Enum enumValue) where T : Attribute + { + var memberInfo = enumValue.GetType().GetMember(enumValue.ToString()) + .FirstOrDefault(); + + if (memberInfo == null) return null; + + var attribute = (T)memberInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault(); + return attribute; + } + } +} diff --git a/SharpShell/SharpShell/ISharpShellServer.cs b/SharpShell/SharpShell/ISharpShellServer.cs index 91ee82e4..40c95cc6 100644 --- a/SharpShell/SharpShell/ISharpShellServer.cs +++ b/SharpShell/SharpShell/ISharpShellServer.cs @@ -18,7 +18,7 @@ public interface ISharpShellServer /// /// Gets the server CLSID. /// - Guid ServerClsid { get; } + Guid ServerClassId { get; } /// /// Gets the display name. diff --git a/SharpShell/SharpShell/ServerRegistration/ClassRegistration.cs b/SharpShell/SharpShell/ServerRegistration/ClassRegistration.cs index 6af417e0..f7752b79 100644 --- a/SharpShell/SharpShell/ServerRegistration/ClassRegistration.cs +++ b/SharpShell/SharpShell/ServerRegistration/ClassRegistration.cs @@ -1,48 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SharpShell.Attributes; -using SharpShell.Extensions; - -namespace SharpShell.ServerRegistration +namespace SharpShell.ServerRegistration { - /// - /// Helper class to determine the registration info of specific class. - /// + /// + /// Helper class to determine the registration info of specific class. + /// public class ClassRegistration { - /// - /// Initializes a new instance of the class. - /// - /// Name of the class. + + /// + /// Initializes a new instance of the class. + /// + /// Name of the class. public ClassRegistration(string className) - { + { ClassName = className; - lazySpecialRegistryClass = new Lazy(DetermineSpecialRegistryClass); } - /// - /// Determines the special registry class. - /// - /// The special registry class, if any. - private SpecialRegistryClass DetermineSpecialRegistryClass() - { - // Create a dictionary of special class key names to special classes. - Dictionary dic = new Dictionary(); - foreach (SpecialRegistryClass enumValue in Enum.GetValues(typeof(SpecialRegistryClass))) - { - var att = enumValue.GetAttribute(); - if (att != null) - dic[att.SpecialClassKey] = enumValue; - } - - var specialClass = SpecialRegistryClass.None; - dic.TryGetValue(ClassName, out specialClass); - return specialClass; - } - private readonly Lazy lazySpecialRegistryClass; + public SpecialRegistryClass SpecialRegistryClass { get; } /// /// Gets or sets the name of the class. diff --git a/SharpShell/SharpShell/ServerRegistration/ManagedAssemblyInfo.cs b/SharpShell/SharpShell/ServerRegistration/ManagedAssemblyInfo.cs new file mode 100644 index 00000000..6e6776be --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/ManagedAssemblyInfo.cs @@ -0,0 +1,156 @@ +using System; +using System.IO; +using System.Reflection; + +namespace SharpShell.ServerRegistration +{ + [Serializable] + public sealed class ManagedAssemblyInfo + { + private readonly string _assemblyPath; + + public ManagedAssemblyInfo(Assembly assembly) + { + FullName = assembly.FullName; + Version = assembly.GetName().Version.ToString(); + RuntimeVersion = assembly.ImageRuntimeVersion; + CodeBase = assembly.CodeBase; + IsSigned = assembly.GetName().GetPublicKey()?.Length > 0; + } + + public ManagedAssemblyInfo(Type type) : this(type.Assembly) + { + } + + internal ManagedAssemblyInfo(string fullName, string version, string runtimeVersion, string codeBase) + { + FullName = fullName; + Version = version; + RuntimeVersion = runtimeVersion; + CodeBase = codeBase; + + try + { + if (!string.IsNullOrEmpty(AssemblyPath) && File.Exists(AssemblyPath)) + { + var assemblyName = AssemblyName.GetAssemblyName(AssemblyPath); + IsSigned = assemblyName.GetPublicKey().Length > 0; + } + } + catch + { + // ignored + } + } + + internal ManagedAssemblyInfo( + string fullName, + string version, + string runtimeVersion, + string codeBase, + bool isSigned) + { + FullName = fullName; + Version = version; + RuntimeVersion = runtimeVersion; + CodeBase = codeBase; + IsSigned = isSigned; + } + + internal ManagedAssemblyInfo( + string fullName, + string version, + string runtimeVersion, + string codeBase, + string assemblyPath) + { + FullName = fullName; + Version = version; + RuntimeVersion = runtimeVersion; + CodeBase = codeBase; + _assemblyPath = assemblyPath; + + try + { + if (!string.IsNullOrEmpty(AssemblyPath) && File.Exists(AssemblyPath)) + { + var assemblyName = AssemblyName.GetAssemblyName(AssemblyPath); + IsSigned = assemblyName.GetPublicKey().Length > 0; + } + } + catch + { + // ignored + } + } + + internal ManagedAssemblyInfo( + string fullName, + string version, + string runtimeVersion, + string codeBase, + bool isSigned, + string assemblyPath) : this(fullName, version, runtimeVersion, codeBase, isSigned) + { + _assemblyPath = assemblyPath; + } + + internal ManagedAssemblyInfo(string assemblyPath) + { + _assemblyPath = assemblyPath; + + try + { + if (!string.IsNullOrEmpty(AssemblyPath) && File.Exists(AssemblyPath)) + { + var assemblyName = AssemblyName.GetAssemblyName(AssemblyPath); + FullName = assemblyName.FullName; + Version = assemblyName.Version.ToString(); + CodeBase = assemblyName.CodeBase; + IsSigned = assemblyName.GetPublicKey().Length > 0; + RuntimeVersion = ""; + } + } + catch + { + // ignored + } + } + + internal ManagedAssemblyInfo(Type type, string assemblyPath) : this(type) + { + _assemblyPath = assemblyPath; + } + + public string AssemblyPath + { + get + { + if (!string.IsNullOrEmpty(_assemblyPath)) + { + return _assemblyPath; + } + + if (!string.IsNullOrEmpty(CodeBase)) + { + try + { + return new Uri(CodeBase).LocalPath; + } + catch + { + // ignored + } + } + + return null; + } + } + + public string CodeBase { get; } + public string FullName { get; } + public bool IsSigned { get; } + public string RuntimeVersion { get; } + public string Version { get; } + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/RegistrationScope.cs b/SharpShell/SharpShell/ServerRegistration/RegistrationScope.cs new file mode 100644 index 00000000..0a4bfff9 --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/RegistrationScope.cs @@ -0,0 +1,18 @@ +namespace SharpShell.ServerRegistration +{ + /// + /// The registration scope. + /// + public enum RegistrationScope + { + /// + /// 32 Bit operating system registration. + /// + OS32Bit, + + /// + /// 64 Bit operating system registration. + /// + OS64Bit + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/RegistrationType.cs b/SharpShell/SharpShell/ServerRegistration/RegistrationType.cs deleted file mode 100644 index b6e607e4..00000000 --- a/SharpShell/SharpShell/ServerRegistration/RegistrationType.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpShell.ServerRegistration -{ - /// - /// The registation type. - /// - public enum RegistrationType - { - /// - /// 32 Bit operating system registration. - /// - OS32Bit, - - /// - /// 64 Bit operating system registration. - /// - OS64Bit - } -} diff --git a/SharpShell/SharpShell/ServerRegistration/ServerInstallationInfo.cs b/SharpShell/SharpShell/ServerRegistration/ServerInstallationInfo.cs new file mode 100644 index 00000000..0fa049fb --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/ServerInstallationInfo.cs @@ -0,0 +1,83 @@ +using System; +using System.Linq; + +namespace SharpShell.ServerRegistration +{ + public class ServerInstallationInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The server class id. + internal ServerInstallationInfo(Guid serverClassId) + { + ServerInstallationType = ServerInstallationType.PartiallyInstalled; + ServerClassId = serverClassId; + } + + internal ServerInstallationInfo( + Guid serverClassId, + string serverPath, + string threadingModel) : this(serverClassId) + { + ServerInstallationType = ServerInstallationType.NativeInProcess32; + ServerPath = serverPath; + ThreadingModel = threadingModel; + } + + internal ServerInstallationInfo( + Guid serverClassId, + string serverPath, + string threadingModel, + ManagedAssemblyInfo assembly, + string managedClassName) : this(serverClassId, serverPath, threadingModel) + { + ServerInstallationType = ServerInstallationType.ManagedInProcess32; + ManagedAssembly = assembly; + ManagedClassName = managedClassName; + } + + public ManagedAssemblyInfo ManagedAssembly { get; set; } + + /// + /// Gets the managed assembly class. + /// + public string ManagedClassName { get; } + + /// + /// Gets the server class id. + /// + public Guid ServerClassId { get; } + + /// + /// Gets the type of the server registration. + /// + /// + /// The type of the server registration. + /// + public ServerInstallationType ServerInstallationType { get; } + + /// + /// Gets the server path. + /// + public string ServerPath { get; } + + /// + /// Gets the threading model. + /// + public string ThreadingModel { get; } + + public SharpShellServerInfo GetSharpShellServerInformation() + { + if (ServerInstallationType != ServerInstallationType.ManagedInProcess32 || ManagedAssembly == null) + { + throw new InvalidOperationException( + "This operation can not be completed on a native or partially registered extension." + ); + } + + return SharpShellServerInfo.FromAssembly(ManagedAssembly) + .FirstOrDefault(info => info.ClassFullName == ManagedClassName); + } + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ServerInstallationType.cs b/SharpShell/SharpShell/ServerRegistration/ServerInstallationType.cs new file mode 100644 index 00000000..69bb713b --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/ServerInstallationType.cs @@ -0,0 +1,23 @@ +namespace SharpShell.ServerRegistration +{ + /// + /// Represents the type of server registration. + /// + public enum ServerInstallationType + { + /// + /// The server is partially installed only - there's no process models. + /// + PartiallyInstalled, + + /// + /// It's a native InProc32 server. + /// + NativeInProcess32, + + /// + /// It's a managed InProc32 server. + /// + ManagedInProcess32 + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ServerRegistationType.cs b/SharpShell/SharpShell/ServerRegistration/ServerRegistationType.cs deleted file mode 100644 index 8e382f71..00000000 --- a/SharpShell/SharpShell/ServerRegistration/ServerRegistationType.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace SharpShell.ServerRegistration -{ - /// - /// Represents the type of server registration. - /// - public enum ServerRegistationType - { - /// - /// The Server is partially registered only - there's no process models. - /// - PartiallyRegistered, - - /// - /// It's a native InProc32 server. - /// - NativeInProc32, - - /// - /// It's a managed InProc32 server. - /// - ManagedInProc32, - } -} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs b/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs index 7db1c8ac..09e89de9 100644 --- a/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs +++ b/SharpShell/SharpShell/ServerRegistration/ServerRegistrationManager.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition.Hosting; using System.Diagnostics; -using System.IO; using System.Linq; using System.Security.AccessControl; using Microsoft.Win32; @@ -12,84 +10,307 @@ using SharpShell.Interop; using SharpShell.Registry; - namespace SharpShell.ServerRegistration { /// - /// THe Server Registration Manager is an object that can be used to - /// help with Server Registration tasks, such as registering, unregistering - /// and checking servers. It will work with SharpShell Server objects or - /// other servers. + /// THe Server Registration Manager is an object that can be used to + /// help with Server Registration tasks, such as registering, un-registering + /// and checking servers. It will work with SharpShell Server objects or + /// other servers. /// public static class ServerRegistrationManager { /// - /// Installs a SharpShell COM server. + /// Opens the classes root. + /// + /// Type of the registration. + /// The classes root key. + private static IRegistryKey OpenClassesRootKey(RegistrationScope registrationScope) + { + // Get the registry. + var registry = ServiceRegistry.ServiceRegistry.GetService(); + + // Get the classes base key. + var classesBaseKey = registrationScope == RegistrationScope.OS64Bit + ? registry.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64) + : registry.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry32); + + // Return the classes key. + return classesBaseKey; + } + + #region Installation + + /// + /// The classes key name. + /// + private const string RegistryClassesKeyName = @"CLSID"; + + /// + /// The InProc32 key name. + /// + private const string RegistryInProcess32KeyName = @"InprocServer32"; + + /// + /// The value for the net framework servers. + /// + private const string RegistryNetFrameworkServerKeyValue = @"mscoree.dll"; + + /// + /// The threading model key name. + /// + private const string RegistryThreadingModelValueName = @"ThreadingModel"; + + /// + /// THe assembly key name. + /// + private const string RegistryAssemblyValueName = @"Assembly"; + + /// + /// The class key name. + /// + private const string RegistryClassValueName = @"Class"; + + /// + /// The runtime version key name. + /// + private const string RegistryRuntimeVersionValueName = @"RuntimeVersion"; + + /// + /// The codebase key name. + /// + private const string RegistryCodeBaseValueName = @"CodeBase"; + + /// + /// Gets the server registration info. + /// + /// Type of the registration. + /// + /// The ServerRegistrationInfo if the server is registered, otherwise false. + /// + public static ServerInstallationInfo GetExtensionInstallationInfo(RegistrationScope registrationScope) + where T : SharpShellServer + { + // Call the main function. + return GetExtensionInstallationInfo(SharpShellServerInfo.GetServerClassId(), registrationScope); + } + + /// + /// Gets the server registration info. + /// + /// The managed server information. + /// Type of the registration. + /// + /// The ServerRegistrationInfo if the server is registered, otherwise false. + /// + public static ServerInstallationInfo GetExtensionInstallationInfo( + SharpShellServerInfo serverInfo, + RegistrationScope registrationScope) + { + // Call the main function. + return GetExtensionInstallationInfo(serverInfo.ClassId, registrationScope); + } + + /// + /// Gets the server registration info. + /// + /// The server class id. + /// Type of the registration. + /// + /// The ServerRegistrationInfo if the server is registered, otherwise false. + /// + public static ServerInstallationInfo GetExtensionInstallationInfo( + Guid serverClassId, + RegistrationScope registrationScope) + { + // Open the classes. + using (var classesKey = OpenInstalledClassesRoot(registrationScope, RegistryKeyPermissionCheck.ReadSubTree)) + { + // Do we have a sub-key for the server? + using (var serverClassKey = classesKey.OpenSubKey(serverClassId.ToRegistryString())) + { + // If there's no sub-key, the server isn't registered. + if (serverClassKey == null) + { + return null; + } + + // Do we have an InProc32 server? + using (var inProcess32ServerKey = serverClassKey.OpenSubKey(RegistryInProcess32KeyName)) + { + // If we do, we can return the server info for an inProcess32 server. + if (inProcess32ServerKey != null) + { + // Get the default value. + var inProcessLibraryName = inProcess32ServerKey.GetValue(null).ToString(); + + // If we default value is null or empty, we've got a partially registered server. + if (string.IsNullOrEmpty(inProcessLibraryName)) + { + return new ServerInstallationInfo(serverClassId); + } + + // Get the threading model. + var threadingModel = inProcess32ServerKey.GetValue(RegistryThreadingModelValueName) + .ToString(); + + // Is it a .NET server? + if (inProcessLibraryName == RegistryNetFrameworkServerKeyValue) + { + // We've got a .NET server. We should have one sub-key, with the assembly version. + var assemblyVersionSubKeyPath = inProcess32ServerKey.GetSubKeyNames().FirstOrDefault(); + + // If we have no sub-key name, we've got a partially registered server. + if (assemblyVersionSubKeyPath == null) + { + return new ServerInstallationInfo(serverClassId); + } + + // Open the assembly sub-key. + using (var assemblyVersionSubKey = + inProcess32ServerKey.OpenSubKey(assemblyVersionSubKeyPath)) + { + // If we can't open the key, we've got a problem. + if (assemblyVersionSubKey == null) + { + throw new InvalidOperationException("Can't open the details of the server."); + } + + // Read the managed server details. + var assemblyName = assemblyVersionSubKey.GetValue(RegistryAssemblyValueName) + .ToString(); + var runtimeVersion = assemblyVersionSubKey.GetValue(RegistryRuntimeVersionValueName) + .ToString(); + var codeBase = assemblyVersionSubKey.GetValue(RegistryCodeBaseValueName).ToString(); + + var assembly = new ManagedAssemblyInfo( + assemblyName, + assemblyVersionSubKeyPath, + runtimeVersion, + codeBase + ); + + var managedClass = assemblyVersionSubKey.GetValue(RegistryClassValueName) + .ToString(); + + // Return the managed server info. + return new ServerInstallationInfo( + serverClassId, + inProcessLibraryName, + threadingModel, + assembly, + managedClass + ); + } + } + + // We've got a native COM server. + return new ServerInstallationInfo( + serverClassId, + inProcessLibraryName, + threadingModel + ); + } + } + + // If by this point we haven't return server info, we've got a partially registered server. + return new ServerInstallationInfo(serverClassId); + } + } + } + + /// + /// Installs a SharpShell COM server. + /// + /// Type of the registration. + /// if set to true use code base registration (i.e full assembly path, not the GAC). + public static void InstallServer(RegistrationScope registrationScope, bool codeBase) + where T : SharpShellServer + { + InstallServer(SharpShellServerInfo.FromServer(), registrationScope, codeBase); + } + + /// + /// Installs a SharpShell COM server. /// - /// The server. - /// Type of the registration. + /// The managed server info. + /// Type of the registration. /// if set to true use code base registration (i.e full assembly path, not the GAC). - public static void InstallServer(ISharpShellServer server, RegistrationType registrationType, bool codeBase) + public static void InstallServer( + SharpShellServerInfo serverInfo, + RegistrationScope registrationScope, + bool codeBase) { - // Get the server registration information. - var serverRegistrationInformation = GetServerRegistrationInfo(server, registrationType); + // Get the server installation information. + var serverInstallationInfo = GetExtensionInstallationInfo(serverInfo.ClassId, registrationScope); + + // If it is installed, uninstall first. + if (serverInstallationInfo != null) + { + UninstallServer(serverInfo.ClassId, registrationScope); + } - // If it is registered, unregister first. - if (serverRegistrationInformation != null) - UninstallServer(server, registrationType); - // Open the classes. - using (var classesKey = OpenClassesKey(registrationType, RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var classesKey = + OpenInstalledClassesRoot(registrationScope, RegistryKeyPermissionCheck.ReadWriteSubTree)) { // Create the server key. - using (var serverKey = classesKey.CreateSubKey(server.ServerClsid.ToRegistryString())) + using (var serverKey = classesKey.CreateSubKey(serverInfo.ClassId.ToRegistryString())) { - if(serverKey == null) + if (serverKey == null) + { throw new InvalidOperationException("Cannot create server key."); + } // We always set the server key default value to the display name if we can. - if(!string.IsNullOrEmpty(server.DisplayName)) - serverKey.SetValue(null, server.DisplayName, RegistryValueKind.String); + if (serverInfo.IsDisplayNameDefined) + { + serverKey.SetValue(null, serverInfo.DisplayName, RegistryValueKind.String); + } - // Create the inproc key. - using (var inproc32Key = serverKey.CreateSubKey(KeyName_InProc32)) + // Create the process key. + using (var inProcess32Key = serverKey.CreateSubKey(RegistryInProcess32KeyName)) { // Check the key. - if(inproc32Key == null) + if (inProcess32Key == null) + { throw new InvalidOperationException("Cannot create InProc32 key."); + } // Set the .NET value. - inproc32Key.SetValue(null, KeyValue_NetFrameworkServer); - - // Create the values. - var assemblyVersion = server.GetType().Assembly.GetName().Version.ToString(); - var assemblyFullName = server.GetType().Assembly.FullName; - var className = server.GetType().FullName; - var runtimeVersion = server.GetType().Assembly.ImageRuntimeVersion; - var codeBaseValue = server.GetType().Assembly.CodeBase; - const string threadingModel = "Both"; - - // Register all details at server level. - inproc32Key.SetValue(KeyName_Assembly, assemblyFullName); - inproc32Key.SetValue(KeyName_Class, className); - inproc32Key.SetValue(KeyName_RuntimeVersion, runtimeVersion); - inproc32Key.SetValue(KeyName_ThreadingModel, threadingModel); + inProcess32Key.SetValue(null, RegistryNetFrameworkServerKeyValue); + + // Install all details at server level. + inProcess32Key.SetValue(RegistryClassValueName, serverInfo.ClassFullName); + inProcess32Key.SetValue(RegistryAssemblyValueName, serverInfo.AssemblyInfo.FullName); + inProcess32Key.SetValue(RegistryRuntimeVersionValueName, + serverInfo.AssemblyInfo.RuntimeVersion); + inProcess32Key.SetValue(RegistryThreadingModelValueName, "Both"); + if (codeBase) - inproc32Key.SetValue(KeyName_CodeBase, codeBaseValue); + { + inProcess32Key.SetValue(RegistryCodeBaseValueName, serverInfo.AssemblyInfo.CodeBase); + } // Create the version key. - using (var versionKey = inproc32Key.CreateSubKey(assemblyVersion)) + using (var versionKey = inProcess32Key.CreateSubKey(serverInfo.AssemblyInfo.Version)) { // Check the key. - if(versionKey == null) + if (versionKey == null) + { throw new InvalidOperationException("Cannot create assembly version key."); + } // Set the values. - versionKey.SetValue(KeyName_Assembly, assemblyFullName); - versionKey.SetValue(KeyName_Class, className); - versionKey.SetValue(KeyName_RuntimeVersion, runtimeVersion); + versionKey.SetValue(RegistryClassValueName, serverInfo.ClassFullName); + versionKey.SetValue(RegistryAssemblyValueName, serverInfo.AssemblyInfo.FullName); + versionKey.SetValue(RegistryRuntimeVersionValueName, + serverInfo.AssemblyInfo.RuntimeVersion); + if (codeBase) - versionKey.SetValue(KeyName_CodeBase, codeBaseValue); + { + versionKey.SetValue(RegistryCodeBaseValueName, serverInfo.AssemblyInfo.CodeBase); + } } } } @@ -97,624 +318,712 @@ public static void InstallServer(ISharpShellServer server, RegistrationType regi } /// - /// Uninstalls the server. + /// Uninstalls the server. /// - /// The server. - /// Type of the registration. + /// Type of the registration. /// True if the server WAS installed and has been uninstalled, false if the server was not found. - public static bool UninstallServer(ISharpShellServer server, RegistrationType registrationType) + public static bool UninstallServer(RegistrationScope registrationScope) where T : SharpShellServer { - return UninstallServer(server.ServerClsid, registrationType); + return UninstallServer(SharpShellServerInfo.FromServer(), registrationScope); } /// - /// Uninstalls the server. + /// Uninstalls the server. /// - /// The server's registration information. - /// Type of the registration. + /// The managed server info. + /// Type of the registration. /// True if the server WAS installed and has been uninstalled, false if the server was not found. - public static bool UninstallServer( - ShellExtensionRegistrationInfo registrationInfo, - RegistrationType registrationType) + public static bool UninstallServer(SharpShellServerInfo serverInfo, RegistrationScope registrationScope) { - return UninstallServer(registrationInfo.ServerCLSID, registrationType); + // Check passed type + return UninstallServer(serverInfo.ClassId, registrationScope); } /// - /// Uninstalls the server. + /// Uninstalls the server. /// - /// The server's class id. - /// Type of the registration. + /// The server's class id. + /// Type of the registration. /// True if the server WAS installed and has been uninstalled, false if the server was not found. - private static bool UninstallServer(Guid classId, RegistrationType registrationType) + public static bool UninstallServer(Guid serverClassId, RegistrationScope registrationScope) { // Open classes. - using (var classesKey = OpenClassesKey(registrationType, RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var classesKey = + OpenInstalledClassesRoot(registrationScope, RegistryKeyPermissionCheck.ReadWriteSubTree)) { - var subKeyTreeName = classId.ToRegistryString(); + var serverSubKeyPath = serverClassId.ToRegistryString(); + + // If the sub-key doesn't exist, we can return false - we're already uninstalled. + using (var serverSubKey = classesKey.OpenSubKey(serverSubKeyPath, false)) + { + if (serverSubKey == null) + { + return false; + } + } - // If the subkey doesn't exist, we can return false - we're already uninstalled. - if (classesKey.GetSubKeyNames().Any(skn => skn.Equals(subKeyTreeName, StringComparison.OrdinalIgnoreCase)) == false) - return false; + // Delete the sub-key tree. + classesKey.DeleteSubKeyTree(serverSubKeyPath); - // Delete the subkey tree. - classesKey.DeleteSubKeyTree(subKeyTreeName); return true; } } /// - /// Registers a SharpShell server. This will create the associations defined by the - /// server's COMServerAssociation attribute. + /// Opens the classes key. /// - /// The server. - /// Type of the registration. - public static void RegisterServer(ISharpShellServer server, RegistrationType registrationType) + /// Type of the registration. + /// The permissions. + /// + private static IRegistryKey OpenInstalledClassesRoot( + RegistrationScope registrationScope, + RegistryKeyPermissionCheck permissions) { - // Pass the server type to the SharpShellServer internal registration function and let it - // take over from there. - RegisterServerType(server.GetType(), registrationType); - - // Approve the extension. - ApproveExtension(server, registrationType); + // Open classes. + return OpenClassesRootKey(registrationScope)? + .OpenSubKey( + RegistryClassesKeyName, + permissions, + RegistryRights.QueryValues | RegistryRights.ReadPermissions | RegistryRights.EnumerateSubKeys + ) ?? + throw new InvalidOperationException("Cannot open classes."); } - /// - /// Actually performs registration. The ComRegisterFunction decorated method will call this function - /// internally with the flag appropriate for the operating system processor architecture. - /// However, this function can also be called manually if needed. - /// - /// The type of object to register, this must be a SharpShellServer derived class. - /// Type of the registration. - internal static void RegisterServerType(Type type, RegistrationType registrationType) - { - Logging.Log($"Preparing to register SharpShell Server {type.Name} as {registrationType}"); - - // Get the association data. - var associationAttributes = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) - .OfType().ToList(); - - // Get the server type and the registration name. - var serverType = ServerTypeAttribute.GetServerType(type); - var registrationName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(type); - - // Register the server associations, if there are any. - if (associationAttributes.Any()) - { - RegisterServerAssociations( - type.GUID, serverType, registrationName, associationAttributes, registrationType); - } - - // If a DisplayName attribute has been set, then set the display name of the COM server. - var displayName = DisplayNameAttribute.GetDisplayName(type); - if (!string.IsNullOrEmpty(displayName)) - SetServerDisplayName(type.GUID, displayName, registrationType); - - // Execute the custom register function, if there is one. - CustomRegisterFunctionAttribute.ExecuteIfExists(type, registrationType); - - // Notify the shell we've updated associations. - Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); - Logging.Log($"Registration of {type.Name} completed"); - } + #endregion + + #region Registration + + /// + /// The default icon key name. + /// + private const string RegistryDefaultIconKeyName = @"DefaultIcon"; + + /// + /// The default icon backup value name. + /// + private const string RegistryDefaultIconBackupValueName = @"SharpShell_Backup_DefaultIcon"; /// - /// Unregisters a SharpShell server. This will remove the associations defined by the - /// server's COMServerAssociation attribute. + /// Registers a SharpShell server. This will create the associations defined by the + /// server's COMServerAssociation attribute. /// - /// The server. - /// Type of the registration to undo. - public static void UnregisterServer(ISharpShellServer server, RegistrationType registrationType) + /// Type of the registration. + public static void RegisterAndApproveServer(RegistrationScope registrationScope) where T : SharpShellServer { - // Unapprove the extension. - UnapproveExtension(server.ServerClsid, registrationType); + RegisterAndApproveServer(SharpShellServerInfo.FromServer(), registrationScope); + } - // Pass the server type to the SharpShellServer internal unregistration function and let it + /// + /// Registers a SharpShell server. This will create the associations defined by the + /// server's COMServerAssociation attribute. + /// + /// The managed server info. + /// Type of the registration. + public static void RegisterAndApproveServer( + SharpShellServerInfo serverInfo, + RegistrationScope registrationScope) + { + // Pass the server type to the SharpShellServer internal registration function and let it // take over from there. - UnregisterServerType(server.GetType(), registrationType); + InternalRegisterServer(serverInfo, registrationScope); + + // Approve the extension. + ApproveExtension(serverInfo, registrationScope); } /// - /// Actually performs unregistration. The ComUnregisterFunction decorated method will call this function - /// internally with the flag appropriate for the operating system processor architecture. - /// However, this function can also be called manually if needed. + /// Actually performs registration. The ComRegisterFunction decorated method will call this function + /// internally with the flag appropriate for the operating system processor architecture. + /// However, this function can also be called manually if needed. /// - /// The type of object to unregister, this must be a SharpShellServer derived class. - /// Type of the registration to unregister. - internal static void UnregisterServerType(Type type, RegistrationType registrationType) + /// The managed server info. + /// Type of the registration. + private static void InternalRegisterServer(SharpShellServerInfo serverInfo, RegistrationScope registrationScope) { - Logging.Log($"Preparing to unregister SharpShell Server {type.Name} as {registrationType}"); + Logging.Log( + $"Preparing to register SharpShell Server {serverInfo.DisplayName} in scope {registrationScope}."); - // Get the association data. - var associationAttributes = type.GetCustomAttributes(typeof(COMServerAssociationAttribute), true) - .OfType().ToList(); - // Get the server type and the registration name. - var serverType = ServerTypeAttribute.GetServerType(type); - var serverName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(type); - - // Unregister the server associations, if there are any. - if (associationAttributes.Any()) + // Register the server associations + if (serverInfo.ShellExtensionType != ShellExtensionType.None) { - UnregisterServerAssociations(serverType, serverName, associationAttributes, registrationType); + // Get the association data. + var associationClassNames = + registrationScope == RegistrationScope.OS64Bit + ? serverInfo.AssociationClassNamesX64 + : serverInfo.AssociationClassNamesX32; + + if (associationClassNames?.Any() == true) + { + foreach (var associationClassName in associationClassNames) + { + RegisterShellExtensionAssociation( + serverInfo.ClassId, + serverInfo.ShellExtensionType, + serverInfo.RegistrationName, + associationClassName, + registrationScope + ); + } + } } - // Execute the custom unregister function, if there is one. - CustomUnregisterFunctionAttribute.ExecuteIfExists(type, registrationType); + // Execute the custom register function, if there is one. + try + { + serverInfo.InvokeCustomRegisterMethodIfExists(registrationScope); + } + catch (Exception e) + { + Logging.Error("Custom register function failed.", e); + } // Notify the shell we've updated associations. Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); - Logging.Log($"Unregistration of {type.Name} completed"); + Logging.Log($"Registration of {serverInfo.DisplayName} completed."); } - + /// - /// Loads all SharpShell servers from an assembly. + /// Un-registers a SharpShell server. This will remove the associations defined by the + /// server's COMServerAssociation attribute. /// - /// The path to the assembly. - /// A ISharpShellServer for each SharpShell server in the assembly. - public static IEnumerable EnumerateFromFile(string path) + /// Type of the registration to undo. + public static void UnregisterAndUnApproveServer(RegistrationScope registrationScope) + where T : SharpShellServer { - // Storage for the servers. - Lazy[] serverTypes; + UnregisterAndUnApproveServer(SharpShellServerInfo.FromServer(), registrationScope); + } - try - { - // Create an assembly catalog for the assembly and a container from it. - var catalog = new AssemblyCatalog(Path.GetFullPath(path)); - var container = new CompositionContainer(catalog); + /// + /// Un-registers a SharpShell server. This will remove the associations defined by the + /// server's COMServerAssociation attribute. + /// + /// The server type. + /// Type of the registration to undo. + public static void UnregisterAndUnApproveServer( + SharpShellServerInfo serverInfo, + RegistrationScope registrationScope) + { + // Un-approve the extension. + UnApproveExtension(serverInfo.ClassId, registrationScope); - // Get all exports of type ISharpShellServer. - serverTypes = container.GetExports().ToArray(); - } - catch (Exception exception) + // Pass the server type to the SharpShellServer internal un-registration function and let it + // take over from there. + InternalUnregisterServer(serverInfo, registrationScope); + } + + /// + /// Un-registers a SharpShell server. This will remove the associations defined by the + /// server's COMServerAssociation attribute. + /// + /// The server class id. + /// Type of the registration to undo. + public static void UnregisterAndUnApproveServer(Guid serverClassId, RegistrationScope registrationScope) + { + // Un-approve the extension. + UnApproveExtension(serverClassId, registrationScope); + + var associations = GetExtensionRegistrationInfo(serverClassId, registrationScope); + + if (associations == null) { - // It's almost certainly not a COM server. - Logging.Error("ServerManager: Failed to load SharpShell server", exception); + return; + } - throw new BadImageFormatException("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", exception); + foreach (var association in associations.Associations) + { + UnregisterShellExtensionAssociation( + association.ShellExtensionType, + association.RegistrationName, + association.AssociationClassName, + registrationScope + ); } + } + + /// + /// Actually performs un-registration. The ComUnregisterFunction decorated method will call this function + /// internally with the flag appropriate for the operating system processor architecture. + /// However, this function can also be called manually if needed. + /// + /// The server type. + /// Type of the registration to unregister. + private static void InternalUnregisterServer( + SharpShellServerInfo serverInfo, + RegistrationScope registrationScope) + { + Logging.Log( + $"Preparing to unregister SharpShell Server {serverInfo.DisplayName} in scope {registrationScope}"); - // Go through each servertype (creating the instance from the lazy). - foreach (var serverType in serverTypes) + // Unregister the server associations + if (serverInfo.ShellExtensionType != ShellExtensionType.None) { - ISharpShellServer server = null; + // Get the association data. + var associationClassNames = + registrationScope == RegistrationScope.OS64Bit + ? serverInfo.AssociationClassNamesX64 + : serverInfo.AssociationClassNamesX32; - try + if (associationClassNames?.Any() == true) { - server = serverType.Value; - } - catch (Exception exception) - { - Trace.TraceError($"An exception occurred loading a server: ${exception}"); + foreach (var associationClassName in associationClassNames) + { + UnregisterShellExtensionAssociation( + serverInfo.ShellExtensionType, + serverInfo.RegistrationName, + associationClassName, + registrationScope + ); + } } + } - if (server != null) - { - // Yield a server entry for the server type. - yield return server; - } + // Execute the custom unregister function, if there is one. + try + { + serverInfo.InvokeCustomUnRegisterMethodIfExists(registrationScope); } + catch (Exception e) + { + Logging.Error("Custom unregister function failed.", e); + } + + // Notify the shell we've updated associations. + Shell32.SHChangeNotify(Shell32.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero); + Logging.Log($"Un-registration of {serverInfo.DisplayName} completed."); } /// - /// Enumerates Shell extensions. + /// Enumerates shell extensions registered for a class. /// - /// Type of the registration. - /// The shell extension types. + /// The class name to return registered shell extensions + /// Type of the registration. /// - public static IEnumerable EnumerateExtensions(RegistrationType registrationType) + public static IEnumerable EnumerateRegisteredAssociations( + string associationClassName, + RegistrationScope registrationScope) { - var shellExtensionsGuidMap = new Dictionary(); + // Go through every shell extension type. - // Go through all classes. - using (var classes = OpenClassesRoot(registrationType)) + return EnumerateRegisteredAssociations( + associationClassName, + registrationScope, + Enum.GetValues(typeof(ShellExtensionType)).OfType() + ); + } + + /// + /// Enumerates shell extensions registered for a class. + /// + /// The class name to return registered shell extensions + /// Type of the registration. + /// Shell extension types to filter with. + /// + public static IEnumerable EnumerateRegisteredAssociations( + string associationClassName, + RegistrationScope registrationScope, + IEnumerable extensionTypes) + { + using (var classesKey = OpenClassesRootKey(registrationScope)) { - // Read each subkey. - foreach (var className in classes.GetSubKeyNames().Where(cn => !cn.StartsWith("{"))) + foreach (var extensionType in extensionTypes) { - // Go through every shell extension type. - foreach (ShellExtensionType shellExtensionType in Enum.GetValues(typeof (ShellExtensionType))) + // Get handler attribute + var handlerAttribute = HandlerSubKeyAttribute.GetHandlerSubKeyAttribute(extensionType); + + // Ignore invalid or null handlers + if (string.IsNullOrEmpty(handlerAttribute?.HandlerSubKey)) { - // Get the handler subkey. - var handlerSubkey = shellExtensionType.GetAttribute(); + continue; + } - if(handlerSubkey == null) - continue; + // Get the handler sub-key. + var handlerSubKeyRoot = $"{associationClassName}\\ShellEx\\{handlerAttribute.HandlerSubKey}"; - // Check for the subkey. - if (handlerSubkey.AllowMultipleEntries) + using (var handlerSubKey = classesKey.OpenSubKey( + handlerSubKeyRoot, + RegistryKeyPermissionCheck.ReadSubTree, + RegistryRights.ReadKey | RegistryRights.QueryValues + )) + { + // Skip empty handlers. + if (handlerSubKey == null) { - // Do we have the single subkey? - var handlerKeyPath = $"{className}\\ShellEx\\{handlerSubkey.HandlerSubkey}"; - using (var handlerSubKey = classes.OpenSubKey(handlerKeyPath, RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey | RegistryRights.QueryValues)) - { - // Skip empty handlers. - if (handlerSubKey == null) continue; + yield break; + } - // Read entries. - foreach (var entry in handlerSubKey.GetSubKeyNames()) + if (handlerAttribute.AllowMultipleEntries) // We should check for multiple sub-keys + { + // Read sub-keys. + foreach (var entrySubKeyName in handlerSubKey.GetSubKeyNames()) + { + using (var entrySubKey = handlerSubKey.OpenSubKey( + entrySubKeyName, + RegistryKeyPermissionCheck.ReadSubTree, + RegistryRights.QueryValues | RegistryRights.ReadKey + )) { - using (var entryKey = handlerSubKey.OpenSubKey(entry, RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.QueryValues | RegistryRights.ReadKey)) + var serverClassIdValue = entrySubKey.GetValue(null, string.Empty).ToString(); + + if (Guid.TryParse(serverClassIdValue, out var serverClassId) == false) { - var guidVal = entryKey.GetValue(null, string.Empty).ToString(); - - Guid guid; - if (Guid.TryParse(guidVal, out guid) == false) - continue; - Trace.WriteLine(string.Format("{0} has {3} {1} guid {2}", className, - shellExtensionType.ToString(), guid, entry)); - - // If we do not have a shell extension info for this extension, create one. - if (!shellExtensionsGuidMap.ContainsKey(guid)) - { - shellExtensionsGuidMap[guid] = new ShellExtensionRegistrationInfo - { - DisplayName = entry, - ShellExtensionType = shellExtensionType, - ServerCLSID = guid, - }; - } - - // Add the class association. - shellExtensionsGuidMap[guid].classRegistrations.Add(new ClassRegistration(className)); + continue; } + + Trace.WriteLine(string.Format( + "Class {0} has {1} with id {2} ({3})", + associationClassName, + extensionType.ToString(), + serverClassId, + entrySubKeyName + )); + + yield return new ShellExtensionRegisteredAssociationInfo( + extensionType, serverClassId, associationClassName, entrySubKeyName + ); } } } - else + else // We should check the root handler sub-key { - // Do we have the single subkey? - var handlerKeyPath = string.Format("{0}\\ShellEx\\{1}", className, handlerSubkey.HandlerSubkey); - using (var handlerSubKey = classes.OpenSubKey(handlerKeyPath, RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey | RegistryRights.QueryValues)) + var serverClassIdValue = handlerSubKey.GetValue(null, string.Empty).ToString(); + + if (Guid.TryParse(serverClassIdValue, out var serverClassId) == false) { - if (handlerSubKey != null) - { - var guidVal = handlerSubKey.GetValue(null, string.Empty).ToString(); + yield break; + } - Guid guid; - if (Guid.TryParse(guidVal, out guid) == false) - continue; - Trace.WriteLine(string.Format("{0} has {1} guid {2}", className, - shellExtensionType.ToString(), guid)); - - // If we do not have a shell extension info for this extension, create one. - if (!shellExtensionsGuidMap.ContainsKey(guid)) - { - shellExtensionsGuidMap[guid] = new ShellExtensionRegistrationInfo - { - ShellExtensionType = shellExtensionType, - ServerCLSID = guid, - }; - } + Trace.WriteLine(string.Format( + "Class {0} has {1} with id {2}", + associationClassName, + extensionType.ToString(), + serverClassId + )); - // Add the class association. - shellExtensionsGuidMap[guid].classRegistrations.Add(new ClassRegistration(className)); - } - } + yield return new ShellExtensionRegisteredAssociationInfo( + extensionType, serverClassId, associationClassName + ); } } } } + } + + /// + /// Enumerates Shell extensions. + /// + /// Type of the registration. + /// + public static IEnumerable EnumerateRegisteredExtensions( + RegistrationScope registrationScope) + { + // Go through all classes. + using (var classesKey = OpenClassesRootKey(registrationScope)) + { + return classesKey.GetSubKeyNames() + .Where(cn => !cn.StartsWith("{")) + .SelectMany(className => EnumerateRegisteredAssociations(className, registrationScope)) + .GroupBy(info => info.ServerClassId) + .Select(group => + { + var isApproved = IsExtensionApproved(group.Key, registrationScope); - return shellExtensionsGuidMap.Values; + return new ShellExtensionRegistrationInfo(group.Key, isApproved, group); + }); + } } /// - /// Gets the server registration info. + /// Get shell extension registration information. /// - /// The server. - /// Type of the registration. - /// - /// The ServerRegistrationInfo if the server is registered, otherwise false. - /// - public static ShellExtensionRegistrationInfo GetServerRegistrationInfo(ISharpShellServer server, RegistrationType registrationType) + /// Type of the registration. + /// + public static ShellExtensionRegistrationInfo GetExtensionRegistrationInfo( + RegistrationScope registrationScope) where T : SharpShellServer { - // Call the main function. - return GetServerRegistrationInfo(server.ServerClsid, registrationType); + return GetExtensionRegistrationInfo(SharpShellServerInfo.FromServer(), registrationScope); } /// - /// Gets the server registration info. + /// Get shell extension registration information. /// - /// The server CLSID. - /// Type of the registration. - /// - /// The ServerRegistrationInfo if the server is registered, otherwise false. - /// - public static ShellExtensionRegistrationInfo GetServerRegistrationInfo(Guid serverCLSID, RegistrationType registrationType) + /// The managed server info + /// Type of the registration. + /// + public static ShellExtensionRegistrationInfo GetExtensionRegistrationInfo( + SharpShellServerInfo serverInfo, + RegistrationScope registrationScope) { - // We can very quickly check to see if the server is approved. - bool serverApproved = IsExtensionApproved(serverCLSID, registrationType); + IEnumerable associations = + new ShellExtensionRegisteredAssociationInfo[0]; - // Open the classes. - using (var classesKey = OpenClassesKey(registrationType, RegistryKeyPermissionCheck.ReadSubTree)) + if (serverInfo.ShellExtensionType != ShellExtensionType.None) { - // Do we have a subkey for the server? - using (var serverClassKey = classesKey.OpenSubKey(serverCLSID.ToRegistryString())) + // Get the association data. + var associationClassNames = + registrationScope == RegistrationScope.OS64Bit + ? serverInfo.AssociationClassNamesX64 + : serverInfo.AssociationClassNamesX32; + + if (associationClassNames.Any()) { - // If there's no subkey, the server isn't registered. - if (serverClassKey == null) - return null; + associations = associationClassNames.SelectMany(className => + EnumerateRegisteredAssociations(className, registrationScope, + new[] {serverInfo.ShellExtensionType}) + .Where(info => info.ServerClassId == serverInfo.ClassId) + ); + } + } - // Do we have an InProc32 server? - using(var inproc32ServerKey = serverClassKey.OpenSubKey(KeyName_InProc32)) - { - // If we do, we can return the server info for an inproc 32 server. - if (inproc32ServerKey != null) - { - // Get the default value. - var defaultValue = GetValueOrEmpty(inproc32ServerKey, null); + var isApproved = IsExtensionApproved(serverInfo.ClassId, registrationScope); - // If we default value is null or empty, we've got a partially registered server. - if (string.IsNullOrEmpty(defaultValue)) - return new ShellExtensionRegistrationInfo(ServerRegistationType.PartiallyRegistered, serverCLSID); + return new ShellExtensionRegistrationInfo(serverInfo.ClassId, isApproved, associations); + } - // Get the threading model. - var threadingModel = GetValueOrEmpty(inproc32ServerKey, KeyName_ThreadingModel); + /// + /// Get shell extension registration information. + /// + /// The server class id + /// Type of the registration. + /// + public static ShellExtensionRegistrationInfo GetExtensionRegistrationInfo( + Guid serverClassId, + RegistrationScope registrationScope) + { + // Go through all classes. + using (var classesKey = OpenClassesRootKey(registrationScope)) + { + var associations = classesKey.GetSubKeyNames() + .Where(cn => !cn.StartsWith("{")) + .SelectMany(className => EnumerateRegisteredAssociations(className, registrationScope)) + .Where(info => info.ServerClassId == serverClassId); - // Is it a .NET server? - if (defaultValue == KeyValue_NetFrameworkServer) - { - // We've got a .NET server. We should have one subkey, with the assembly version. - var subkeyName = inproc32ServerKey.GetSubKeyNames().FirstOrDefault(); + var isApproved = IsExtensionApproved(serverClassId, registrationScope); - // If we have no subkey name, we've got a partially registered server. - if (subkeyName == null) - return new ShellExtensionRegistrationInfo(ServerRegistationType.PartiallyRegistered, serverCLSID); + return new ShellExtensionRegistrationInfo(serverClassId, isApproved, associations); + } + } - // Otherwise we now have the assembly version. - var assemblyVersion = subkeyName; + /// + /// Registers the server associations. + /// + /// The server's class id. + /// Type of the server. + /// Name of the server. + /// The association class name. + /// Type of the registration. + internal static void RegisterShellExtensionAssociation( + Guid serverClassId, + ShellExtensionType extensionType, + string registrationName, + string associationClassName, + RegistrationScope registrationScope) + { + using (var classesKey = OpenClassesRootKey(registrationScope)) + { + var attribute = HandlerSubKeyAttribute.GetHandlerSubKeyAttribute(extensionType); - // Open the assembly subkey. - using (var assemblySubkey = inproc32ServerKey.OpenSubKey(assemblyVersion)) - { - // If we can't open the key, we've got a problem. - if (assemblySubkey == null) - throw new InvalidOperationException("Can't open the details of the server."); + if (attribute == null) + { + throw new ArgumentException("This server type does not have a handler sub key.", + nameof(extensionType)); + } - // Read the managed server details. - var assembly = GetValueOrEmpty(assemblySubkey, KeyName_Assembly); - var @class = GetValueOrEmpty(assemblySubkey, KeyName_Class); - var runtimeVersion = GetValueOrEmpty(assemblySubkey, KeyName_RuntimeVersion); - var codeBase = assemblySubkey.GetValue(KeyName_CodeBase, null); - - // Return the server info. - return new ShellExtensionRegistrationInfo(ServerRegistationType.ManagedInProc32, serverCLSID) - { - ThreadingModel = threadingModel, - Assembly = assembly, - AssemblyVersion = assemblyVersion, - Class = @class, - RuntimeVersion = runtimeVersion, - CodeBase = codeBase != null ? codeBase.ToString() : null, - IsApproved = serverApproved - }; - } - } + var subKeyName = attribute.HandlerSubKey; - // We've got a native COM server. + if (string.IsNullOrEmpty(subKeyName)) + { + return; + } - // Return the server info. - return new ShellExtensionRegistrationInfo(ServerRegistationType.NativeInProc32, serverCLSID) - { - ThreadingModel = threadingModel, - ServerPath = defaultValue, - IsApproved = serverApproved - }; - } - } + var associationKeyPath = $"{associationClassName}\\ShellEx\\{subKeyName}"; - // If by this point we haven't return server info, we've got a partially registered server. - return new ShellExtensionRegistrationInfo(ServerRegistationType.PartiallyRegistered, serverCLSID); + if (attribute.AllowMultipleEntries) + { + associationKeyPath += $"\\{registrationName}"; } - } - } - /// - /// Sets the display name of the a COM server. - /// - /// The class identifier. - /// The display name. - /// Type of the registration. - /// - public static void SetServerDisplayName(Guid classId, string displayName, RegistrationType registrationType) - { - // Open the classes. - using (var classesKey = OpenClassesKey(registrationType, RegistryKeyPermissionCheck.ReadWriteSubTree)) - { // Create the server key. - using (var serverKey = classesKey.OpenSubKey(classId.ToRegistryString(), RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue)) + using (var serverKey = classesKey.CreateSubKey(associationKeyPath)) { - if (serverKey == null) - throw new InvalidOperationException($"Cannot open class id key {classId}"); + // Set the server class id. + serverKey?.SetValue(null, serverClassId.ToRegistryString()); + } - // Set the display name. - serverKey.SetValue(null, displayName, RegistryValueKind.String); + // If we're a shell icon handler, we must also set the default icon. + if (extensionType == ShellExtensionType.ShellIconHandler) + { + SetIconHandlerDefaultIcon(registrationScope, associationClassName); } } } /// - /// Registers the server associations. + /// Sets the icon handler default icon, enabling an icon handler extension. /// - /// The server CLSID. - /// Type of the server. - /// Name of the server. - /// The association attributes. - /// Type of the registration. - internal static void RegisterServerAssociations(Guid serverClsid, ServerType serverType, string serverName, - IEnumerable associationAttributes, RegistrationType registrationType) + /// Type of the registration. + /// Association class name. + private static void SetIconHandlerDefaultIcon(RegistrationScope registrationScope, string associationClassName) { - // Go through each association. - foreach (var associationAttribute in associationAttributes) + using (var classesKey = OpenClassesRootKey(registrationScope)) { - // Get the association classes. - var associationClassNames = CreateClassNamesForAssociations(associationAttribute.AssociationType, - associationAttribute.Associations, registrationType); - - // Open the classes key. - using (var classesKey = OpenClassesRoot(registrationType)) + // Open the class. + using (var classKey = classesKey.OpenSubKey(associationClassName)) { - // For each one, create the server type key. - foreach (var associationClassName in associationClassNames) + // Check we have the class. + if (classKey == null) + { + throw new InvalidOperationException("Cannot open class " + associationClassName); + } + + // Open the default icon. + using (var defaultIconKey = classKey.OpenSubKey( + RegistryDefaultIconKeyName, + RegistryKeyPermissionCheck.ReadWriteSubTree, + RegistryRights.ReadKey | RegistryRights.WriteKey + )) { - // Create the server key. - using (var serverKey = classesKey.CreateSubKey(GetKeyForServerType(associationClassName, serverType, serverName))) + // Check we have the key. + if (defaultIconKey == null) { - // Set the server class id. - if (serverKey != null) - serverKey.SetValue(null, serverClsid.ToRegistryString()); + // if not, we create the key. + var tempDefaultIconKey = classesKey.CreateSubKey( + associationClassName + @"\" + RegistryDefaultIconKeyName, + RegistryKeyPermissionCheck.ReadWriteSubTree + ); + tempDefaultIconKey.SetValue(null, "%1"); } + else + { + // Get the default icon. + var defaultIcon = defaultIconKey.GetValue(null, string.Empty).ToString(); - // If we're a shell icon handler, we must also set the defaulticon. - if (serverType == ServerType.ShellIconHandler) - SetIconHandlerDefaultIcon(classesKey, associationClassName); + // Save the default icon. + defaultIconKey.SetValue(RegistryDefaultIconBackupValueName, defaultIcon); + defaultIconKey.SetValue(null, "%1"); + } } } } } /// - /// Sets the icon handler default icon, enabling an icon handler extension. + /// Un-sets the icon handler default icon sharp shell value, restoring the backed up value. /// - /// The classes key. - /// Name of the class. - private static void SetIconHandlerDefaultIcon(IRegistryKey classesKey, string className) + /// Type of the registration. + /// Name of the class. + private static void UnsetIconHandlerDefaultIcon( + RegistrationScope registrationScope, + string associationClassName) { - // Open the class. - using (var classKey = classesKey.OpenSubKey(className)) + using (var classesKey = OpenClassesRootKey(registrationScope)) { - // Check we have the class. - if(classKey == null) - throw new InvalidOperationException("Cannot open class " + className); - - // Open the default icon. - using (var defaultIconKey = classKey.OpenSubKey(KeyName_DefaultIcon, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ReadKey | RegistryRights.WriteKey)) + // Open the class. + using (var classKey = classesKey.OpenSubKey(associationClassName)) { - // Check we have the key. - if (defaultIconKey == null) + // Check we have the class. + if (classKey == null) { - // if not, we create the key. - var tempDefaultIconKey = classesKey.CreateSubKey(className + @"\" + KeyName_DefaultIcon, RegistryKeyPermissionCheck.ReadWriteSubTree); - tempDefaultIconKey.SetValue(null, "%1"); - } - else + throw new InvalidOperationException("Cannot open class " + associationClassName); + } + + // Open the default icon. + using (var defaultIconKey = classKey.OpenSubKey( + RegistryDefaultIconKeyName, + RegistryKeyPermissionCheck.ReadWriteSubTree, + RegistryRights.ReadKey | RegistryRights.WriteKey + )) { - // Get the default icon. - var defaultIcon = defaultIconKey.GetValue(null, string.Empty).ToString(); + // Check we have the key. + if (defaultIconKey == null) + { + throw new InvalidOperationException( + "Cannot open default icon key for class " + associationClassName); + } + + // Get the backup default icon. + var backupDefaultIcon = defaultIconKey.GetValue(RegistryDefaultIconBackupValueName)?.ToString(); - // Save the default icon. - defaultIconKey.SetValue(ValueName_DefaultIconBackup, defaultIcon); - defaultIconKey.SetValue(null, "%1"); + if (backupDefaultIcon != null) + { + // Save the default icon, delete the backup. + defaultIconKey.SetValue(null, backupDefaultIcon); + defaultIconKey.DeleteValue(RegistryDefaultIconBackupValueName); + } } } } } /// - /// Unsets the icon handler default icon sharp shell value, restoring the backed up value. + /// Un-registers the server associations. /// - /// The classes key. - /// Name of the class. - private static void UnsetIconHandlerDefaultIcon(IRegistryKey classesKey, string className) + /// Type of the shell extension type. + /// Name of the server. + /// The association class name. + /// Type of the registration. + private static void UnregisterShellExtensionAssociation( + ShellExtensionType extensionType, + string registrationName, + string associationClassName, + RegistrationScope registrationScope) { - // Open the class. - using (var classKey = classesKey.OpenSubKey(className)) + // Open the classes key... + using (var classesKey = OpenClassesRootKey(registrationScope)) { - // Check we have the class. - if (classKey == null) - throw new InvalidOperationException("Cannot open class " + className); + var attribute = HandlerSubKeyAttribute.GetHandlerSubKeyAttribute(extensionType); - // Open the default icon. - using (var defaultIconKey = classKey.OpenSubKey(KeyName_DefaultIcon, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ReadKey | RegistryRights.WriteKey)) + if (attribute == null) { - // Check we have the key. - if (defaultIconKey == null) - throw new InvalidOperationException("Cannot open default icon key for class " + className); + throw new ArgumentException("This server type does not have a handler sub key.", + nameof(extensionType)); + } - // Do we have a backup default icon to restore? - if (defaultIconKey.GetValueNames().Any(vm => vm == ValueName_DefaultIconBackup)) - { - // Get the backup default icon. - var backupDefaultIcon = defaultIconKey.GetValue(ValueName_DefaultIconBackup, string.Empty).ToString(); + var subKeyName = attribute.HandlerSubKey; - // Save the default icon, delete the backup. - defaultIconKey.SetValue(null, backupDefaultIcon); - defaultIconKey.DeleteValue(ValueName_DefaultIconBackup); - } + if (string.IsNullOrEmpty(subKeyName)) + { + return; } - } - } - - /// - /// Unregisters the server associations. - /// - /// Type of the server. - /// Name of the server. - /// The association attributes. - /// Type of the registration. - private static void UnregisterServerAssociations(ServerType serverType, string serverName, - IEnumerable associationAttributes, RegistrationType registrationType) - { - // Go through each association attribute. - foreach (var associationAttribute in associationAttributes) - { - // Get the assocation classes. - var associationClassNames = CreateClassNamesForAssociations(associationAttribute.AssociationType, - associationAttribute.Associations, registrationType); - UnregisterServerAssociations(serverType, serverName, associationClassNames, registrationType); - } - } + // Get the key for the association. + var associationKeyPath = $"{associationClassName}\\ShellEx\\{subKeyName}"; - /// - /// Unregisters the server associations. - /// - /// Type of the server. - /// Name of the server. - /// The association class names. - /// Type of the registration. - private static void UnregisterServerAssociations( - ServerType serverType, - string serverName, - IEnumerable associationClassNames, - RegistrationType registrationType) - { - // Open the classes key... - using (var classesKey = OpenClassesRoot(registrationType)) - { - // ...then go through each association class. - foreach (var associationClassName in associationClassNames) + if (attribute.AllowMultipleEntries) { - // Get the key for the association. - var associationKeyPath = GetKeyForServerType(associationClassName, serverType, serverName); + associationKeyPath += $"\\{registrationName}"; + } + - // Delete it if it exists. - classesKey.DeleteSubKeyTree(associationKeyPath, false); + // Delete it if it exists. + classesKey.DeleteSubKeyTree(associationKeyPath, false); - // If we're a shell icon handler, we must also unset the defaulticon. - if (serverType == ServerType.ShellIconHandler) - UnsetIconHandlerDefaultIcon(classesKey, associationClassName); + // If we're a shell icon handler, we must also unset the default icon. + if (extensionType == ShellExtensionType.ShellIconHandler) + { + UnsetIconHandlerDefaultIcon(registrationScope, associationClassName); } } } /// - /// Creates the class names for associations. + /// Creates the class names for associations. /// /// Type of the association. /// The associations. - /// Type of the registration. + /// Type of the registration. /// - /// The class names for the associations. + /// The class names for the associations. /// - private static IEnumerable CreateClassNamesForAssociations(AssociationType associationType, - IEnumerable associations, RegistrationType registrationType) + internal static IEnumerable GetAssociationClassNames( + AssociationType associationType, + IEnumerable associations, + RegistrationScope registrationScope) { // Switch on the association type. switch (associationType) { - // We are handling the obsolete file extension type for backwards compatiblity. + // We are handling the obsolete file extension type for backwards compatibility. #pragma warning disable 618 case AssociationType.FileExtension: #pragma warning restore 618 @@ -725,9 +1034,11 @@ private static IEnumerable CreateClassNamesForAssociations(AssociationTy case AssociationType.ClassOfExtension: // Open the classes sub key and get or create each file extension classes. - using (var classesKey = OpenClassesRoot(registrationType)) + using (var classesKey = OpenClassesRootKey(registrationScope)) { - return associations.Select(extension => FileExtensionClass.Get(classesKey, extension, true)).ToArray(); + return associations + .Select(extension => FileExtensionClass.Get(classesKey, extension, true)) + .ToArray(); } case AssociationType.Class: @@ -738,250 +1049,108 @@ private static IEnumerable CreateClassNamesForAssociations(AssociationTy default: // If this is a predefined shell object, return the class for it. - var className = PredefinedShellObjectAttribute.GetClassName(associationType); - if (className != null) return new[] {className}; - - // It's not a type we know how to deal with, so bail. - throw new InvalidOperationException($@"Unable to determine associations for AssociationType '{associationType}'"); - } - } - - /// - /// Gets the type of the key for server. - /// - /// Name of the class. - /// Type of the server. - /// Name of the server. - /// - private static string GetKeyForServerType(string className, ServerType serverType, string serverName) - { - // Create the server type name. - switch (serverType) - { - case ServerType.ShellContextMenu: - - // Create the key name for a context menu. - return string.Format(@"{0}\ShellEx\ContextMenuHandlers\{1}", className, serverName); + var className = PredefinedShellObjectAttribute.GetPredefinedShellObjectAttribute(associationType) + ?.ClassName; - case ServerType.ShellPropertySheet: - - // Create the key name for a property sheet. - return string.Format(@"{0}\ShellEx\PropertySheetHandlers\{1}", className, serverName); - - case ServerType.ShellIconHandler: - - // Create the key name for an icon handler. This has no server name, - // as there cannot be multiple icon handlers. - return string.Format(@"{0}\ShellEx\IconHandler", className); - - case ServerType.ShellInfoTipHandler: - - // Create the key name for an info tip handler. This has no server name, - // as there cannot be multiple info tip handlers. - return string.Format(@"{0}\ShellEx\{{00021500-0000-0000-C000-000000000046}}", className); - - case ServerType.ShellDropHandler: - - // Create the key name for a drop handler. This has no server name, - // as there cannot be multiple drop handlers. - return string.Format(@"{0}\ShellEx\DropHandler", className); - - case ServerType.ShellPreviewHander: - - // Create the key name for a preview handler. This has no server name, - // as there cannot be multiple preview handlers. - return string.Format(@"{0}\ShellEx\{{8895b1c6-b41f-4c1c-a562-0d564250836f}}", className); - - case ServerType.ShellDataHandler: - - // Create the key name for a data handler. This has no server name, - // as there cannot be multiple data handlers. - return string.Format(@"{0}\ShellEx\DataHandler", className); - - case ServerType.ShellThumbnailHandler: - - // Create the key name for a thumbnail handler. This has no server name, - // as there cannot be multiple data handlers. - return string.Format(@"{0}\ShellEx\{{e357fccd-a995-4576-b01f-234630154e96}}", className); - - case ServerType.ShellNamespaceExtension: + if (className != null) + { + return new[] {className}; + } - // We don't have a key for shell namespace extensions. - return null; - - default: - throw new ArgumentOutOfRangeException(nameof(serverType)); + // It's not a type we know how to deal with, so bail. + throw new InvalidOperationException( + $@"Unable to determine associations for AssociationType '{associationType}'"); } } /// - /// Opens the classes key. + /// Approves an extension. /// - /// Type of the registration. - /// The permissions. - /// - private static IRegistryKey OpenClassesKey(RegistrationType registrationType, RegistryKeyPermissionCheck permissions) - { - // Get the classes base key. - var classesBaseKey = OpenClassesRoot(registrationType); - - // Open classes. - var classesKey = classesBaseKey.OpenSubKey(KeyName_Classes, permissions, RegistryRights.QueryValues | RegistryRights.ReadPermissions | RegistryRights.EnumerateSubKeys); - if (classesKey == null) - throw new InvalidOperationException("Cannot open classes."); - - return classesKey; - } - - /// - /// Opens the classes root. - /// - /// Type of the registration. - /// The classes root key. - private static IRegistryKey OpenClassesRoot(RegistrationType registrationType) - { - // Get the registry. - var registry = ServiceRegistry.ServiceRegistry.GetService(); - - // Get the classes base key. - var classesBaseKey = registrationType == RegistrationType.OS64Bit - ? registry.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64) : - registry.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry32); - - // Return the classes key. - return classesBaseKey; - } - - /// - /// Gets the value or empty. - /// - /// The key. - /// Name of the value. - /// - private static string GetValueOrEmpty(IRegistryKey key, string valueName) - { - object value = key.GetValue(valueName); - if (value == null) - return string.Empty; - return value.ToString(); - } - - /// - /// Approves an extension. - /// - /// The server. - /// Type of the registration. - /// Failed to open the Approved Extensions key. - private static void ApproveExtension(ISharpShellServer server, RegistrationType registrationType) + /// The server info. + /// Type of the registration. + /// Failed to open the Approved Extensions key. + private static void ApproveExtension(SharpShellServerInfo serverInfo, RegistrationScope registrationScope) { // Open the approved extensions key. - using(var approvedKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, - registrationType == RegistrationType.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32) - .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var approvedKey = RegistryKey.OpenBaseKey( + RegistryHive.LocalMachine, + registrationScope == RegistrationScope.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32 + ).OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", + RegistryKeyPermissionCheck.ReadWriteSubTree + )) { // If we can't open the key, we're going to have problems. - if(approvedKey == null) + if (approvedKey == null) + { throw new InvalidOperationException("Failed to open the Approved Extensions key."); + } // Create an entry for the server. - approvedKey.SetValue(server.ServerClsid.ToRegistryString(), server.DisplayName); + approvedKey.SetValue(serverInfo.ClassId.ToRegistryString(), serverInfo.DisplayName); } } /// - /// Determines whether an extension is approved. + /// Determines whether an extension is approved. /// - /// The server CLSID. - /// Type of the registration. + /// The server class id. + /// Type of the registration. /// - /// true if the extension is approved; otherwise, false. + /// true if the extension is approved; otherwise, false. /// - /// Failed to open the Approved Extensions key. - private static bool IsExtensionApproved(Guid serverClsid, RegistrationType registrationType) + /// Failed to open the Approved Extensions key. + private static bool IsExtensionApproved(Guid serverClassId, RegistrationScope registrationScope) { // Open the approved extensions key. - using (var approvedKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, - registrationType == RegistrationType.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32) - .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", RegistryKeyPermissionCheck.ReadSubTree)) + using (var approvedKey = RegistryKey.OpenBaseKey( + RegistryHive.LocalMachine, + registrationScope == RegistrationScope.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32 + ).OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", + RegistryKeyPermissionCheck.ReadSubTree + )) { // If we can't open the key, we're going to have problems. if (approvedKey == null) + { throw new InvalidOperationException("Failed to open the Approved Extensions key."); + } - return approvedKey.GetValueNames().Any(vn => vn.Equals(serverClsid.ToRegistryString(), StringComparison.OrdinalIgnoreCase)); + return approvedKey.GetValueNames().Any(valueName => + valueName.Equals(serverClassId.ToRegistryString(), StringComparison.OrdinalIgnoreCase) + ); } } /// - /// Unapproves an extension. + /// UnApproves an extension. /// /// The server's class id. - /// Type of the registration. - /// Failed to open the Approved Extensions key. - private static void UnapproveExtension(Guid serverClassId, RegistrationType registrationType) + /// Type of the registration. + /// Failed to open the Approved Extensions key. + private static void UnApproveExtension(Guid serverClassId, RegistrationScope registrationScope) { // Open the approved extensions key. - using (var approvedKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, - registrationType == RegistrationType.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32) - .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", RegistryKeyPermissionCheck.ReadWriteSubTree)) + using (var approvedKey = RegistryKey.OpenBaseKey( + RegistryHive.LocalMachine, + registrationScope == RegistrationScope.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32 + ).OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", + RegistryKeyPermissionCheck.ReadWriteSubTree + )) { // If we can't open the key, we're going to have problems. if (approvedKey == null) + { throw new InvalidOperationException("Failed to open the Approved Extensions key."); + } // Delete the value if it's there. approvedKey.DeleteValue(serverClassId.ToRegistryString(), false); } } - /// - /// The classes key name. - /// - private const string KeyName_Classes = @"CLSID"; - - /// - /// The InProc32 key name. - /// - private const string KeyName_InProc32 = @"InprocServer32"; - - /// - /// The value for the net framework servers. - /// - private const string KeyValue_NetFrameworkServer = @"mscoree.dll"; - - /// - /// The threading model key name. - /// - private const string KeyName_ThreadingModel = @"ThreadingModel"; - - /// - /// THe assembly key name. - /// - private const string KeyName_Assembly = @"Assembly"; - - /// - /// The class key name. - /// - private const string KeyName_Class = @"Class"; - - /// - /// The runtime version key name. - /// - private const string KeyName_RuntimeVersion = @"RuntimeVersion"; - - /// - /// The codebase keyname. - /// - private const string KeyName_CodeBase = @"CodeBase"; - - /// - /// The default icon keyname. - /// - private const string KeyName_DefaultIcon = @"DefaultIcon"; - - /// - /// The default icon backup value name. - /// - private const string ValueName_DefaultIconBackup = @"SharpShell_Backup_DefaultIcon"; + #endregion } -} +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ServerSandBox.cs b/SharpShell/SharpShell/ServerRegistration/ServerSandBox.cs new file mode 100644 index 00000000..123ecf05 --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/ServerSandBox.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace SharpShell.ServerRegistration +{ + internal class ServerSandBox : MarshalByRefObject + { + public static SharpShellServerInfo[] FromAssemblyFile(FileInfo assemblyFile) + { + // Get sandbox type + var sandboxType = typeof(ServerSandBox); + + if (string.IsNullOrEmpty(sandboxType.FullName)) + { + return null; + } + + // Creating a new temporary domain + var domain = AppDomain.CreateDomain("ServerTemporarySandboxedDomain"); + + try + { + // Adding custom resolve function to load local version of SharpShell and other dependencies + domain.AssemblyResolve += DomainOnAssemblyResolve; + + // Create and instance of this class inside the newly created domain + var sandbox = (ServerSandBox) domain.CreateInstanceAndUnwrap( + sandboxType.Assembly.FullName, + sandboxType.FullName + ); + + // Load assembly + var assemblyLocation = sandbox.InjectedLoadAssemblyFile(assemblyFile.FullName); + + // Get server information from inside of the newly created domain + return sandbox.InjectedGetServersInformation(assemblyLocation); + } + catch (Exception e) + { + throw new BadImageFormatException("File is not a valid .Net library or failed to load the library.", e); + } + finally + { + // Unload the newly created domain to free up resource and close loaded assembly files + AppDomain.Unload(domain); + } + } + + public static SharpShellServerInfo[] FromGAC(AssemblyName assemblyName) + { + // Get sandbox type + var sandboxType = typeof(ServerSandBox); + + if (string.IsNullOrEmpty(sandboxType.FullName)) + { + return null; + } + + // Creating a new temporary domain + var domain = AppDomain.CreateDomain("ServerTemporarySandboxedDomain"); + + try + { + // Adding custom resolve function to load local version of SharpShell and other dependencies + domain.AssemblyResolve += DomainOnAssemblyResolve; + + // Create and instance of this class inside the newly created domain + var sandbox = (ServerSandBox) domain.CreateInstanceAndUnwrap( + sandboxType.Assembly.FullName, + sandboxType.FullName + ); + + // Load assembly + var assemblyLocation = sandbox.InjectedLoadAssemblyGAC(assemblyName); + + // Get server information from inside of the newly created domain + return sandbox.InjectedGetServersInformation(assemblyLocation); + } + catch (Exception e) + { + throw new BadImageFormatException("File is not a valid .Net library or failed to load the library.", e); + } + finally + { + // Unload the newly created domain to free up resource and close loaded assembly files + AppDomain.Unload(domain); + } + } + + public static IEnumerable GetAttributesSafe( + MemberInfo memberInfo, + string attributeTypeName, + bool inherit) + { + foreach (var customAttribute in memberInfo.GetCustomAttributes(inherit)) + { + var customAttributeType = customAttribute?.GetType(); + + while (customAttributeType != null && customAttributeType.Name != nameof(Attribute)) + { + if (customAttributeType.Name == attributeTypeName) + { + yield return customAttribute; + + continue; + } + + customAttributeType = customAttributeType.BaseType; + } + } + } + + public static IEnumerable GetAttributesSafe(Type type, string attributeTypeName, bool inherit) + { + foreach (var customAttribute in type.GetCustomAttributes(inherit)) + { + var customAttributeType = customAttribute?.GetType(); + + while (customAttributeType != null && customAttributeType.Name != nameof(Attribute)) + { + if (customAttributeType.Name == attributeTypeName) + { + yield return customAttribute; + + break; + } + + customAttributeType = customAttributeType.BaseType; + } + } + } + + public static T GetByRefPropertySafe(object obj, string propertyName) where T : class + { + if (obj == null) + { + return null; + } + + try + { + var property = obj.GetType().GetProperty(propertyName); + + if (property != null) + { + return (T) property.GetValue(obj, null); + } + } + catch + { + // ignored + } + + return null; + } + + public static T? GetByValPropertySafe(object obj, string propertyName) where T : struct + { + if (obj == null) + { + return null; + } + + try + { + var property = obj.GetType().GetProperty(propertyName); + + if (property != null) + { + return (T) property.GetValue(obj, null); + } + } + catch + { + // ignored + } + + return null; + } + + public static string GetStringPropertySafe(object obj, string propertyName) + { + if (obj == null) + { + return null; + } + + try + { + var property = obj.GetType().GetProperty(propertyName); + + if (property != null) + { + return property.GetValue(obj, null)?.ToString(); + } + } + catch + { + // ignored + } + + return null; + } + + public static void LoadAndInvokeCustomMethodFromFile( + FileInfo assemblyFile, + Guid typeGuid, + string methodName, + RegistrationScope registrationScope) + { + // Get sandbox type + var sandboxType = typeof(ServerSandBox); + + if (string.IsNullOrEmpty(sandboxType.FullName)) + { + return; + } + + // Creating a new temporary domain + var domain = AppDomain.CreateDomain("ServerTemporarySandboxedDomain"); + + try + { + // Adding custom resolve function to load local version of SharpShell and other dependencies + domain.AssemblyResolve += DomainOnAssemblyResolve; + + // Create and instance of this class inside the newly created domain + var sandbox = (ServerSandBox) domain.CreateInstanceAndUnwrap( + sandboxType.Assembly.FullName, + sandboxType.FullName + ); + + // Load assembly + var assemblyLocation = sandbox.InjectedLoadAssemblyFile(assemblyFile.FullName); + + // Get server information from inside of the newly created domain + sandbox.InjectedInvokeServerCustomStaticMethod( + assemblyLocation, + typeGuid, + methodName, + registrationScope + ); + } + catch (Exception e) + { + throw new BadImageFormatException("File is not a valid .Net library or failed to load the library.", e); + } + finally + { + // Unload the newly created domain to free up resource and close loaded assembly files + AppDomain.Unload(domain); + } + } + + private static Assembly DomainOnAssemblyResolve(object sender, ResolveEventArgs args) + { + // Extract dll name and check if it is valid + var dllName = args.Name.Split(',').FirstOrDefault(); + + if (string.IsNullOrWhiteSpace(dllName)) + { + return null; + } + + // Create an array of search paths + var possibleDirectories = new[] + { + Path.GetDirectoryName(args.RequestingAssembly.Location), + Path.GetDirectoryName(AppDomain.CurrentDomain.RelativeSearchPath), + Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory) + }.Where(s => !string.IsNullOrEmpty(s)); + + // Create an array of valid file names + var possibleFile = new[] + { + dllName + ".dll", + Path.Combine(dllName, dllName + ".dll") + }; + + // Load dependency if found + foreach (var directory in possibleDirectories) + { + foreach (var file in possibleFile) + { + try + { + var fullAddress = Path.Combine(directory, file); + + if (File.Exists(fullAddress)) + { + return Assembly.LoadFrom(fullAddress); + } + } + catch + { + // ignored + } + } + } + + // Failed to load dependency + return null; + } + + private SharpShellServerInfo[] InjectedGetServersInformation(string assemblyPath) + { + // Load and get all server types + var serverTypes = InjectedGetServerTypes(assemblyPath); + + // Go through server types and extract server info + var servers = new List(); + + foreach (var serverType in serverTypes) + { + try + { + servers.Add(new SharpShellServerInfo(serverType, assemblyPath)); + } + catch + { + // ignored + } + } + + return servers.ToArray(); + } + + private Type[] InjectedGetServerTypes(string assemblyPath) + { + // Get loaded assembly + var assembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.Location == assemblyPath); + + if (assembly == null) + { + return new Type[0]; + } + + // Finding types that inherit from SharpShellServer + var serverTypes = new List(); + + foreach (var type in assembly.GetTypes()) + { + // Ignore invalid types + if (!type.IsClass || type.IsAbstract) + { + continue; + } + + var baseType = type.BaseType; + + while (baseType != null && baseType.Name != nameof(Object)) + { + if (baseType.Name == nameof(SharpShellServer)) + { + serverTypes.Add(type); + + break; + } + + baseType = baseType.BaseType; + } + } + + return serverTypes.ToArray(); + } + + private void InjectedInvokeServerCustomStaticMethod( + string assemblyPath, + Guid typeGuid, + string methodName, + RegistrationScope registrationScope) + { + // Load and get all server types + var serverTypes = InjectedGetServerTypes(assemblyPath); + + // Find server and throw if server type was absent + var serverType = serverTypes.FirstOrDefault(type => type.GUID == typeGuid); + + if (serverType == null) + { + throw new ArgumentException("Type not found.", nameof(typeGuid)); + } + + // Find method or throw if method was absent + var methodInfo = serverType.GetMethod( + methodName, + BindingFlags.Static | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.FlattenHierarchy + ); + + if (methodInfo == null) + { + throw new ArgumentException("Method not found.", nameof(methodInfo)); + } + + // Invoke method with server type and registration info + methodInfo.Invoke(null, new object[] {serverType, registrationScope}); + } + + private string InjectedLoadAssemblyFile(string assemblyPath) + { + // Actually load the assembly + return Assembly.LoadFile(assemblyPath).Location; + } + + private string InjectedLoadAssemblyGAC(AssemblyName assemblyName) + { + // Actually load the assembly + return Assembly.Load(assemblyName).Location; + } + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/SharpShellServerInfo.cs b/SharpShell/SharpShell/ServerRegistration/SharpShellServerInfo.cs new file mode 100644 index 00000000..7900df87 --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/SharpShellServerInfo.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using SharpShell.Attributes; + +namespace SharpShell.ServerRegistration +{ + [Serializable] + public sealed class SharpShellServerInfo + { + internal SharpShellServerInfo(Type type) + { + ClassFullName = type.FullName; + ClassId = GetServerClassId(type); + ClassName = type.Name; + + var displayNameAttribute = DisplayNameAttribute.GetDisplayNameAttribute(type); + IsDisplayNameDefined = !string.IsNullOrEmpty(displayNameAttribute?.DisplayName); + DisplayName = displayNameAttribute?.DisplayName ?? ClassName; + + var registrationNameAttribute = RegistrationNameAttribute.GetRegistrationNameAttribute(type); + IsRegistrationNameDefined = !string.IsNullOrEmpty(registrationNameAttribute?.RegistrationName); + RegistrationName = registrationNameAttribute?.RegistrationName ?? ClassName; + + var serverTypeAttribute = ServerTypeAttribute.GetServerTypeAttribute(type); + ServerType = serverTypeAttribute?.ServerType ?? ServerType.None; + ShellExtensionType = serverTypeAttribute?.ShellExtensionType ?? ShellExtensionType.None; + + var associationAttributes = COMServerAssociationAttribute.GetAssociationAttributes(type).ToArray(); + + if (associationAttributes.Any()) + { + AssociationClassNamesX32 = associationAttributes.SelectMany(attribute => + attribute.GetAssociationClassNames(RegistrationScope.OS32Bit) ?? new string[0]).ToArray(); + AssociationClassNamesX64 = associationAttributes.SelectMany(attribute => + attribute.GetAssociationClassNames(RegistrationScope.OS64Bit) ?? new string[0]).ToArray(); + } + + CustomRegistrationMethodName = CustomRegisterFunctionAttribute.GetMethodName(type); + CustomUnRegistrationMethodName = CustomUnregisterFunctionAttribute.GetMethodName(type); + + AssemblyInfo = new ManagedAssemblyInfo(type); + + try + { + // Gets the latest SharpServer assembly loaded into memory + var sharpShellAssembly = AppDomain.CurrentDomain.GetAssemblies().Reverse() + .FirstOrDefault(assembly => assembly.GetName().Name == nameof(SharpShell)); + + if (sharpShellAssembly != null) + { + SharpShellAssemblyInfo = new ManagedAssemblyInfo(sharpShellAssembly); + } + } + catch + { + // ignored + } + } + + internal SharpShellServerInfo(Type type, string assemblyPath) : this(type) + { + AssemblyInfo = new ManagedAssemblyInfo(type, assemblyPath); + IsAssemblyExternal = true; + } + + public ManagedAssemblyInfo AssemblyInfo { get; } + public string[] AssociationClassNamesX32 { get; } = new string[0]; + public string[] AssociationClassNamesX64 { get; } = new string[0]; + public string ClassFullName { get; } + public Guid ClassId { get; } + public string ClassName { get; } + public string CustomRegistrationMethodName { get; } + public string CustomUnRegistrationMethodName { get; } + public string DisplayName { get; } + public bool IsAssemblyExternal { get; } + public bool IsDisplayNameDefined { get; } + public bool IsRegistrationNameDefined { get; } + public string RegistrationName { get; } + public ServerType ServerType { get; } + + public ManagedAssemblyInfo SharpShellAssemblyInfo { get; } + public ShellExtensionType ShellExtensionType { get; } + + public static IEnumerable FromAssembly(Assembly assembly) + { + return assembly.GetTypes() + .Where(type => !type.IsAbstract && typeof(SharpShellServer).IsAssignableFrom(type)) + .Select(type => new SharpShellServerInfo(type)); + } + + public static IEnumerable FromAssembly(ManagedAssemblyInfo assembly) + { + // If file address is known load from file + if (!string.IsNullOrEmpty(assembly.AssemblyPath)) + { + return FromExternalAssemblyFile(assembly.AssemblyPath); + } + + // If otherwise load from GAC + return FromExternalAssembly(assembly.FullName); + } + + public static IEnumerable FromExternalAssembly(string assemblyName) + { + AssemblyName name; + + try + { + // Throw if failed to create assembly name + name = new AssemblyName(assemblyName); + } + catch (Exception e) + { + throw new ArgumentException("Invalid assembly name provided.", nameof(assemblyName), e); + } + + return ServerSandBox.FromGAC(name); + } + + public static IEnumerable FromExternalAssemblyFile(string assemblyPath) + { + // Normalize path + assemblyPath = Path.GetFullPath(assemblyPath); + + var assemblyFile = new FileInfo(assemblyPath); + + // Throw if assembly file not found + if (!assemblyFile.Exists) + { + throw new FileNotFoundException("Assembly file not found."); + } + + return ServerSandBox.FromAssemblyFile(assemblyFile); + } + + public static SharpShellServerInfo FromServer() where T : SharpShellServer + { + return new SharpShellServerInfo(typeof(T)); + } + + public static Guid GetServerClassId() where T : SharpShellServer + { + return GetServerClassId(typeof(T)); + } + + public static Guid GetServerClassId(Type type) + { + return type.GUID; + } + + public void InvokeCustomRegisterMethodIfExists(RegistrationScope registrationScope) + { + // Return if there is no custom register method + if (string.IsNullOrEmpty(CustomRegistrationMethodName)) + { + return; + } + + // Ask sandbox to invoke the method if this is an external assembly + if (IsAssemblyExternal) + { + // Throw if assembly file not found + if (string.IsNullOrWhiteSpace(AssemblyInfo?.AssemblyPath) || !File.Exists(AssemblyInfo.AssemblyPath)) + { + throw new FileNotFoundException("Assembly file not found."); + } + + ServerSandBox.LoadAndInvokeCustomMethodFromFile( + new FileInfo(AssemblyInfo.AssemblyPath), + ClassId, + CustomRegistrationMethodName, + registrationScope + ); + + return; + } + + // Otherwise invoke directly + InvokeCustomMethod(ClassId, CustomRegistrationMethodName, registrationScope); + } + + public void InvokeCustomUnRegisterMethodIfExists(RegistrationScope registrationScope) + { + // Return if there is no custom unregister method + if (string.IsNullOrEmpty(CustomUnRegistrationMethodName)) + { + return; + } + + // Ask sandbox to invoke the method if this is an external assembly + if (IsAssemblyExternal) + { + // Throw if assembly file not found + if (string.IsNullOrWhiteSpace(AssemblyInfo?.AssemblyPath) || !File.Exists(AssemblyInfo.AssemblyPath)) + { + throw new FileNotFoundException("Assembly file not found."); + } + + ServerSandBox.LoadAndInvokeCustomMethodFromFile( + new FileInfo(AssemblyInfo.AssemblyPath), + ClassId, + CustomUnRegistrationMethodName, + registrationScope + ); + + return; + } + + // Otherwise invoke directly + InvokeCustomMethod(ClassId, CustomUnRegistrationMethodName, registrationScope); + } + + private void InvokeCustomMethod(Guid typeGuid, string methodName, RegistrationScope registrationScope) + { + var serverType = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(assembly => + { + try + { + return assembly.GetTypes(); + } + catch + { + // ignored + } + + return new Type[0]; + }) + .Where(type => typeof(SharpShellServer).IsAssignableFrom(type) && !type.IsAbstract) + .FirstOrDefault(type => type.GUID == typeGuid); + + if (serverType == null) + { + throw new ArgumentException("Type not found.", nameof(typeGuid)); + } + + // Find method or throw if method was absent + var methodInfo = serverType.GetMethod( + methodName, + BindingFlags.Static | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.FlattenHierarchy + ); + + if (methodInfo == null) + { + throw new ArgumentException("Method not found.", nameof(methodInfo)); + } + + methodInfo.Invoke(null, new object[] {serverType, registrationScope}); + } + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegisteredAssociationInfo.cs b/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegisteredAssociationInfo.cs new file mode 100644 index 00000000..57428b81 --- /dev/null +++ b/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegisteredAssociationInfo.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SharpShell.Attributes; +using SharpShell.Extensions; + +namespace SharpShell.ServerRegistration +{ + /// + /// Represents association info + /// + public class ShellExtensionRegisteredAssociationInfo + { + private static readonly Dictionary SpecialRegistryClassNameMap = + Enum.GetValues(typeof(SpecialRegistryClass)) + .OfType() + .Select(enumValue => + new + { + SpecialClass = enumValue, + ClassName = enumValue.GetAttribute()?.SpecialClassKey + } + ) + .Where(pair => pair.ClassName != null) + .ToDictionary(pair => pair.ClassName, pair => pair.SpecialClass); + + + internal ShellExtensionRegisteredAssociationInfo( + ShellExtensionType extensionType, + Guid serverClassId, + string associationClassName) + { + ShellExtensionType = extensionType; + ServerClassId = serverClassId; + AssociationClassName = associationClassName; + RegistrationName = $"{associationClassName}'s {ShellExtensionType} ({serverClassId:B})"; + } + + internal ShellExtensionRegisteredAssociationInfo( + ShellExtensionType extensionType, + Guid serverClassId, + string associationClassName, + string registrationName) : this(extensionType, serverClassId, associationClassName) + { + RegistrationName = registrationName ?? RegistrationName; + } + + /// + /// Gets the target class name + /// + /// + /// The target class name. + /// + + public string AssociationClassName { get; } + + /// + /// Gets the display name. + /// + /// + /// The display name. + /// + public string RegistrationName { get; } + + /// + /// Gets the server class id. + /// + public Guid ServerClassId { get; } + + /// + /// Gets the type of the shell extension. + /// + /// + /// The type of the shell extension. + /// + public ShellExtensionType ShellExtensionType { get; } + + /// + /// Gets the target special class value + /// + /// + /// The target special class value + /// + public SpecialRegistryClass SpecialRegistryClass + { + get => !string.IsNullOrEmpty(AssociationClassName) && + SpecialRegistryClassNameMap.ContainsKey(AssociationClassName) + ? SpecialRegistryClassNameMap[AssociationClassName] + : SpecialRegistryClass.None; + } + } +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegistrationInfo.cs b/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegistrationInfo.cs index 965d6535..a2ab6656 100644 --- a/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegistrationInfo.cs +++ b/SharpShell/SharpShell/ServerRegistration/ShellExtensionRegistrationInfo.cs @@ -4,109 +4,37 @@ namespace SharpShell.ServerRegistration { /// - /// Represents registration info for a server. + /// Represents registration info for a server. /// public class ShellExtensionRegistrationInfo { - internal ShellExtensionRegistrationInfo() + public ShellExtensionRegistrationInfo( + Guid serverClassId, + bool isApproved, + IEnumerable associations) { - + ServerClassId = serverClassId; + IsApproved = isApproved; + Associations = associations; } /// - /// Initializes a new instance of the class. + /// Gets the server registered associations /// - /// Type of the server registation. - /// The server CLSID. - public ShellExtensionRegistrationInfo(ServerRegistationType serverRegistationType, Guid serverCLSID) - { - ServerRegistationType = serverRegistationType; - ServerCLSID = serverCLSID; - } - - /// - /// The class registrations. - /// - internal readonly List classRegistrations = new List(); - - /// - /// Gets the server CLSID. - /// - public Guid ServerCLSID { get; internal set; } + public IEnumerable Associations { get; } - /// - /// Gets the type of the shell extension. - /// - /// - /// The type of the shell extension. - /// - public ShellExtensionType ShellExtensionType { get; internal set; } /// - /// Gets the display name. + /// Gets a value indicating whether this extension is on the approved list. /// /// - /// The display name. + /// true if this instance is approved; otherwise, false. /// - public string DisplayName { get; internal set; } + public bool IsApproved { get; } /// - /// Gets the server path. + /// Gets the server class id. /// - public string ServerPath { get; internal set; } - - /// - /// Gets the threading model. - /// - public string ThreadingModel { get; internal set; } - - /// - /// Gets the assembly version. - /// - public string AssemblyVersion { get; internal set; } - - /// - /// Gets the assembly. - /// - public string Assembly { get; internal set; } - - /// - /// Gets the class. - /// - public string Class { get; internal set; } - - /// - /// Gets the runtime version. - /// - public string RuntimeVersion { get; internal set; } - - /// - /// Gets the codebase path. - /// - public string CodeBase { get; internal set; } - - /// - /// Gets a value indicating whether this extension is on the approved list. - /// - /// - /// true if this instance is approved; otherwise, false. - /// - public bool IsApproved { get; internal set; } - - /// - /// Gets the type of the server registation. - /// - /// - /// The type of the server registation. - /// - public ServerRegistationType ServerRegistationType { get; internal set; } - - /// - /// Gets the class registrations. - /// - /// - /// The class registrations. - /// - public IEnumerable ClassRegistrations { get { return classRegistrations; } } + public Guid ServerClassId { get; } } -} +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/ShellExtensionType.cs b/SharpShell/SharpShell/ServerRegistration/ShellExtensionType.cs index b98c3140..a523c6c2 100644 --- a/SharpShell/SharpShell/ServerRegistration/ShellExtensionType.cs +++ b/SharpShell/SharpShell/ServerRegistration/ShellExtensionType.cs @@ -1,129 +1,128 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; using SharpShell.Attributes; namespace SharpShell.ServerRegistration -{ - /// - /// The Shell Extension Type. - /// +{ + /// + /// The Shell Extension Type. + /// [Flags] public enum ShellExtensionType { - /// - /// None. - /// + /// + /// None. + /// None = 0, - /// - /// The shortcut menu handler type. - /// - [HandlerSubkey(true, @"ContextMenuHandlers")] - ShortcutMenuHandler = 1 << 0, - - /// - /// The copyhook handler type. - /// - [HandlerSubkey(true, @"CopyHookHandlers")] - CopyhookHandler = 1 << 1, - - /// - /// The drag and drop handler type. - /// - [HandlerSubkey(true, @"DragDropHandlers")] - DragAndDropHandler = 1 << 2, - - /// - /// The property sheet handler type. - /// - [HandlerSubkey(true, @"PropertySheetHandlers")] - PropertySheetHandler = 1 << 3, - - /// - /// The column provider handler type. - /// - [HandlerSubkey(true, @"ColumnHandlers")] - ColumnProviderHandler = 1 << 4, - - /// - /// The data handler type. - /// - [HandlerSubkey(false, @"DataHandler")] - DataHandler = 1 << 5, - - /// - /// The drop handler type. - /// - [HandlerSubkey(false, @"DropHandler")] - DropHandler = 1 << 6, - - /// - /// The icon handler type. - /// - [HandlerSubkey(false, @"IconHandler")] - IconHandler = 1 << 7, - - /// - /// The image handler type. - /// - [HandlerSubkey(false, @"{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}")] + /// + /// The shortcut menu handler type. + /// + [HandlerSubKey(@"ContextMenuHandlers", true)] + ShellContextMenu = 1 << 0, + + /// + /// The copy-hook handler type. + /// + [HandlerSubKey(@"CopyHookHandlers", true)] + ShellCopyHookHandler = 1 << 1, + + /// + /// The drag and drop handler type. + /// + [HandlerSubKey(@"DragDropHandlers", true)] + ShellDragDropHandlers = 1 << 2, + + /// + /// The property sheet handler type. + /// + [HandlerSubKey(@"PropertySheetHandlers", true)] + ShellPropertySheet = 1 << 3, + + /// + /// The column provider handler type. + /// + [HandlerSubKey(@"ColumnHandlers", true)] + ShellColumnProviderHandler = 1 << 4, + + /// + /// The data handler type. + /// + [HandlerSubKey(@"DataHandler", false)] ShellDataHandler = 1 << 5, + + /// + /// The drop handler type. + /// + [HandlerSubKey(@"DropHandler", false)] ShellDropHandler = 1 << 6, + + /// + /// The icon handler type. + /// + [HandlerSubKey(@"IconHandler", false)] ShellIconHandler = 1 << 7, + + /// + /// The image handler type. + /// + [HandlerSubKey(@"{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}", false)] ImageHandler = 1 << 8, - /// - /// The thumbnail image handler type. - /// - [HandlerSubkey(false, @"{E357FCCD-A995-4576-B01F-234630154E96}")] - ThumbnailImageHandler = 1 << 9, - - /// - /// The infotip handler type. - /// - [HandlerSubkey(false, @"{00021500-0000-0000-C000-000000000046}")] - InfotipHandler = 1 << 10, - - /// - /// The shell link ANSI type. - /// - [HandlerSubkey(false, @"{000214EE-0000-0000-C000-000000000046}")] - ShellLinkANSI = 1 << 11, - - /// - /// The shell link unicode type. - /// - [HandlerSubkey(false, @"{000214F9-0000-0000-C000-000000000046}")] - ShellLinkUNICODE = 1 << 12, - - /// - /// The structured storage type. - /// - [HandlerSubkey(false, @"{0000000B-0000-0000-C000-000000000046}")] - StructuredStorage = 1 << 13, - - /// - /// The metadata property store type. - /// - [HandlerSubkey(false, @"PropertyHandler")] - MetadataPropertyStore = 1 << 14, - - /// - /// The metadata property set storage type. - /// - [HandlerSubkey(false, @"PropertyHandler")] - MetadataPropertySetStorage = 1 << 15, - - /// - /// The pin to start menu type. - /// - [HandlerSubkey(false, @"{a2a9545d-a0c2-42b4-9708-a0b2badd77c8}")] - PinToStartMenu = 1 << 16, - - /// - /// The pin to taskbar type. - /// - [HandlerSubkey(false, @"{90AA3A4E-1CBA-4233-B8BB-535773D48449}")] - PinToTaskbar = 1 << 17 + /// + /// The thumbnail image handler type. + /// + [HandlerSubKey(@"{E357FCCD-A995-4576-B01F-234630154E96}", false)] + ShellThumbnailHandler = 1 << 9, + + /// + /// The info-tip handler type. + /// + [HandlerSubKey(@"{00021500-0000-0000-C000-000000000046}", false)] + ShellInfoTipHandler = 1 << 10, + + /// + /// The shell link ANSI type. + /// + [HandlerSubKey(@"{000214EE-0000-0000-C000-000000000046}", false)] + ShellLinkAnsi = 1 << 11, + + /// + /// The shell link unicode type. + /// + [HandlerSubKey(@"{000214F9-0000-0000-C000-000000000046}", false)] + ShellLinkUnicode = 1 << 12, + + /// + /// The structured storage type. + /// + [HandlerSubKey(@"{0000000B-0000-0000-C000-000000000046}", false)] + ShellStructuredStorage = 1 << 13, + + /// + /// The metadata property store type. + /// + [HandlerSubKey(@"PropertyHandler", false)] + ShellMetadataPropertyStore = 1 << 14, + + /// + /// The metadata property set storage type. + /// + [HandlerSubKey(@"PropertyHandler", false)] + ShellMetadataPropertySetStorage = 1 << 15, + + /// + /// The pin to start menu type. + /// + [HandlerSubKey(@"{a2a9545d-a0c2-42b4-9708-a0b2badd77c8}", false)] + ShellPinToStartMenu = 1 << 16, + + /// + /// The pin to task-bar type. + /// + [HandlerSubKey(@"{90AA3A4E-1CBA-4233-B8BB-535773D48449}", false)] + ShellPinToTaskBar = 1 << 17, + + /// + /// The pin to start menu type. + /// + [HandlerSubKey(@"{8895b1c6-b41f-4c1c-a562-0d564250836f}", false)] + ShellPreviewHandler = 1 << 18 } -} +} \ No newline at end of file diff --git a/SharpShell/SharpShell/ServerRegistration/SpecialRegistryClass.cs b/SharpShell/SharpShell/ServerRegistration/SpecialRegistryClass.cs index f62c4331..6a9e4b88 100644 --- a/SharpShell/SharpShell/ServerRegistration/SpecialRegistryClass.cs +++ b/SharpShell/SharpShell/ServerRegistration/SpecialRegistryClass.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; +using System.ComponentModel; using SharpShell.Attributes; namespace SharpShell.ServerRegistration diff --git a/SharpShell/SharpShell/ServerType.cs b/SharpShell/SharpShell/ServerType.cs index 5ed4c024..0d8fac0a 100644 --- a/SharpShell/SharpShell/ServerType.cs +++ b/SharpShell/SharpShell/ServerType.cs @@ -11,72 +11,72 @@ public enum ServerType /// No Server Type. /// [Description("Not a SharpShell Server")] - None, + None = 0, /// /// A Shell Context Menu. /// - [Description("Shell Context Menu")] - ShellContextMenu, + [Description(@"Shell Context Menu")] + ShellContextMenu = 1, /// /// A Shell Property Sheet. /// - [Description("Shell Property Sheet")] - ShellPropertySheet, + [Description(@"Shell Property Sheet")] + ShellPropertySheet = 2, /// /// A Shell Icon Handler. /// - [Description("Shell Icon Handler")] - ShellIconHandler, + [Description(@"Shell Icon Handler")] + ShellIconHandler = 3, /// /// A Shell Info Tip Handler. /// - [Description("Shell Info Tip Handler")] - ShellInfoTipHandler, + [Description(@"Shell Info Tip Handler")] + ShellInfoTipHandler = 4, /// /// A Shell Drop Handler /// - [Description("Shell Drop Handler")] - ShellDropHandler, + [Description(@"Shell Drop Handler")] + ShellDropHandler = 5, /// /// A Shell Icon Overlay Handler. /// - [Description("Shell Icon Overlay Handler")] - ShellIconOverlayHandler, + [Description(@"Shell Icon Overlay Handler")] + ShellIconOverlayHandler = 6, /// /// A Shell Preview Handler /// - [Description("Shell Preview Handler")] - ShellPreviewHander, + [Description(@"Shell Preview Handler")] + ShellPreviewHandler = 7, /// /// A Shell Data Handler /// - [Description("Shell Data Handler")] - ShellDataHandler, + [Description(@"Shell Data Handler")] + ShellDataHandler = 8, /// /// A Shell Thumbnail Handler /// - [Description("Shell Thumbnail Handler")] - ShellThumbnailHandler, + [Description(@"Shell Thumbnail Handler")] + ShellThumbnailHandler = 9, /// /// A Shell Namespace Extension /// - [Description("Shell Namespace Extension")] - ShellNamespaceExtension, + [Description(@"Shell Namespace Extension")] + ShellNamespaceExtension = 10, /// /// A Shell Desk Band Extension /// - [Description("Shell Desk Band Extension")] - ShellDeskBand + [Description(@"Shell Desk Band Extension")] + ShellDeskBand = 11 } } \ No newline at end of file diff --git a/SharpShell/SharpShell/SharpDeskBand/SharpDeskBand.cs b/SharpShell/SharpShell/SharpDeskBand/SharpDeskBand.cs index 9b73f304..53357aae 100644 --- a/SharpShell/SharpShell/SharpDeskBand/SharpDeskBand.cs +++ b/SharpShell/SharpShell/SharpDeskBand/SharpDeskBand.cs @@ -135,7 +135,7 @@ int IPersistStream.GetClassID(out Guid pClassID) Log("IPersistStream.GetClassID called."); // Return the server class id. - pClassID = ServerClsid; + pClassID = ServerClassId; // Return success. return WinError.S_OK; @@ -189,7 +189,7 @@ int IPersist.GetClassID(out Guid pClassID) // The class ID is just a unique identifier for the class, meaning // that we can use the class GUID as it will be provided for // all SharpShell servers. - pClassID = ServerClsid; + pClassID = ServerClassId; // Return success. return WinError.S_OK; @@ -478,7 +478,7 @@ int IInputObject.TranslateAcceleratorIO(ref MSG msg) /// The custom registration function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. /// /// Unable to register a SharpNamespaceExtension as it is missing it's junction point definition. /// or @@ -491,9 +491,9 @@ int IInputObject.TranslateAcceleratorIO(ref MSG msg) /// An exception occured creating the ShellFolder key. /// [CustomRegisterFunction] - internal static void CustomRegisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomRegisterFunction(Type serverType, RegistrationScope registrationScope) { - Logging.Log($"DeskBand: Preparing to register {registrationType} COM categories for type {serverType.Name}"); + Logging.Log($"DeskBand: Preparing to register {registrationScope} COM categories for type {serverType.Name}"); // Use the category manager to register this server as a Desk Band. try @@ -502,7 +502,7 @@ internal static void CustomRegisterFunction(Type serverType, RegistrationType re } catch (Exception exception) { - Logging.Error($"An exception occurred to registering {registrationType} COM categories for type {serverType.Name}", exception); + Logging.Error($"An exception occurred to registering {registrationScope} COM categories for type {serverType.Name}", exception); } } @@ -510,11 +510,11 @@ internal static void CustomRegisterFunction(Type serverType, RegistrationType re /// Customs the unregister function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. [CustomUnregisterFunction] - internal static void CustomUnregisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomUnregisterFunction(Type serverType, RegistrationScope registrationScope) { - Logging.Log($"DeskBand: Preparing to unregister {registrationType} COM categories for type {serverType.Name}"); + Logging.Log($"DeskBand: Preparing to unregister {registrationScope} COM categories for type {serverType.Name}"); // Use the category manager to register this server as a Desk Band. try @@ -523,7 +523,7 @@ internal static void CustomUnregisterFunction(Type serverType, RegistrationType } catch (Exception exception) { - Logging.Error($"An exception occurred to registering {registrationType} COM categories for type {serverType.Name}", exception); + Logging.Error($"An exception occurred to registering {registrationScope} COM categories for type {serverType.Name}", exception); } } diff --git a/SharpShell/SharpShell/SharpIconOverlayHandler/SharpIconOverlayHandler.cs b/SharpShell/SharpShell/SharpIconOverlayHandler/SharpIconOverlayHandler.cs index 0db82b57..6df1ea21 100644 --- a/SharpShell/SharpShell/SharpIconOverlayHandler/SharpIconOverlayHandler.cs +++ b/SharpShell/SharpShell/SharpIconOverlayHandler/SharpIconOverlayHandler.cs @@ -212,15 +212,15 @@ private string GetIconFilePath() /// The custom registration function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. [CustomRegisterFunction] - internal static void CustomRegisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomRegisterFunction(Type serverType, RegistrationScope registrationScope) { - var keyName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(serverType); - Logging.Log($"IconOverlayHandler: Preparing to register {registrationType} Icon Overlay Handler for type '{serverType.Name}' with key name '{keyName}'"); + var keyName = RegistrationNameAttribute.GetRegistrationNameAttribute(serverType); + Logging.Log($"IconOverlayHandler: Preparing to register {registrationScope} Icon Overlay Handler for type '{serverType.Name}' with key name '{keyName}'"); // Open the local machine. - using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit + using (var localMachineBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { @@ -241,7 +241,7 @@ internal static void CustomRegisterFunction(Type serverType, RegistrationType re "being registered, it will not be used by Windows Explorer."); // Create the overlay key. - using (var overlayKey = overlayIdentifiers.CreateSubKey(keyName)) + using (var overlayKey = overlayIdentifiers.CreateSubKey(keyName.RegistrationName)) { // If we don't have the overlay key, we've got a problem. if(overlayKey == null) @@ -258,15 +258,15 @@ internal static void CustomRegisterFunction(Type serverType, RegistrationType re /// Customs the unregister function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. [CustomUnregisterFunction] - internal static void CustomUnregisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomUnregisterFunction(Type serverType, RegistrationScope registrationScope) { - var keyName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(serverType); - Logging.Log($"IconOverlayHandler: Preparing to unregister {registrationType} Icon Overlay Handler for type '{serverType.Name}' with key name '{keyName}'"); + var keyName = RegistrationNameAttribute.GetRegistrationNameAttribute(serverType); + Logging.Log($"IconOverlayHandler: Preparing to unregister {registrationScope} Icon Overlay Handler for type '{serverType.Name}' with key name '{keyName}'"); // Open the local machine. - using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit + using (var localMachineBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { @@ -280,8 +280,8 @@ internal static void CustomUnregisterFunction(Type serverType, RegistrationType throw new InvalidOperationException("Cannot open the ShellIconOverlayIdentifiers key."); // Delete the overlay key. - if (overlayIdentifiers.GetSubKeyNames().Any(skn => skn == keyName)) - overlayIdentifiers.DeleteSubKey(keyName); + if (overlayIdentifiers.GetSubKeyNames().Any(skn => skn == keyName.RegistrationName)) + overlayIdentifiers.DeleteSubKey(keyName.RegistrationName); } } } diff --git a/SharpShell/SharpShell/SharpNamespaceExtension/SharpNamespaceExtension.cs b/SharpShell/SharpShell/SharpNamespaceExtension/SharpNamespaceExtension.cs index 4a234a17..96f55466 100644 --- a/SharpShell/SharpShell/SharpNamespaceExtension/SharpNamespaceExtension.cs +++ b/SharpShell/SharpShell/SharpNamespaceExtension/SharpNamespaceExtension.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.EnterpriseServices; using System.Linq; using System.Reflection.Emit; using System.Runtime.InteropServices; @@ -397,7 +396,7 @@ int IPersistIDList.GetIDList([Out] out IntPtr pidl) /// The custom registration function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. /// /// Unable to register a SharpNamespaceExtension as it is missing it's junction point definition. /// or @@ -410,7 +409,7 @@ int IPersistIDList.GetIDList([Out] out IntPtr pidl) /// An exception occured creating the ShellFolder key. /// [CustomRegisterFunction] - internal static void CustomRegisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomRegisterFunction(Type serverType, RegistrationScope registrationScope) { // Get the junction point. var junctionPoint = NamespaceExtensionJunctionPointAttribute.GetJunctionPoint(serverType); @@ -437,7 +436,7 @@ Virtual Folder Name var hive = junctionPoint.Availablity == NamespaceExtensionAvailability.CurrentUser ? RegistryHive.CurrentUser : RegistryHive.LocalMachine; - var view = registrationType == RegistrationType.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32; + var view = registrationScope == RegistrationScope.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32; // Now open the base key. using (var baseKey = RegistryKey.OpenBaseKey(hive, view)) @@ -468,7 +467,7 @@ Virtual Folder Name // adapting it here. // Open the classes root. - using (var classesBaseKey = registrationType == RegistrationType.OS64Bit + using (var classesBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry32)) { @@ -524,9 +523,9 @@ Virtual Folder Name /// Customs the unregister function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. [CustomUnregisterFunction] - internal static void CustomUnregisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomUnregisterFunction(Type serverType, RegistrationScope registrationScope) { // Get the junction point. var junctionPoint = NamespaceExtensionJunctionPointAttribute.GetJunctionPoint(serverType); @@ -540,7 +539,7 @@ internal static void CustomUnregisterFunction(Type serverType, RegistrationType var hive = junctionPoint.Availablity == NamespaceExtensionAvailability.CurrentUser ? RegistryHive.CurrentUser : RegistryHive.LocalMachine; - var view = registrationType == RegistrationType.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32; + var view = registrationScope == RegistrationScope.OS64Bit ? RegistryView.Registry64 : RegistryView.Registry32; // Now open the base key. using (var baseKey = RegistryKey.OpenBaseKey(hive, view)) diff --git a/SharpShell/SharpShell/SharpNamespaceExtension/ShellFolderImpl.cs b/SharpShell/SharpShell/SharpNamespaceExtension/ShellFolderImpl.cs index 2e0fdc0a..d6ab2b97 100644 --- a/SharpShell/SharpShell/SharpNamespaceExtension/ShellFolderImpl.cs +++ b/SharpShell/SharpShell/SharpNamespaceExtension/ShellFolderImpl.cs @@ -763,7 +763,7 @@ int IShellFolder2.MapColumnToSCID(uint iColumn, out PROPERTYKEY pscid) int IPersist.GetClassID(out Guid pClassID) { // Set the class ID to the server id. - pClassID = namespaceExtension.ServerClsid; + pClassID = namespaceExtension.ServerClassId; return WinError.S_OK; } int IPersistFolder.GetClassID(out Guid pClassID) { return ((IPersist)this).GetClassID(out pClassID); } diff --git a/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerHost.cs b/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerHost.cs index 69bc53db..416c9b9f 100644 --- a/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerHost.cs +++ b/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerHost.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; diff --git a/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerRegistrar.cs b/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerRegistrar.cs index 9a4b0b7f..032fa58d 100644 --- a/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerRegistrar.cs +++ b/SharpShell/SharpShell/SharpPreviewHandler/PreviewHandlerRegistrar.cs @@ -17,7 +17,7 @@ internal static class PreviewHandlerRegistrar { private const string PreviewHandlersKey = @"Software\Microsoft\Windows\CurrentVersion\PreviewHandlers"; - public static void Register(Type serverType, RegistrationType registrationType) + public static void Register(Type serverType, RegistrationScope registrationScope) { // Get the preview handler attribute. If it is missing, throw a registration exception. var previewHandlerAttribute = PreviewHandlerAttribute.GetPreviewHandlerAttribute(serverType); @@ -27,10 +27,10 @@ public static void Register(Type serverType, RegistrationType registrationType) } // We will use the display name a few times. - var displayName = DisplayNameAttribute.GetDisplayNameOrTypeName(serverType); + var displayName = DisplayNameAttribute.GetDisplayNameAttribute(serverType)?.DisplayName ?? serverType.Name; // Open the local machine. - using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit + using (var localMachineBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, @@ -52,7 +52,7 @@ public static void Register(Type serverType, RegistrationType registrationType) } // Open the classes root. - using (var classesBaseKey = registrationType == RegistrationType.OS64Bit + using (var classesBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry32)) { @@ -109,11 +109,11 @@ public static void Register(Type serverType, RegistrationType registrationType) /// Unregisters the SharpShell Preview Handler with the given type. /// /// Type of the server. - /// Type of the registration. - public static void Unregister(Type serverType, RegistrationType registrationType) + /// Type of the registration. + public static void Unregister(Type serverType, RegistrationScope registrationScope) { // Open the local machine. - using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit + using (var localMachineBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { diff --git a/SharpShell/SharpShell/SharpPreviewHandler/SharpPreviewHandler.cs b/SharpShell/SharpShell/SharpPreviewHandler/SharpPreviewHandler.cs index d0da5d34..729e04fb 100644 --- a/SharpShell/SharpShell/SharpPreviewHandler/SharpPreviewHandler.cs +++ b/SharpShell/SharpShell/SharpPreviewHandler/SharpPreviewHandler.cs @@ -25,7 +25,7 @@ namespace SharpShell.SharpPreviewHandler /// The SharpPreviewHandler is the base class for Shell Preview Handlers /// implemented with SharpShell. /// - [ServerType(ServerType.ShellPreviewHander)] + [ServerType(ServerType.ShellPreviewHandler)] public abstract class SharpPreviewHandler : SharpShellServer, IInitializeWithFile, /*IInitializeWithStream,*/ @@ -540,24 +540,24 @@ int IPreviewHandlerVisuals.SetTextColor(COLORREF color) /// The custom registration function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. [CustomRegisterFunction] - internal static void CustomRegisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomRegisterFunction(Type serverType, RegistrationScope registrationScope) { // Register preview handlers via the registrar. - PreviewHandlerRegistrar.Register(serverType, registrationType); + PreviewHandlerRegistrar.Register(serverType, registrationScope); } /// /// Customs the unregister function. /// /// Type of the server. - /// Type of the registration. + /// Type of the registration. [CustomUnregisterFunction] - internal static void CustomUnregisterFunction(Type serverType, RegistrationType registrationType) + internal static void CustomUnregisterFunction(Type serverType, RegistrationScope registrationScope) { // Open the local machine. - using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit + using (var localMachineBaseKey = registrationScope == RegistrationScope.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { diff --git a/SharpShell/SharpShell/SharpShell.csproj b/SharpShell/SharpShell/SharpShell.csproj index 36be2b8a..8454ac40 100644 --- a/SharpShell/SharpShell/SharpShell.csproj +++ b/SharpShell/SharpShell/SharpShell.csproj @@ -58,13 +58,8 @@ - - - - - @@ -208,6 +203,11 @@ + + + + + @@ -302,9 +302,9 @@ - - - + + + diff --git a/SharpShell/SharpShell/SharpShellServer.cs b/SharpShell/SharpShell/SharpShellServer.cs index 63a282db..aab50fb4 100644 --- a/SharpShell/SharpShell/SharpShellServer.cs +++ b/SharpShell/SharpShell/SharpShellServer.cs @@ -34,9 +34,9 @@ internal static void Register(Type type) // Register the type, use the operating system architecture to determine // what registration type to perform. - ServerRegistrationManager.RegisterServerType( - type, - Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit + ServerRegistrationManager.RegisterAndApproveServer( + new SharpShellServerInfo(type), + Environment.Is64BitOperatingSystem ? RegistrationScope.OS64Bit : RegistrationScope.OS32Bit ); } @@ -49,13 +49,13 @@ internal static void Register(Type type) [ComUnregisterFunction] internal static void Unregister(Type type) { - Logging.Log("Unregistering server for type " + type.Name); + Logging.Log("Un-registering server for type " + type.Name); // Unregister the type, use the operating system architecture to determine // what registration type to unregister. - ServerRegistrationManager.UnregisterServerType( - type, - Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit + ServerRegistrationManager.UnregisterAndUnApproveServer( + new SharpShellServerInfo(type), + Environment.Is64BitOperatingSystem ? RegistrationScope.OS64Bit : RegistrationScope.OS32Bit ); } @@ -88,7 +88,10 @@ protected virtual void LogError(string message, Exception exception = null) /// /// The name of the server. /// - public string DisplayName => DisplayNameAttribute.GetDisplayNameOrTypeName(GetType()); + public string DisplayName + { + get => DisplayNameAttribute.GetDisplayNameAttribute(GetType())?.DisplayName ?? GetType().Name; + } /// /// Gets the type of the server. @@ -96,11 +99,17 @@ protected virtual void LogError(string message, Exception exception = null) /// /// The type of the server. /// - public ServerType ServerType => ServerTypeAttribute.GetServerType(GetType()); + public ServerType ServerType + { + get => ServerTypeAttribute.GetServerTypeAttribute(GetType())?.ServerType ?? ServerType.None; + } /// - /// Gets the server CLSID. + /// Gets the server class id. /// - public Guid ServerClsid => GetType().GUID; + public Guid ServerClassId + { + get => SharpShellServerInfo.GetServerClassId(GetType()); + } } } diff --git a/SharpShell/Tools/ServerManager/ObjectExtensions.cs b/SharpShell/Tools/ServerManager/ObjectExtensions.cs index d25d2c9d..530db10d 100644 --- a/SharpShell/Tools/ServerManager/ObjectExtensions.cs +++ b/SharpShell/Tools/ServerManager/ObjectExtensions.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; +using System.ComponentModel; using System.Linq; -using System.Text; namespace ServerManager { @@ -10,10 +7,10 @@ public static class ObjectExtensions { public static string GetDescription(this object @this) { - var attributes = @this.GetType().GetCustomAttributes(typeof (DescriptionAttribute), true); - if (!attributes.Any()) - return null; - return attributes.OfType().First().Description; + return @this.GetType() + .GetCustomAttributes(typeof(DescriptionAttribute), true) + .OfType() + .FirstOrDefault()?.Description; } } } diff --git a/SharpShell/Tools/ServerManager/Program.cs b/SharpShell/Tools/ServerManager/Program.cs index 1bca6a8b..45a6de8c 100644 --- a/SharpShell/Tools/ServerManager/Program.cs +++ b/SharpShell/Tools/ServerManager/Program.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Windows.Forms; namespace ServerManager diff --git a/SharpShell/Tools/ServerManager/Properties/Resources.Designer.cs b/SharpShell/Tools/ServerManager/Properties/Resources.Designer.cs index 8ce1b9e2..8fe2081b 100644 --- a/SharpShell/Tools/ServerManager/Properties/Resources.Designer.cs +++ b/SharpShell/Tools/ServerManager/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18051 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -19,7 +19,7 @@ namespace ServerManager.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/SharpShell/Tools/ServerManager/Properties/Settings.Designer.cs b/SharpShell/Tools/ServerManager/Properties/Settings.Designer.cs index 72bc7379..deb6e675 100644 --- a/SharpShell/Tools/ServerManager/Properties/Settings.Designer.cs +++ b/SharpShell/Tools/ServerManager/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.269 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,7 +12,7 @@ namespace ServerManager.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.Designer.cs b/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.Designer.cs deleted file mode 100644 index 4c275e7c..00000000 --- a/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.Designer.cs +++ /dev/null @@ -1,347 +0,0 @@ -namespace ServerManager.ServerDetails -{ - partial class ServerDetailsView - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.label5 = new System.Windows.Forms.Label(); - this.textBox32BitServer = new System.Windows.Forms.TextBox(); - this.textBox64BitServer = new System.Windows.Forms.TextBox(); - this.label7 = new System.Windows.Forms.Label(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.textBoxAssociations = new System.Windows.Forms.TextBox(); - this.label8 = new System.Windows.Forms.Label(); - this.textBoxAssemblyPath = new System.Windows.Forms.TextBox(); - this.label6 = new System.Windows.Forms.Label(); - this.textBoxServerSecurity = new System.Windows.Forms.TextBox(); - this.textBoxServerCLSID = new System.Windows.Forms.TextBox(); - this.textBoxServerType = new System.Windows.Forms.TextBox(); - this.textBoxServerName = new System.Windows.Forms.TextBox(); - this.label4 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.groupBoxRegistration = new System.Windows.Forms.GroupBox(); - this.textBox32BitServerRegistration = new System.Windows.Forms.TextBox(); - this.label9 = new System.Windows.Forms.Label(); - this.textBox64BitServerRegistration = new System.Windows.Forms.TextBox(); - this.label10 = new System.Windows.Forms.Label(); - this.groupBox1.SuspendLayout(); - this.groupBox2.SuspendLayout(); - this.groupBoxRegistration.SuspendLayout(); - this.SuspendLayout(); - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(18, 33); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(68, 13); - this.label5.TabIndex = 0; - this.label5.Text = "32 Bit Server"; - // - // textBox32BitServer - // - this.textBox32BitServer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBox32BitServer.Location = new System.Drawing.Point(128, 30); - this.textBox32BitServer.Name = "textBox32BitServer"; - this.textBox32BitServer.ReadOnly = true; - this.textBox32BitServer.Size = new System.Drawing.Size(230, 20); - this.textBox32BitServer.TabIndex = 1; - // - // textBox64BitServer - // - this.textBox64BitServer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBox64BitServer.Location = new System.Drawing.Point(127, 56); - this.textBox64BitServer.Name = "textBox64BitServer"; - this.textBox64BitServer.ReadOnly = true; - this.textBox64BitServer.Size = new System.Drawing.Size(230, 20); - this.textBox64BitServer.TabIndex = 3; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(18, 59); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(68, 13); - this.label7.TabIndex = 2; - this.label7.Text = "64 Bit Server"; - // - // groupBox1 - // - this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox1.Controls.Add(this.textBoxAssociations); - this.groupBox1.Controls.Add(this.label8); - this.groupBox1.Controls.Add(this.textBoxAssemblyPath); - this.groupBox1.Controls.Add(this.label6); - this.groupBox1.Controls.Add(this.textBoxServerSecurity); - this.groupBox1.Controls.Add(this.textBoxServerCLSID); - this.groupBox1.Controls.Add(this.textBoxServerType); - this.groupBox1.Controls.Add(this.textBoxServerName); - this.groupBox1.Controls.Add(this.label4); - this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Location = new System.Drawing.Point(3, 3); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(376, 198); - this.groupBox1.TabIndex = 0; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Server"; - // - // textBoxAssociations - // - this.textBoxAssociations.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxAssociations.Location = new System.Drawing.Point(128, 161); - this.textBoxAssociations.Name = "textBoxAssociations"; - this.textBoxAssociations.ReadOnly = true; - this.textBoxAssociations.Size = new System.Drawing.Size(230, 20); - this.textBoxAssociations.TabIndex = 11; - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(18, 164); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(113, 13); - this.label8.TabIndex = 10; - this.label8.Text = "Specified Associations"; - // - // textBoxAssemblyPath - // - this.textBoxAssemblyPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxAssemblyPath.Location = new System.Drawing.Point(128, 135); - this.textBoxAssemblyPath.Name = "textBoxAssemblyPath"; - this.textBoxAssemblyPath.ReadOnly = true; - this.textBoxAssemblyPath.Size = new System.Drawing.Size(230, 20); - this.textBoxAssemblyPath.TabIndex = 9; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(18, 138); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(76, 13); - this.label6.TabIndex = 8; - this.label6.Text = "Assembly Path"; - // - // textBoxServerSecurity - // - this.textBoxServerSecurity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxServerSecurity.Location = new System.Drawing.Point(128, 109); - this.textBoxServerSecurity.Name = "textBoxServerSecurity"; - this.textBoxServerSecurity.ReadOnly = true; - this.textBoxServerSecurity.Size = new System.Drawing.Size(230, 20); - this.textBoxServerSecurity.TabIndex = 7; - // - // textBoxServerCLSID - // - this.textBoxServerCLSID.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxServerCLSID.Location = new System.Drawing.Point(128, 83); - this.textBoxServerCLSID.Name = "textBoxServerCLSID"; - this.textBoxServerCLSID.ReadOnly = true; - this.textBoxServerCLSID.Size = new System.Drawing.Size(230, 20); - this.textBoxServerCLSID.TabIndex = 5; - // - // textBoxServerType - // - this.textBoxServerType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxServerType.Location = new System.Drawing.Point(128, 57); - this.textBoxServerType.Name = "textBoxServerType"; - this.textBoxServerType.ReadOnly = true; - this.textBoxServerType.Size = new System.Drawing.Size(230, 20); - this.textBoxServerType.TabIndex = 3; - // - // textBoxServerName - // - this.textBoxServerName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxServerName.Location = new System.Drawing.Point(128, 31); - this.textBoxServerName.Name = "textBoxServerName"; - this.textBoxServerName.ReadOnly = true; - this.textBoxServerName.Size = new System.Drawing.Size(230, 20); - this.textBoxServerName.TabIndex = 1; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(18, 112); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(45, 13); - this.label4.TabIndex = 6; - this.label4.Text = "Security"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(18, 86); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(72, 13); - this.label3.TabIndex = 4; - this.label3.Text = "Server CLSID"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(18, 60); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(65, 13); - this.label2.TabIndex = 2; - this.label2.Text = "Server Type"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(18, 34); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(35, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Name"; - // - // groupBox2 - // - this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox2.Controls.Add(this.textBox32BitServer); - this.groupBox2.Controls.Add(this.label5); - this.groupBox2.Controls.Add(this.textBox64BitServer); - this.groupBox2.Controls.Add(this.label7); - this.groupBox2.Location = new System.Drawing.Point(0, 207); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(376, 91); - this.groupBox2.TabIndex = 1; - this.groupBox2.TabStop = false; - this.groupBox2.Text = "Installation"; - // - // groupBoxRegistration - // - this.groupBoxRegistration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxRegistration.Controls.Add(this.textBox32BitServerRegistration); - this.groupBoxRegistration.Controls.Add(this.label9); - this.groupBoxRegistration.Controls.Add(this.textBox64BitServerRegistration); - this.groupBoxRegistration.Controls.Add(this.label10); - this.groupBoxRegistration.Location = new System.Drawing.Point(0, 304); - this.groupBoxRegistration.Name = "groupBoxRegistration"; - this.groupBoxRegistration.Size = new System.Drawing.Size(376, 91); - this.groupBoxRegistration.TabIndex = 2; - this.groupBoxRegistration.TabStop = false; - this.groupBoxRegistration.Text = "Registration"; - // - // textBox32BitServerRegistration - // - this.textBox32BitServerRegistration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBox32BitServerRegistration.Location = new System.Drawing.Point(128, 30); - this.textBox32BitServerRegistration.Name = "textBox32BitServerRegistration"; - this.textBox32BitServerRegistration.ReadOnly = true; - this.textBox32BitServerRegistration.Size = new System.Drawing.Size(230, 20); - this.textBox32BitServerRegistration.TabIndex = 1; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(18, 33); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(68, 13); - this.label9.TabIndex = 0; - this.label9.Text = "32 Bit Server"; - // - // textBox64BitServerRegistration - // - this.textBox64BitServerRegistration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBox64BitServerRegistration.Location = new System.Drawing.Point(127, 56); - this.textBox64BitServerRegistration.Name = "textBox64BitServerRegistration"; - this.textBox64BitServerRegistration.ReadOnly = true; - this.textBox64BitServerRegistration.Size = new System.Drawing.Size(230, 20); - this.textBox64BitServerRegistration.TabIndex = 3; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(18, 59); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(68, 13); - this.label10.TabIndex = 2; - this.label10.Text = "64 Bit Server"; - // - // ServerDetailsView - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.groupBoxRegistration); - this.Controls.Add(this.groupBox2); - this.Controls.Add(this.groupBox1); - this.Name = "ServerDetailsView"; - this.Size = new System.Drawing.Size(382, 437); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.groupBoxRegistration.ResumeLayout(false); - this.groupBoxRegistration.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Label label5; - private System.Windows.Forms.TextBox textBox32BitServer; - private System.Windows.Forms.TextBox textBox64BitServer; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.TextBox textBoxServerSecurity; - private System.Windows.Forms.TextBox textBoxServerCLSID; - private System.Windows.Forms.TextBox textBoxServerType; - private System.Windows.Forms.TextBox textBoxServerName; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.GroupBox groupBox2; - private System.Windows.Forms.TextBox textBoxAssemblyPath; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.TextBox textBoxAssociations; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.GroupBox groupBoxRegistration; - private System.Windows.Forms.TextBox textBox32BitServerRegistration; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.TextBox textBox64BitServerRegistration; - private System.Windows.Forms.Label label10; - } -} diff --git a/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.cs b/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.cs deleted file mode 100644 index 4aa487e6..00000000 --- a/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Windows.Forms; -using SharpShell.Attributes; -using SharpShell.ServerRegistration; - -namespace ServerManager.ServerDetails -{ - public partial class ServerDetailsView : UserControl - { - public ServerDetailsView() - { - InitializeComponent(); - } - - public void Initialise(ServerEntry serverEntry) - { - if (serverEntry != null) - { - textBoxServerName.Text = serverEntry.ServerName; - textBoxServerType.Text = serverEntry.ServerType.ToString(); - textBoxServerCLSID.Text = serverEntry.ClassId.ToString(); - textBoxServerSecurity.Text = serverEntry.GetSecurityStatus(); - textBoxAssemblyPath.Text = serverEntry.ServerPath; - - if (serverEntry.IsInvalid) - { - // Clear other data for invalid servers. - textBoxAssociations.Text = string.Empty; - textBox32BitServer.Text = string.Empty; - textBox64BitServer.Text = string.Empty; - } - else - { - // Get the specified associations. - var associationType = COMServerAssociationAttribute.GetAssociationType(serverEntry.Server.GetType()); - var associations = COMServerAssociationAttribute.GetAssociations(serverEntry.Server.GetType()); - textBoxAssociations.Text = associationType.ToString() + " " + string.Join(", ", associations); - - // Now use the server registration manager to get the registration info - // for the different operating system architectures. - var info32 = ServerRegistrationManager.GetServerRegistrationInfo(serverEntry.Server.ServerClsid, - RegistrationType.OS32Bit); - var info64 = ServerRegistrationManager.GetServerRegistrationInfo(serverEntry.Server.ServerClsid, - RegistrationType.OS64Bit); - - // By default, our installation info is going to be empty. - textBox32BitServer.Text = "Not Installed"; - textBox64BitServer.Text = "Not Installed"; - textBox32BitServerRegistration.Text = "Not Registered"; - textBox64BitServerRegistration.Text = "Not Registered"; - - // Do we have 32 bit registration info? - if (info32 != null) - { - // Do we have a codebase? - if (!string.IsNullOrEmpty(info32.CodeBase)) - textBox32BitServer.Text = info32.CodeBase; - else if (!string.IsNullOrEmpty(info32.Assembly)) - textBox32BitServer.Text = info32.Assembly + " (GAC)"; - - // Set the registration info. - if (info32.IsApproved) - textBox32BitServerRegistration.Text = "Registered"; - } - - // Do we have 32 bit registration info? - if (info64 != null) - { - // Do we have a codebase? - if (!string.IsNullOrEmpty(info64.CodeBase)) - textBox64BitServer.Text = info64.CodeBase; - else if (!string.IsNullOrEmpty(info64.Assembly)) - textBox64BitServer.Text = info64.Assembly + " (GAC)"; - - // Set the registration info. - if (info64.IsApproved) - textBox64BitServerRegistration.Text = "Registered"; - } - } - } - } - } -} diff --git a/SharpShell/Tools/ServerManager/ServerEntry.cs b/SharpShell/Tools/ServerManager/ServerEntry.cs deleted file mode 100644 index 0af53624..00000000 --- a/SharpShell/Tools/ServerManager/ServerEntry.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Reflection; -using SharpShell; - -namespace ServerManager -{ - /// - /// A Server Entry in the application. Keeps track of viewmodel style data - /// for a sharp shell server. - /// - public class ServerEntry - { - /// - /// Gets or sets the name of the server. - /// - /// - /// The name of the server. - /// - public string ServerName { get; set; } - - /// - /// Gets or sets the server path. - /// - /// - /// The server path. - /// - public string ServerPath { get; set; } - - /// - /// Gets or sets the type of the server. - /// - /// - /// The type of the server. - /// - public ServerType ServerType { get; set; } - - /// - /// Gets or sets the class id. - /// - /// - /// The class id. - /// - public Guid ClassId { get; set; } - - /// - /// Gets or sets the server. - /// - /// - /// The server. - /// - public ISharpShellServer Server { get; set; } - - /// - /// Gets or sets a value indicating whether the server is invalid. - /// - public bool IsInvalid { get; set; } - - /// - /// Gets the security status. - /// - /// - public string GetSecurityStatus() - { - AssemblyName asmName = AssemblyName.GetAssemblyName(ServerPath); - var key = asmName.GetPublicKey(); - return key != null && key.Length > 0 ? "Signed" : "Not Signed"; - } - } -} diff --git a/SharpShell/Tools/ServerManager/ServerManager.csproj b/SharpShell/Tools/ServerManager/ServerManager.csproj index 05f467cc..92c4aaa3 100644 --- a/SharpShell/Tools/ServerManager/ServerManager.csproj +++ b/SharpShell/Tools/ServerManager/ServerManager.csproj @@ -1,5 +1,5 @@  - + Debug x86 @@ -10,8 +10,9 @@ Properties ServerManager ServerManager - v4.0 - Client + v4.6.2 + + 512 ..\..\ true @@ -62,6 +63,7 @@ false ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules true + false bin\x64\Release\ @@ -79,6 +81,7 @@ ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules true false + false true @@ -96,6 +99,7 @@ ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules true false + false bin\Release\ @@ -112,6 +116,7 @@ true ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules true + false SharpShell.ico @@ -146,13 +151,12 @@ AboutForm.cs - + UserControl - + ServerDetailsView.cs - Form @@ -171,6 +175,7 @@ Component + UserControl @@ -189,6 +194,7 @@ TestShellForm.cs + AboutForm.cs @@ -202,7 +208,7 @@ Resources.resx True - + ServerDetailsView.cs @@ -223,6 +229,7 @@ TestShellForm.cs + SettingsSingleFileGenerator diff --git a/SharpShell/Tools/ServerManager/ServerManagerForm.Designer.cs b/SharpShell/Tools/ServerManager/ServerManagerForm.Designer.cs index 460121b5..7cbb271a 100644 --- a/SharpShell/Tools/ServerManager/ServerManagerForm.Designer.cs +++ b/SharpShell/Tools/ServerManager/ServerManagerForm.Designer.cs @@ -1,5 +1,5 @@ -using ServerManager.ServerDetails; - +using ServerManager.Views; + namespace ServerManager { partial class ServerManagerForm @@ -33,22 +33,26 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServerManagerForm)); this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer(); - this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.statusStrip = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabelOSProcessor = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabelProcessProcessor = new System.Windows.Forms.ToolStripStatusLabel(); - this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.splitContainer = new System.Windows.Forms.SplitContainer(); this.listViewServers = new System.Windows.Forms.ListView(); this.columnHeaderServerName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeaderServerType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.imageList1 = new System.Windows.Forms.ImageList(this.components); - this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.serverDetailsView = new ServerManager.Views.ServerDetailsView(); + this.menuStrip = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.loadServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.serverToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.installToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.uninstallToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.installServerx86ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.registerServerx86ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.unregisterServerx86ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -73,28 +77,28 @@ private void InitializeComponent() this.requestAFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMain = new System.Windows.Forms.ToolStrip(); + this.toolStrip = new System.Windows.Forms.ToolStrip(); this.toolStripButtonOpenTestShell = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonTestServer = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonOpenShellDialog = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripButtonAttachDebugger = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonShellDebugger = new System.Windows.Forms.ToolStripButton(); - this.installToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.uninstallToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.serverDetailsView1 = new ServerManager.ServerDetails.ServerDetailsView(); - this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); + this.panelPleaseWait = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); this.toolStripContainer1.BottomToolStripPanel.SuspendLayout(); this.toolStripContainer1.ContentPanel.SuspendLayout(); this.toolStripContainer1.TopToolStripPanel.SuspendLayout(); this.toolStripContainer1.SuspendLayout(); - this.statusStrip1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); - this.splitContainer1.Panel1.SuspendLayout(); - this.splitContainer1.Panel2.SuspendLayout(); - this.splitContainer1.SuspendLayout(); - this.menuStrip1.SuspendLayout(); - this.toolStripMain.SuspendLayout(); + this.statusStrip.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); + this.splitContainer.Panel1.SuspendLayout(); + this.splitContainer.Panel2.SuspendLayout(); + this.splitContainer.SuspendLayout(); + this.menuStrip.SuspendLayout(); + this.toolStrip.SuspendLayout(); + this.panelPleaseWait.SuspendLayout(); this.SuspendLayout(); // // toolStripContainer1 @@ -102,43 +106,41 @@ private void InitializeComponent() // // toolStripContainer1.BottomToolStripPanel // - this.toolStripContainer1.BottomToolStripPanel.Controls.Add(this.statusStrip1); + this.toolStripContainer1.BottomToolStripPanel.Controls.Add(this.statusStrip); // // toolStripContainer1.ContentPanel // - this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1); - this.toolStripContainer1.ContentPanel.Margin = new System.Windows.Forms.Padding(6); - this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(1744, 859); + this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer); + this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(1084, 574); this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill; this.toolStripContainer1.Location = new System.Drawing.Point(0, 0); - this.toolStripContainer1.Margin = new System.Windows.Forms.Padding(6); this.toolStripContainer1.Name = "toolStripContainer1"; - this.toolStripContainer1.Size = new System.Drawing.Size(1744, 981); + this.toolStripContainer1.Size = new System.Drawing.Size(1084, 661); this.toolStripContainer1.TabIndex = 0; this.toolStripContainer1.Text = "toolStripContainer1"; // // toolStripContainer1.TopToolStripPanel // - this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStripMain); - this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.menuStrip1); + this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.menuStrip); + this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip); // - // statusStrip1 + // statusStrip // - this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.statusStrip1.ImageScalingSize = new System.Drawing.Size(32, 32); - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.statusStrip.Dock = System.Windows.Forms.DockStyle.None; + this.statusStrip.ImageScalingSize = new System.Drawing.Size(32, 32); + this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1, this.toolStripStatusLabelOSProcessor, this.toolStripStatusLabelProcessProcessor}); - this.statusStrip1.Location = new System.Drawing.Point(0, 0); - this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(1744, 41); - this.statusStrip1.TabIndex = 0; + this.statusStrip.Location = new System.Drawing.Point(0, 0); + this.statusStrip.Name = "statusStrip"; + this.statusStrip.Size = new System.Drawing.Size(1084, 24); + this.statusStrip.TabIndex = 0; // // toolStripStatusLabel1 // this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(632, 36); + this.toolStripStatusLabel1.Size = new System.Drawing.Size(307, 19); this.toolStripStatusLabel1.Text = "Drop SharpShell Server DLLs onto the list to analyse them"; // // toolStripStatusLabelOSProcessor @@ -146,7 +148,7 @@ private void InitializeComponent() this.toolStripStatusLabelOSProcessor.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left; this.toolStripStatusLabelOSProcessor.BorderStyle = System.Windows.Forms.Border3DStyle.Etched; this.toolStripStatusLabelOSProcessor.Name = "toolStripStatusLabelOSProcessor"; - this.toolStripStatusLabelOSProcessor.Size = new System.Drawing.Size(165, 36); + this.toolStripStatusLabelOSProcessor.Size = new System.Drawing.Size(83, 19); this.toolStripStatusLabelOSProcessor.Text = "Windows: x64"; // // toolStripStatusLabelProcessProcessor @@ -154,28 +156,26 @@ private void InitializeComponent() this.toolStripStatusLabelProcessProcessor.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left; this.toolStripStatusLabelProcessProcessor.BorderStyle = System.Windows.Forms.Border3DStyle.Etched; this.toolStripStatusLabelProcessProcessor.Name = "toolStripStatusLabelProcessProcessor"; - this.toolStripStatusLabelProcessProcessor.Size = new System.Drawing.Size(147, 36); + this.toolStripStatusLabelProcessProcessor.Size = new System.Drawing.Size(74, 19); this.toolStripStatusLabelProcessProcessor.Text = "Process: x86"; // - // splitContainer1 + // splitContainer // - this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; - this.splitContainer1.Location = new System.Drawing.Point(0, 0); - this.splitContainer1.Margin = new System.Windows.Forms.Padding(6); - this.splitContainer1.Name = "splitContainer1"; + this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + this.splitContainer.Location = new System.Drawing.Point(0, 0); + this.splitContainer.Name = "splitContainer"; // - // splitContainer1.Panel1 + // splitContainer.Panel1 // - this.splitContainer1.Panel1.Controls.Add(this.listViewServers); + this.splitContainer.Panel1.Controls.Add(this.listViewServers); // - // splitContainer1.Panel2 + // splitContainer.Panel2 // - this.splitContainer1.Panel2.Controls.Add(this.serverDetailsView1); - this.splitContainer1.Size = new System.Drawing.Size(1744, 859); - this.splitContainer1.SplitterDistance = 1356; - this.splitContainer1.SplitterWidth = 8; - this.splitContainer1.TabIndex = 1; + this.splitContainer.Panel2.Controls.Add(this.serverDetailsView); + this.splitContainer.Size = new System.Drawing.Size(1084, 574); + this.splitContainer.SplitterDistance = 686; + this.splitContainer.TabIndex = 1; // // listViewServers // @@ -187,9 +187,8 @@ private void InitializeComponent() this.listViewServers.Dock = System.Windows.Forms.DockStyle.Fill; this.listViewServers.FullRowSelect = true; this.listViewServers.Location = new System.Drawing.Point(0, 0); - this.listViewServers.Margin = new System.Windows.Forms.Padding(6); this.listViewServers.Name = "listViewServers"; - this.listViewServers.Size = new System.Drawing.Size(1356, 859); + this.listViewServers.Size = new System.Drawing.Size(686, 574); this.listViewServers.SmallImageList = this.imageList1; this.listViewServers.TabIndex = 0; this.listViewServers.UseCompatibleStateImageBehavior = false; @@ -202,17 +201,17 @@ private void InitializeComponent() // columnHeaderServerName // this.columnHeaderServerName.Text = "Server Name"; - this.columnHeaderServerName.Width = 200; + this.columnHeaderServerName.Width = 230; // // columnHeaderServerType // this.columnHeaderServerType.Text = "Type"; - this.columnHeaderServerType.Width = 120; + this.columnHeaderServerType.Width = 230; // // columnHeader // this.columnHeader.Text = "CLSID"; - this.columnHeader.Width = 200; + this.columnHeader.Width = 230; // // imageList1 // @@ -224,21 +223,32 @@ private void InitializeComponent() this.imageList1.Images.SetKeyName(3, "InfoTip.png"); this.imageList1.Images.SetKeyName(4, "IconOverlayHandler.png"); // - // menuStrip1 + // serverDetailsView + // + this.serverDetailsView.AutoScroll = true; + this.serverDetailsView.Dock = System.Windows.Forms.DockStyle.Fill; + this.serverDetailsView.ExtensionEntry = null; + this.serverDetailsView.Location = new System.Drawing.Point(0, 0); + this.serverDetailsView.Margin = new System.Windows.Forms.Padding(6); + this.serverDetailsView.Name = "serverDetailsView"; + this.serverDetailsView.Size = new System.Drawing.Size(394, 574); + this.serverDetailsView.TabIndex = 1; // - this.menuStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.menuStrip1.ImageScalingSize = new System.Drawing.Size(32, 32); - this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + // menuStrip + // + this.menuStrip.Dock = System.Windows.Forms.DockStyle.None; + this.menuStrip.ImageScalingSize = new System.Drawing.Size(32, 32); + this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.fileToolStripMenuItem, this.serverToolStripMenuItem, this.explorerToolStripMenuItem, this.toolsToolStripMenuItem, this.helpToolStripMenuItem}); - this.menuStrip1.Location = new System.Drawing.Point(0, 0); - this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Size = new System.Drawing.Size(1744, 42); - this.menuStrip1.TabIndex = 2; - this.menuStrip1.Text = "menuStrip1"; + this.menuStrip.Location = new System.Drawing.Point(0, 0); + this.menuStrip.Name = "menuStrip"; + this.menuStrip.Size = new System.Drawing.Size(1084, 24); + this.menuStrip.TabIndex = 2; + this.menuStrip.Text = "menuStrip1"; // // fileToolStripMenuItem // @@ -247,25 +257,25 @@ private void InitializeComponent() this.toolStripSeparator2, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(64, 38); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "&File"; // // loadServerToolStripMenuItem // this.loadServerToolStripMenuItem.Name = "loadServerToolStripMenuItem"; - this.loadServerToolStripMenuItem.Size = new System.Drawing.Size(254, 38); + this.loadServerToolStripMenuItem.Size = new System.Drawing.Size(144, 22); this.loadServerToolStripMenuItem.Text = "&Load Server..."; this.loadServerToolStripMenuItem.Click += new System.EventHandler(this.loadServerToolStripMenuItem_Click); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(251, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(141, 6); // // exitToolStripMenuItem // this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; - this.exitToolStripMenuItem.Size = new System.Drawing.Size(254, 38); + this.exitToolStripMenuItem.Size = new System.Drawing.Size(144, 22); this.exitToolStripMenuItem.Text = "&Exit"; this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); // @@ -287,80 +297,101 @@ private void InitializeComponent() this.toolStripSeparator1, this.testServerToolStripMenuItem}); this.serverToolStripMenuItem.Name = "serverToolStripMenuItem"; - this.serverToolStripMenuItem.Size = new System.Drawing.Size(94, 38); + this.serverToolStripMenuItem.Size = new System.Drawing.Size(51, 20); this.serverToolStripMenuItem.Text = "&Server"; // + // installToolStripMenuItem + // + this.installToolStripMenuItem.Name = "installToolStripMenuItem"; + this.installToolStripMenuItem.Size = new System.Drawing.Size(191, 22); + this.installToolStripMenuItem.Text = "&Install Assembly"; + this.installToolStripMenuItem.Click += new System.EventHandler(this.installToolStripMenuItem_Click); + // + // uninstallToolStripMenuItem + // + this.uninstallToolStripMenuItem.Name = "uninstallToolStripMenuItem"; + this.uninstallToolStripMenuItem.Size = new System.Drawing.Size(191, 22); + this.uninstallToolStripMenuItem.Text = "&Uninstall Assembly"; + this.uninstallToolStripMenuItem.Click += new System.EventHandler(this.uninstallToolStripMenuItem_Click); + // + // toolStripSeparator7 + // + this.toolStripSeparator7.Name = "toolStripSeparator7"; + this.toolStripSeparator7.Size = new System.Drawing.Size(188, 6); + // // installServerx86ToolStripMenuItem // this.installServerx86ToolStripMenuItem.Name = "installServerx86ToolStripMenuItem"; - this.installServerx86ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.installServerx86ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.installServerx86ToolStripMenuItem.Text = "Install Server (x86)"; - this.installServerx86ToolStripMenuItem.Click += new System.EventHandler(this.installServerx86ToolStripMenuItem_Click); + this.installServerx86ToolStripMenuItem.Click += new System.EventHandler(this.installServerX86ToolStripMenuItem_Click); // // registerServerx86ToolStripMenuItem // this.registerServerx86ToolStripMenuItem.Name = "registerServerx86ToolStripMenuItem"; - this.registerServerx86ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.registerServerx86ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.registerServerx86ToolStripMenuItem.Text = "Register Server (x86)"; - this.registerServerx86ToolStripMenuItem.Click += new System.EventHandler(this.registerServerx86ToolStripMenuItem_Click); + this.registerServerx86ToolStripMenuItem.Click += new System.EventHandler(this.registerServerX86ToolStripMenuItem_Click); // // unregisterServerx86ToolStripMenuItem // this.unregisterServerx86ToolStripMenuItem.Name = "unregisterServerx86ToolStripMenuItem"; - this.unregisterServerx86ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.unregisterServerx86ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.unregisterServerx86ToolStripMenuItem.Text = "Unregister Server (x86)"; - this.unregisterServerx86ToolStripMenuItem.Click += new System.EventHandler(this.unregisterServerx86ToolStripMenuItem_Click); + this.unregisterServerx86ToolStripMenuItem.Click += new System.EventHandler(this.unregisterServerX86ToolStripMenuItem_Click); // // uninstallServerx86ToolStripMenuItem // this.uninstallServerx86ToolStripMenuItem.Name = "uninstallServerx86ToolStripMenuItem"; - this.uninstallServerx86ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.uninstallServerx86ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.uninstallServerx86ToolStripMenuItem.Text = "Uninstall Server (x86)"; - this.uninstallServerx86ToolStripMenuItem.Click += new System.EventHandler(this.uninstallServerx86ToolStripMenuItem_Click); + this.uninstallServerx86ToolStripMenuItem.Click += new System.EventHandler(this.uninstallServerX86ToolStripMenuItem_Click); // // toolStripSeparator3 // this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(353, 6); + this.toolStripSeparator3.Size = new System.Drawing.Size(188, 6); // // installServerx64ToolStripMenuItem // this.installServerx64ToolStripMenuItem.Name = "installServerx64ToolStripMenuItem"; - this.installServerx64ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.installServerx64ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.installServerx64ToolStripMenuItem.Text = "Install Server (x64)"; - this.installServerx64ToolStripMenuItem.Click += new System.EventHandler(this.installServerx64ToolStripMenuItem_Click); + this.installServerx64ToolStripMenuItem.Click += new System.EventHandler(this.installServerX64ToolStripMenuItem_Click); // // registerServerx64ToolStripMenuItem // this.registerServerx64ToolStripMenuItem.Name = "registerServerx64ToolStripMenuItem"; - this.registerServerx64ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.registerServerx64ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.registerServerx64ToolStripMenuItem.Text = "Register Server (x64)"; - this.registerServerx64ToolStripMenuItem.Click += new System.EventHandler(this.registerServerx64ToolStripMenuItem_Click); + this.registerServerx64ToolStripMenuItem.Click += new System.EventHandler(this.registerServerX64ToolStripMenuItem_Click); // // unregisterServerx64ToolStripMenuItem // this.unregisterServerx64ToolStripMenuItem.Name = "unregisterServerx64ToolStripMenuItem"; - this.unregisterServerx64ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.unregisterServerx64ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.unregisterServerx64ToolStripMenuItem.Text = "Unregister Server (x64)"; - this.unregisterServerx64ToolStripMenuItem.Click += new System.EventHandler(this.unregisterServerx64ToolStripMenuItem_Click); + this.unregisterServerx64ToolStripMenuItem.Click += new System.EventHandler(this.unregisterServerX64ToolStripMenuItem_Click); // // uninstallServerx64ToolStripMenuItem // this.uninstallServerx64ToolStripMenuItem.Name = "uninstallServerx64ToolStripMenuItem"; - this.uninstallServerx64ToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.uninstallServerx64ToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.uninstallServerx64ToolStripMenuItem.Text = "Unin&stall Server (x64)"; - this.uninstallServerx64ToolStripMenuItem.Click += new System.EventHandler(this.uninstallServerx64ToolStripMenuItem_Click); + this.uninstallServerx64ToolStripMenuItem.Click += new System.EventHandler(this.uninstallServerX64ToolStripMenuItem_Click); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(353, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(188, 6); + this.toolStripSeparator1.Visible = false; // // testServerToolStripMenuItem // this.testServerToolStripMenuItem.Name = "testServerToolStripMenuItem"; - this.testServerToolStripMenuItem.Size = new System.Drawing.Size(356, 38); + this.testServerToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.testServerToolStripMenuItem.Text = "&Test Server..."; + this.testServerToolStripMenuItem.Visible = false; this.testServerToolStripMenuItem.Click += new System.EventHandler(this.testServerToolStripMenuItem_Click); // // explorerToolStripMenuItem @@ -370,14 +401,14 @@ private void InitializeComponent() this.desktopProcessToolStripMenuItem, this.restartExplorerToolStripMenuItem}); this.explorerToolStripMenuItem.Name = "explorerToolStripMenuItem"; - this.explorerToolStripMenuItem.Size = new System.Drawing.Size(113, 38); + this.explorerToolStripMenuItem.Size = new System.Drawing.Size(61, 20); this.explorerToolStripMenuItem.Text = "&Explorer"; // // alwaysUnloadDLLToolStripMenuItem // this.alwaysUnloadDLLToolStripMenuItem.CheckOnClick = true; this.alwaysUnloadDLLToolStripMenuItem.Name = "alwaysUnloadDLLToolStripMenuItem"; - this.alwaysUnloadDLLToolStripMenuItem.Size = new System.Drawing.Size(324, 38); + this.alwaysUnloadDLLToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.alwaysUnloadDLLToolStripMenuItem.Text = "&Always Unload DLL"; this.alwaysUnloadDLLToolStripMenuItem.Click += new System.EventHandler(this.alwaysUnloadDLLToolStripMenuItem_Click); // @@ -385,14 +416,14 @@ private void InitializeComponent() // this.desktopProcessToolStripMenuItem.CheckOnClick = true; this.desktopProcessToolStripMenuItem.Name = "desktopProcessToolStripMenuItem"; - this.desktopProcessToolStripMenuItem.Size = new System.Drawing.Size(324, 38); + this.desktopProcessToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.desktopProcessToolStripMenuItem.Text = "&Desktop Process"; this.desktopProcessToolStripMenuItem.Click += new System.EventHandler(this.desktopProcessToolStripMenuItem_Click); // // restartExplorerToolStripMenuItem // this.restartExplorerToolStripMenuItem.Name = "restartExplorerToolStripMenuItem"; - this.restartExplorerToolStripMenuItem.Size = new System.Drawing.Size(324, 38); + this.restartExplorerToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.restartExplorerToolStripMenuItem.Text = "&Restart Explorer"; this.restartExplorerToolStripMenuItem.Click += new System.EventHandler(this.restartExplorerToolStripMenuItem_Click); // @@ -401,13 +432,13 @@ private void InitializeComponent() this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.clearMostRecentlyUsedServersToolStripMenuItem}); this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; - this.toolsToolStripMenuItem.Size = new System.Drawing.Size(82, 38); + this.toolsToolStripMenuItem.Size = new System.Drawing.Size(47, 20); this.toolsToolStripMenuItem.Text = "&Tools"; // // clearMostRecentlyUsedServersToolStripMenuItem // this.clearMostRecentlyUsedServersToolStripMenuItem.Name = "clearMostRecentlyUsedServersToolStripMenuItem"; - this.clearMostRecentlyUsedServersToolStripMenuItem.Size = new System.Drawing.Size(459, 38); + this.clearMostRecentlyUsedServersToolStripMenuItem.Size = new System.Drawing.Size(243, 22); this.clearMostRecentlyUsedServersToolStripMenuItem.Text = "&Clear most recently used servers"; this.clearMostRecentlyUsedServersToolStripMenuItem.Click += new System.EventHandler(this.clearMostRecentlyUsedServersToolStripMenuItem_Click); // @@ -421,68 +452,68 @@ private void InitializeComponent() this.toolStripSeparator5, this.aboutToolStripMenuItem}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size(77, 38); + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); this.helpToolStripMenuItem.Text = "&Help"; // // sharpShellProjectHomePageToolStripMenuItem // this.sharpShellProjectHomePageToolStripMenuItem.Name = "sharpShellProjectHomePageToolStripMenuItem"; - this.sharpShellProjectHomePageToolStripMenuItem.Size = new System.Drawing.Size(437, 38); + this.sharpShellProjectHomePageToolStripMenuItem.Size = new System.Drawing.Size(234, 22); this.sharpShellProjectHomePageToolStripMenuItem.Text = "&SharpShell Project Home Page"; this.sharpShellProjectHomePageToolStripMenuItem.Click += new System.EventHandler(this.sharpShellProjectHomePageToolStripMenuItem_Click); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(434, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(231, 6); // // reportABugToolStripMenuItem // this.reportABugToolStripMenuItem.Name = "reportABugToolStripMenuItem"; - this.reportABugToolStripMenuItem.Size = new System.Drawing.Size(437, 38); + this.reportABugToolStripMenuItem.Size = new System.Drawing.Size(234, 22); this.reportABugToolStripMenuItem.Text = "&Report a Bug"; this.reportABugToolStripMenuItem.Click += new System.EventHandler(this.reportABugToolStripMenuItem_Click); // // requestAFeatureToolStripMenuItem // this.requestAFeatureToolStripMenuItem.Name = "requestAFeatureToolStripMenuItem"; - this.requestAFeatureToolStripMenuItem.Size = new System.Drawing.Size(437, 38); + this.requestAFeatureToolStripMenuItem.Size = new System.Drawing.Size(234, 22); this.requestAFeatureToolStripMenuItem.Text = "Request a &Feature"; this.requestAFeatureToolStripMenuItem.Click += new System.EventHandler(this.requestAFeatureToolStripMenuItem_Click); // // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(434, 6); + this.toolStripSeparator5.Size = new System.Drawing.Size(231, 6); // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(437, 38); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(234, 22); this.aboutToolStripMenuItem.Text = "&About..."; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); // - // toolStripMain + // toolStrip // - this.toolStripMain.Dock = System.Windows.Forms.DockStyle.None; - this.toolStripMain.ImageScalingSize = new System.Drawing.Size(32, 32); - this.toolStripMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStrip.Dock = System.Windows.Forms.DockStyle.None; + this.toolStrip.ImageScalingSize = new System.Drawing.Size(32, 32); + this.toolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripButtonOpenTestShell, this.toolStripButtonTestServer, this.toolStripButtonOpenShellDialog, this.toolStripSeparator6, this.toolStripButtonAttachDebugger, this.toolStripButtonShellDebugger}); - this.toolStripMain.Location = new System.Drawing.Point(3, 42); - this.toolStripMain.Name = "toolStripMain"; - this.toolStripMain.Size = new System.Drawing.Size(1099, 39); - this.toolStripMain.TabIndex = 3; + this.toolStrip.Location = new System.Drawing.Point(3, 24); + this.toolStrip.Name = "toolStrip"; + this.toolStrip.Size = new System.Drawing.Size(616, 39); + this.toolStrip.TabIndex = 3; // // toolStripButtonOpenTestShell // this.toolStripButtonOpenTestShell.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButtonOpenTestShell.Name = "toolStripButtonOpenTestShell"; - this.toolStripButtonOpenTestShell.Size = new System.Drawing.Size(186, 36); + this.toolStripButtonOpenTestShell.Size = new System.Drawing.Size(92, 36); this.toolStripButtonOpenTestShell.Text = "Open Test Shell"; this.toolStripButtonOpenTestShell.Click += new System.EventHandler(this.toolStripButtonOpenTestShell_Click); // @@ -490,8 +521,9 @@ private void InitializeComponent() // this.toolStripButtonTestServer.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButtonTestServer.Name = "toolStripButtonTestServer"; - this.toolStripButtonTestServer.Size = new System.Drawing.Size(270, 36); + this.toolStripButtonTestServer.Size = new System.Drawing.Size(132, 36); this.toolStripButtonTestServer.Text = "Test Server in Test Shell"; + this.toolStripButtonTestServer.Visible = false; this.toolStripButtonTestServer.Click += new System.EventHandler(this.toolStripButtonTestServer_Click); // // toolStripButtonOpenShellDialog @@ -500,7 +532,7 @@ private void InitializeComponent() this.toolStripButtonOpenShellDialog.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButtonOpenShellDialog.Image"))); this.toolStripButtonOpenShellDialog.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButtonOpenShellDialog.Name = "toolStripButtonOpenShellDialog"; - this.toolStripButtonOpenShellDialog.Size = new System.Drawing.Size(213, 36); + this.toolStripButtonOpenShellDialog.Size = new System.Drawing.Size(105, 36); this.toolStripButtonOpenShellDialog.Text = "Open Shell Dialog"; this.toolStripButtonOpenShellDialog.Click += new System.EventHandler(this.toolStripButtonOpenShellDialog_Click); // @@ -524,50 +556,52 @@ private void InitializeComponent() this.toolStripButtonShellDebugger.Image = global::ServerManager.Properties.Resources.Debug; this.toolStripButtonShellDebugger.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButtonShellDebugger.Name = "toolStripButtonShellDebugger"; - this.toolStripButtonShellDebugger.Size = new System.Drawing.Size(376, 36); + this.toolStripButtonShellDebugger.Size = new System.Drawing.Size(202, 36); this.toolStripButtonShellDebugger.Text = "Shell Debugger (Experimental)"; this.toolStripButtonShellDebugger.Click += new System.EventHandler(this.toolStripButtonShellDebugger_Click); // - // installToolStripMenuItem + // panelPleaseWait // - this.installToolStripMenuItem.Name = "installToolStripMenuItem"; - this.installToolStripMenuItem.Size = new System.Drawing.Size(356, 38); - this.installToolStripMenuItem.Text = "&Install"; - this.installToolStripMenuItem.Click += new System.EventHandler(this.installToolStripMenuItem_Click); - // - // uninstallToolStripMenuItem - // - this.uninstallToolStripMenuItem.Name = "uninstallToolStripMenuItem"; - this.uninstallToolStripMenuItem.Size = new System.Drawing.Size(356, 38); - this.uninstallToolStripMenuItem.Text = "&Uninstall"; - this.uninstallToolStripMenuItem.Click += new System.EventHandler(this.uninstallToolStripMenuItem_Click); + this.panelPleaseWait.Anchor = System.Windows.Forms.AnchorStyles.None; + this.panelPleaseWait.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panelPleaseWait.Controls.Add(this.label1); + this.panelPleaseWait.Controls.Add(this.progressBar1); + this.panelPleaseWait.Location = new System.Drawing.Point(400, 300); + this.panelPleaseWait.Name = "panelPleaseWait"; + this.panelPleaseWait.Size = new System.Drawing.Size(300, 50); + this.panelPleaseWait.TabIndex = 1; + this.panelPleaseWait.Visible = false; // - // serverDetailsView1 + // label1 // - this.serverDetailsView1.Dock = System.Windows.Forms.DockStyle.Fill; - this.serverDetailsView1.Location = new System.Drawing.Point(0, 0); - this.serverDetailsView1.Margin = new System.Windows.Forms.Padding(12); - this.serverDetailsView1.Name = "serverDetailsView1"; - this.serverDetailsView1.Size = new System.Drawing.Size(380, 859); - this.serverDetailsView1.TabIndex = 1; + this.label1.Location = new System.Drawing.Point(3, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(292, 17); + this.label1.TabIndex = 1; + this.label1.Text = "Please wait ..."; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // - // toolStripSeparator7 + // progressBar1 // - this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(353, 6); + this.progressBar1.Location = new System.Drawing.Point(3, 23); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(292, 23); + this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; + this.progressBar1.TabIndex = 0; + this.progressBar1.Value = 33; // // ServerManagerForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(192F, 192F); + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(1744, 981); + this.ClientSize = new System.Drawing.Size(1084, 661); + this.Controls.Add(this.panelPleaseWait); this.Controls.Add(this.toolStripContainer1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MainMenuStrip = this.menuStrip1; - this.Margin = new System.Windows.Forms.Padding(6); + this.MainMenuStrip = this.menuStrip; this.Name = "ServerManagerForm"; this.Text = "Server Manager"; - this.Load += new System.EventHandler(this.ServerManagerForm_Load); + this.Shown += new System.EventHandler(this.ServerManagerForm_Shown); this.toolStripContainer1.BottomToolStripPanel.ResumeLayout(false); this.toolStripContainer1.BottomToolStripPanel.PerformLayout(); this.toolStripContainer1.ContentPanel.ResumeLayout(false); @@ -575,16 +609,17 @@ private void InitializeComponent() this.toolStripContainer1.TopToolStripPanel.PerformLayout(); this.toolStripContainer1.ResumeLayout(false); this.toolStripContainer1.PerformLayout(); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); - this.splitContainer1.Panel1.ResumeLayout(false); - this.splitContainer1.Panel2.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); - this.splitContainer1.ResumeLayout(false); - this.menuStrip1.ResumeLayout(false); - this.menuStrip1.PerformLayout(); - this.toolStripMain.ResumeLayout(false); - this.toolStripMain.PerformLayout(); + this.statusStrip.ResumeLayout(false); + this.statusStrip.PerformLayout(); + this.splitContainer.Panel1.ResumeLayout(false); + this.splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit(); + this.splitContainer.ResumeLayout(false); + this.menuStrip.ResumeLayout(false); + this.menuStrip.PerformLayout(); + this.toolStrip.ResumeLayout(false); + this.toolStrip.PerformLayout(); + this.panelPleaseWait.ResumeLayout(false); this.ResumeLayout(false); } @@ -596,7 +631,7 @@ private void InitializeComponent() private System.Windows.Forms.ColumnHeader columnHeaderServerName; private System.Windows.Forms.ColumnHeader columnHeader; private System.Windows.Forms.ColumnHeader columnHeaderServerType; - private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.MenuStrip menuStrip; private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem explorerToolStripMenuItem; @@ -606,13 +641,13 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem installServerx86ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem uninstallServerx86ToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.StatusStrip statusStrip; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; private System.Windows.Forms.ToolStripMenuItem loadServerToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; private System.Windows.Forms.ImageList imageList1; - private System.Windows.Forms.SplitContainer splitContainer1; - private ServerDetailsView serverDetailsView1; + private System.Windows.Forms.SplitContainer splitContainer; + private ServerDetailsView serverDetailsView; private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem clearMostRecentlyUsedServersToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem installServerx64ToolStripMenuItem; @@ -624,7 +659,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem unregisterServerx64ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem restartExplorerToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem testServerToolStripMenuItem; - private System.Windows.Forms.ToolStrip toolStripMain; + private System.Windows.Forms.ToolStrip toolStrip; private System.Windows.Forms.ToolStripButton toolStripButtonTestServer; private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem sharpShellProjectHomePageToolStripMenuItem; @@ -643,6 +678,9 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem installToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem uninstallToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; + private System.Windows.Forms.Panel panelPleaseWait; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ProgressBar progressBar1; } } diff --git a/SharpShell/Tools/ServerManager/ServerManagerForm.cs b/SharpShell/Tools/ServerManager/ServerManagerForm.cs index efffd40d..4efafa4c 100644 --- a/SharpShell/Tools/ServerManager/ServerManagerForm.cs +++ b/SharpShell/Tools/ServerManager/ServerManagerForm.cs @@ -2,225 +2,139 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; -using System.Drawing; using System.IO; using System.Linq; +using System.Threading.Tasks; using System.Windows.Forms; +using ServerManager.Properties; using ServerManager.ShellDebugger; using ServerManager.TestShell; +using ServerManager.Views; using SharpShell; using SharpShell.Diagnostics; -using SharpShell.Helpers; using SharpShell.ServerRegistration; -using SharpShell.SharpContextMenu; -using SharpShell.SharpDropHandler; -using SharpShell.SharpIconHandler; -using SharpShell.SharpIconOverlayHandler; -using SharpShell.SharpInfoTipHandler; -using SharpShell.SharpPreviewHandler; -using SharpShell.SharpThumbnailHandler; namespace ServerManager { /// - /// The main class + /// The main class /// - public partial class ServerManagerForm : Form + internal partial class ServerManagerForm : Form { + /// + /// The explorer configuration manager. + /// + private readonly ExplorerConfigurationManager + _explorerConfigurationManager = new ExplorerConfigurationManager(); + public ServerManagerForm() { InitializeComponent(); - if (Properties.Settings.Default.RecentlyUsedFiles == null) - Properties.Settings.Default.RecentlyUsedFiles = new StringCollection(); + // Setup the statusbar. + toolStripStatusLabelOSProcessor.Text = + Environment.Is64BitOperatingSystem ? "Windows (x64)" : "Windows (x86)"; + toolStripStatusLabelProcessProcessor.Text = Environment.Is64BitProcess ? "Process (x64)" : "Process (x86)"; + + // Set the settings. + desktopProcessToolStripMenuItem.Checked = _explorerConfigurationManager.DesktopProcess; + alwaysUnloadDLLToolStripMenuItem.Checked = _explorerConfigurationManager.AlwaysUnloadDll; // Set initial UI command state. UpdateUserInterfaceCommands(); } - public IEnumerable ServerEntries + #region Control Event Handlers + + private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { - get { return listViewServers.Items.OfType().Select(lvi => lvi.Tag).OfType(); } + new AboutForm().ShowDialog(this); } - public void AddServer(string path, bool addToMostRecentlyUsedFiles) + private void alwaysUnloadDLLToolStripMenuItem_Click(object sender, EventArgs e) { - if (ServerEntries.Any(se => se.ServerPath == path)) - return; - - try - { - // Load any servers from the assembly. - var serverEntries = ServerRegistrationManager.EnumerateFromFile(path); - - foreach (var serverEntry in serverEntries) - { - try - { - AddServerEntryToList(new ServerEntry - { - ClassId = serverEntry.ServerClsid, - Server = serverEntry, - ServerName = serverEntry.DisplayName, - ServerPath = path, - ServerType = serverEntry.ServerType, - IsInvalid = false - }); - } - catch - { - AddServerEntryToList(new ServerEntry - { - ServerName = "Invalid", - ServerPath = path, - ServerType = ServerType.None, - ClassId = new Guid(), - Server = null, - IsInvalid = true - }); - } - } - } - catch - { - addToMostRecentlyUsedFiles = false; - MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning"); - } - - if (addToMostRecentlyUsedFiles && Properties.Settings.Default.RecentlyUsedFiles.Contains(path) == false) - { - // We've successfully added the server - so add the path of the server to our recent files. - Properties.Settings.Default.RecentlyUsedFiles.Insert(0, path); - Properties.Settings.Default.Save(); - } + _explorerConfigurationManager.AlwaysUnloadDll = alwaysUnloadDLLToolStripMenuItem.Checked; } - private void AddServerEntryToList(ServerEntry serverEntry) + private void CheckIfRegisterOrUnregisterRequiresExplorerRestart(params SharpShellServerInfo[] servers) { - var listItem = new ListViewItem( - new[] - { - serverEntry.ServerName, - serverEntry.ServerType.ToString(), - serverEntry.ClassId.ToString() - }) {Tag = serverEntry}; - - switch (serverEntry.ServerType) + if (servers?.Any(server => server?.ServerType == ServerType.ShellIconOverlayHandler) == true) { - case ServerType.ShellContextMenu: - listItem.ImageIndex = 0; - break; - case ServerType.ShellPropertySheet: - listItem.ImageIndex = 2; - break; - case ServerType.ShellIconHandler: - listItem.ImageIndex = 1; - break; - case ServerType.ShellInfoTipHandler: - listItem.ImageIndex = 3; - break; - case ServerType.ShellIconOverlayHandler: - listItem.ImageIndex = 4; - break; - default: - listItem.ImageIndex = 0; - break; + if (MessageBox.Show(this, + @"This change will not take effect until Windows Explorer is restarted. Would you " + + @"like to restart Windows Explorer now?", @"Restart Explorer?", MessageBoxButtons.YesNo, + MessageBoxIcon.Question) == + DialogResult.Yes) + { + ExplorerManager.RestartExplorer(); + } } - - if (serverEntry.IsInvalid) - listItem.ForeColor = Color.FromArgb(255, 0, 0); - - listViewServers.Items.Add(listItem); - } - public ServerEntry SelectedServerEntry + private void clearMostRecentlyUsedServersToolStripMenuItem_Click(object sender, EventArgs e) { - get { return listViewServers.SelectedItems.Count > 0 ? (ServerEntry)listViewServers.SelectedItems[0].Tag : null; } + ClearRecentlyUsed(); } - public ServerEntry[] AllServerEntries + private void desktopProcessToolStripMenuItem_Click(object sender, EventArgs e) { - get - { - return listViewServers.Items - .Cast() - .Select(item => item.Tag as ServerEntry) - .Where(entry => entry != null).ToArray(); - } + _explorerConfigurationManager.DesktopProcess = desktopProcessToolStripMenuItem.Checked; } - private void ServerManagerForm_Load(object sender, EventArgs e) + private void exitToolStripMenuItem_Click(object sender, EventArgs e) { - // Setup the statusbar. - toolStripStatusLabelOSProcessor.Text = Environment.Is64BitOperatingSystem ? "Windows (x64)" : "Windows (x86)"; - toolStripStatusLabelProcessProcessor.Text = Environment.Is64BitProcess ? "Process (x64)" : "Process (x86)"; - - // Set the settings. - desktopProcessToolStripMenuItem.Checked = explorerConfigurationManager.DesktopProcess; - alwaysUnloadDLLToolStripMenuItem.Checked = explorerConfigurationManager.AlwaysUnloadDll; - - // Add the recently used servers. If any of them fail to load, we'll remove them from the list. - var recentlyUsedFilesToRemove = new List(); - if (Properties.Settings.Default.RecentlyUsedFiles != null) - { - foreach(var path in Properties.Settings.Default.RecentlyUsedFiles) - AddServer(path, false); - } - - // Check for any servers added via the command line. - var arguments = Environment.GetCommandLineArgs(); - for(int i = 1; i < arguments.Count(); i++) - { - var arg = arguments[i]; - if(File.Exists(arg)) - AddServer(arg, true); - } + Close(); } - private void alwaysUnloadDLLToolStripMenuItem_Click(object sender, EventArgs e) + private void installServerX64ToolStripMenuItem_Click(object sender, EventArgs e) { - explorerConfigurationManager.AlwaysUnloadDll = alwaysUnloadDLLToolStripMenuItem.Checked; + // Install the server. + InstallServer(SelectedEntry, RegistrationScope.OS64Bit); } - private void desktopProcessToolStripMenuItem_Click(object sender, EventArgs e) + private void installServerX86ToolStripMenuItem_Click(object sender, EventArgs e) { - explorerConfigurationManager.DesktopProcess = desktopProcessToolStripMenuItem.Checked; + // Install the server. + InstallServer(SelectedEntry, RegistrationScope.OS32Bit); } - /// - /// The explorer configuration manager. - /// - private readonly ExplorerConfigurationManager explorerConfigurationManager = new ExplorerConfigurationManager(); - - private void installServerx86ToolStripMenuItem_Click(object sender, EventArgs e) + private void installToolStripMenuItem_Click(object sender, EventArgs e) { - if (SelectedServerEntry == null) + // Bail if we have no server selected. + if (SelectedEntry?.SharpShellServerInfo?.AssemblyInfo == null) + { return; + } - ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS32Bit, true); - serverDetailsView1.Initialise(SelectedServerEntry); - } - - private void uninstallServerx86ToolStripMenuItem_Click(object sender, EventArgs e) - { - if (SelectedServerEntry == null) - return; + var assembly = SelectedEntry.SharpShellServerInfo.AssemblyInfo; + var fromGac = string.IsNullOrEmpty(SelectedEntry.SharpShellServerInfo.AssemblyInfo.AssemblyPath); + var success = InstallAssembly(assembly, !fromGac); - // Unregister the server. - ServerRegistrationManager.UninstallServer(SelectedServerEntry.Server, RegistrationType.OS32Bit); - serverDetailsView1.Initialise(SelectedServerEntry); + // Inform the user of the result. + if (success) + { + MessageBox.Show(@"Installed server successfully.", @"Install Server", MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + else + { + MessageBox.Show(@"Failed to install, check the SharpShell log for details.", @"Install Server", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } } - private void loadServerToolStripMenuItem_Click(object sender, EventArgs e) + private void listViewServers_DragDrop(object sender, DragEventArgs e) { - // Create a file open dialog. - var fileOpenDialog = new OpenFileDialog(); - fileOpenDialog.Filter = "COM Servers (*.dll)|*.dll|All Files (*.*)|*.*"; - if (fileOpenDialog.ShowDialog(this) == DialogResult.OK) + if (e.Data.GetDataPresent(DataFormats.FileDrop)) { - // Try and add the server. - AddServer(fileOpenDialog.FileName, true); + if (e.Data.GetData(DataFormats.FileDrop) is string[] files) + { + foreach (var file in files) + { + AddServersFromFile(file); + } + } } } @@ -228,7 +142,9 @@ private void listViewServers_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { - e.Effect = ((string[]) e.Data.GetData(DataFormats.FileDrop)).Any() ? DragDropEffects.Copy : DragDropEffects.None; + e.Effect = ((string[])e.Data.GetData(DataFormats.FileDrop)).Any() + ? DragDropEffects.Copy + : DragDropEffects.None; } else { @@ -236,16 +152,27 @@ private void listViewServers_DragEnter(object sender, DragEventArgs e) } } - private void listViewServers_DragDrop(object sender, DragEventArgs e) + private void listViewServers_KeyDown(object sender, KeyEventArgs e) { - - if (e.Data.GetDataPresent(DataFormats.FileDrop)) + if (SelectedEntry == null) { - var files = e.Data.GetData(DataFormats.FileDrop) as string[]; - if (files != null) + return; + } + + if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back) + { + var selectedServerEntry = SelectedEntry; + + // If we have a server selected, remove it. + if (selectedServerEntry?.InstallationInfo32 == null && + selectedServerEntry?.InstallationInfo64 == null && + selectedServerEntry?.RegistrationInfo32 == null && + selectedServerEntry?.RegistrationInfo64 == null) { - foreach(var file in files) - AddServer(file, true); + RemoveExtensionEntryFromList(selectedServerEntry); + + // Remove from the most recently used files. + RemoveRecentlyUsed(selectedServerEntry?.SharpShellServerInfo?.AssemblyInfo?.AssemblyPath); } } } @@ -255,350 +182,603 @@ private void listViewServers_SelectedIndexChanged(object sender, EventArgs e) // Update the user interface commands. UpdateUserInterfaceCommands(); - // Update the details view with the selected server entry. - serverDetailsView1.Initialise(SelectedServerEntry); + // Update list view + AddOrUpdateEntry(SelectedEntry); } - private void listViewServers_KeyDown(object sender, KeyEventArgs e) + private void loadServerToolStripMenuItem_Click(object sender, EventArgs e) { - if (SelectedServerEntry == null) - return; - - if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back) + // Create a file open dialog. + var fileOpenDialog = new OpenFileDialog { - var selectedServerEntry = SelectedServerEntry; - - // If we have a server selected, remove it. - var item = listViewServers.Items.OfType().FirstOrDefault(li => li.Tag == selectedServerEntry); - if (item != null) - { - listViewServers.Items.Remove(item); + Filter = @"COM Servers (*.dll)|*.dll|All Files (*.*)|*.*" + }; - // Remove from the most recently used files. - if (Properties.Settings.Default.RecentlyUsedFiles != null) - { - Properties.Settings.Default.RecentlyUsedFiles.Remove(selectedServerEntry.ServerPath); - Properties.Settings.Default.Save(); - } - } + if (fileOpenDialog.ShowDialog(this) == DialogResult.OK) + { + // Try and add the server. + AddServersFromFile(fileOpenDialog.FileName); } + } + private void registerServerX64ToolStripMenuItem_Click(object sender, EventArgs e) + { + // Register the server + RegisterServer(SelectedEntry, RegistrationScope.OS64Bit); } - private void clearMostRecentlyUsedServersToolStripMenuItem_Click(object sender, EventArgs e) + private void registerServerX86ToolStripMenuItem_Click(object sender, EventArgs e) { - Properties.Settings.Default.RecentlyUsedFiles.Clear(); - Properties.Settings.Default.Save(); + // Register the server + RegisterServer(SelectedEntry, RegistrationScope.OS32Bit); } - private void exitToolStripMenuItem_Click(object sender, EventArgs e) + private void reportABugToolStripMenuItem_Click(object sender, EventArgs e) { - Close(); + Process.Start(Resources.UrlReportABug); } - private void installServerx64ToolStripMenuItem_Click(object sender, EventArgs e) + private void requestAFeatureToolStripMenuItem_Click(object sender, EventArgs e) { - // Get the selected server. - var selectedServer = SelectedServerEntry; - if (selectedServer == null) - return; + Process.Start(Resources.URlSuggestAFeature); + } - ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true); - serverDetailsView1.Initialise(SelectedServerEntry); + private void restartExplorerToolStripMenuItem_Click(object sender, EventArgs e) + { + ExplorerManager.RestartExplorer(); } - private void uninstallServerx64ToolStripMenuItem_Click(object sender, EventArgs e) + + private void ServerManagerForm_Shown(object sender, EventArgs e) { - // Bail if we have no server selected. - if (SelectedServerEntry == null) - return; + PrepareServerList(); + } - ServerRegistrationManager.UninstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit); - serverDetailsView1.Initialise(SelectedServerEntry); + private void sharpShellProjectHomePageToolStripMenuItem_Click(object sender, EventArgs e) + { + Process.Start(Resources.UrlSharpShellProjectHomePage); } - private void CheckIfRegisterOrUnregisterRequiresExplorerRestart(ISharpShellServer server) + private void testServerToolStripMenuItem_Click(object sender, EventArgs e) { - if (server.ServerType == ServerType.ShellIconOverlayHandler) - { - if (MessageBox.Show(this, "This change will not take effect until Windows Explorer is restarted. Would you " + - "like to restart Windows Explorer now?", "Restart Explorer?", MessageBoxButtons.YesNo, - MessageBoxIcon.Question) == DialogResult.Yes) - { - ExplorerManager.RestartExplorer(); - } - } + // Call the test server command. + DoTestServer(); } - private void CheckIfRegisterOrUnregisterRequiresExplorerRestart(ISharpShellServer[] servers) + private void toolStripButtonAttachDebugger_Click(object sender, EventArgs e) { - if (servers.Any(server => server.ServerType == ServerType.ShellIconOverlayHandler)) - { - if (MessageBox.Show(this, "This change will not take effect until Windows Explorer is restarted. Would you " + - "like to restart Windows Explorer now?", "Restart Explorer?", MessageBoxButtons.YesNo, - MessageBoxIcon.Question) == DialogResult.Yes) - { - ExplorerManager.RestartExplorer(); - } - } + Debugger.Launch(); } - private void registerServerx86ToolStripMenuItem_Click(object sender, EventArgs e) + private void toolStripButtonOpenShellDialog_Click(object sender, EventArgs e) { - // Bail if we have no server selected. - if (SelectedServerEntry == null) - return; + // Show a shell dialog. + new OpenFileDialog().ShowDialog(this); + } - // Register the server, x86 mode. - ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS32Bit); - serverDetailsView1.Initialise(SelectedServerEntry); - CheckIfRegisterOrUnregisterRequiresExplorerRestart(SelectedServerEntry.Server); + private void toolStripButtonOpenTestShell_Click(object sender, EventArgs e) + { + new TestShellForm().ShowDialog(this); } - private void registerServerx64ToolStripMenuItem_Click(object sender, EventArgs e) + private void toolStripButtonShellDebugger_Click(object sender, EventArgs e) { - // Bail if we have no server selected. - if (SelectedServerEntry == null) - return; + // Create and show a new shell debugger. + new ShellDebuggerForm().ShowDialog(this); + } - // Register the server, x64 mode. - ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit); - serverDetailsView1.Initialise(SelectedServerEntry); - CheckIfRegisterOrUnregisterRequiresExplorerRestart(SelectedServerEntry.Server); + private void toolStripButtonTestServer_Click(object sender, EventArgs e) + { + // Call the test server command. + DoTestServer(); } - private void unregisterServerx86ToolStripMenuItem_Click(object sender, EventArgs e) + private void uninstallServerX64ToolStripMenuItem_Click(object sender, EventArgs e) { - // Bail if we have no server selected. - if (SelectedServerEntry == null) - return; + // Uninstall the server. + UninstallServer(SelectedEntry, RegistrationScope.OS64Bit); + } - // Unregister the server, x86 mode. - ServerRegistrationManager.UnregisterServer(SelectedServerEntry.Server, RegistrationType.OS32Bit); - serverDetailsView1.Initialise(SelectedServerEntry); - CheckIfRegisterOrUnregisterRequiresExplorerRestart(SelectedServerEntry.Server); + private void uninstallServerX86ToolStripMenuItem_Click(object sender, EventArgs e) + { + // Uninstall the server. + UninstallServer(SelectedEntry, RegistrationScope.OS32Bit); } - private void unregisterServerx64ToolStripMenuItem_Click(object sender, EventArgs e) + + private void uninstallToolStripMenuItem_Click(object sender, EventArgs e) { // Bail if we have no server selected. - if (SelectedServerEntry == null) + if (SelectedEntry?.SharpShellServerInfo?.AssemblyInfo == null) + { return; + } + + var assemblyInfo = SelectedEntry.SharpShellServerInfo.AssemblyInfo; - // Unregister the server, x64 mode. - ServerRegistrationManager.UnregisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit); - serverDetailsView1.Initialise(SelectedServerEntry); - CheckIfRegisterOrUnregisterRequiresExplorerRestart(SelectedServerEntry.Server); + // Inform the user of the result. + if (UninstallAssembly(assemblyInfo)) + { + MessageBox.Show(@"Uninstalled server successfully.", @"Uninstall Server", MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + else + { + MessageBox.Show(@"Failed to uninstall, check the SharpShell log for details.", @"Uninstall Server", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } } - private void restartExplorerToolStripMenuItem_Click(object sender, EventArgs e) + private void unregisterServerX64ToolStripMenuItem_Click(object sender, EventArgs e) { - ExplorerManager.RestartExplorer(); + // Unregister the server + UnregisterServer(SelectedEntry, RegistrationScope.OS64Bit); } - - private void UpdateUserInterfaceCommands() - { - // Install/Uninstall etc etc only available if we have a selection. - installServerx86ToolStripMenuItem.Enabled = SelectedServerEntry != null; - installServerx64ToolStripMenuItem.Enabled = SelectedServerEntry != null; - registerServerx86ToolStripMenuItem.Enabled = SelectedServerEntry != null; - registerServerx64ToolStripMenuItem.Enabled = SelectedServerEntry != null; - unregisterServerx86ToolStripMenuItem.Enabled = SelectedServerEntry != null; - unregisterServerx64ToolStripMenuItem.Enabled = SelectedServerEntry != null; - uninstallServerx86ToolStripMenuItem.Enabled = SelectedServerEntry != null; - uninstallServerx64ToolStripMenuItem.Enabled = SelectedServerEntry != null; - uninstallToolStripMenuItem.Enabled = SelectedServerEntry != null; - installToolStripMenuItem.Enabled = SelectedServerEntry != null; - // Test functions only available for specific servers. - testServerToolStripMenuItem.Enabled = - ( - SelectedServerEntry != null && - ( - SelectedServerEntry.Server is SharpContextMenu || - SelectedServerEntry.Server is SharpIconHandler || - SelectedServerEntry.Server is SharpInfoTipHandler || - SelectedServerEntry.Server is SharpDropHandler || - SelectedServerEntry.Server is SharpPreviewHandler || - SelectedServerEntry.Server is SharpThumbnailHandler || - SelectedServerEntry.Server is SharpIconOverlayHandler - ) - ); - toolStripButtonTestServer.Enabled = testServerToolStripMenuItem.Enabled; + private void unregisterServerX86ToolStripMenuItem_Click(object sender, EventArgs e) + { + // Unregister the server + UnregisterServer(SelectedEntry, RegistrationScope.OS32Bit); } - private void testServerToolStripMenuItem_Click(object sender, EventArgs e) + #endregion + + #region Main Logic + + public IEnumerable Entries { - // Call the test server command. - DoTestServer(); + get + { + return listViewServers.Items + .OfType() + .Select(item => item.ExtensionEntry); + } } - private void toolStripButtonTestServer_Click(object sender, EventArgs e) + public ShellExtensionEntry SelectedEntry { - // Call the test server command. - DoTestServer(); + get => listViewServers.SelectedItems.OfType().FirstOrDefault()?.ExtensionEntry; } /// - /// Tests the selected serer. + /// Tests the selected serer. /// private void DoTestServer() { // If we don't have a server, bail. - if (SelectedServerEntry == null) + if (SelectedEntry == null) + { return; + } + + // TODO // Create a test shell form. - var testShellForm = new TestShellForm { TestServer = SelectedServerEntry.Server }; + //var testShellForm = new TestShellForm { TestServer = SelectedEntry }; // Show the form. - testShellForm.ShowDialog(this); + //testShellForm.ShowDialog(this); } - private void sharpShellProjectHomePageToolStripMenuItem_Click(object sender, EventArgs e) + private void UpdateUserInterfaceCommands() { - Process.Start(Properties.Resources.UrlSharpShellProjectHomePage); + // Install/Uninstall etc etc only available if we have a selection. + installServerx86ToolStripMenuItem.Enabled = SelectedEntry?.SharpShellServerInfo != null; + installServerx64ToolStripMenuItem.Enabled = SelectedEntry?.SharpShellServerInfo != null; + registerServerx86ToolStripMenuItem.Enabled = SelectedEntry?.SharpShellServerInfo != null; + registerServerx64ToolStripMenuItem.Enabled = SelectedEntry?.SharpShellServerInfo != null; + unregisterServerx86ToolStripMenuItem.Enabled = SelectedEntry != null; + unregisterServerx64ToolStripMenuItem.Enabled = SelectedEntry != null; + uninstallServerx86ToolStripMenuItem.Enabled = SelectedEntry != null; + uninstallServerx64ToolStripMenuItem.Enabled = SelectedEntry != null; + installToolStripMenuItem.Enabled = SelectedEntry?.SharpShellServerInfo != null; + uninstallToolStripMenuItem.Enabled = SelectedEntry != null; + + // Get selected managed server type + var serverType = SelectedEntry?.SharpShellServerInfo?.ServerType; + + // Test functions only available for specific servers. + testServerToolStripMenuItem.Enabled = + SelectedEntry != null && + ( + serverType == ServerType.ShellContextMenu || + serverType == ServerType.ShellIconHandler || + serverType == ServerType.ShellInfoTipHandler || + serverType == ServerType.ShellDropHandler || + serverType == ServerType.ShellPreviewHandler || + serverType == ServerType.ShellThumbnailHandler || + serverType == ServerType.ShellIconOverlayHandler + ); + + toolStripButtonTestServer.Enabled = testServerToolStripMenuItem.Enabled; } + + private bool InstallAssembly(ManagedAssemblyInfo assembly, bool codeBase) + { + // Get all server types + var servers = SharpShellServerInfo.FromAssembly(assembly).ToArray(); - private void reportABugToolStripMenuItem_Click(object sender, EventArgs e) + var registrationScope = Environment.Is64BitOperatingSystem + ? RegistrationScope.OS64Bit + : RegistrationScope.OS32Bit; + + var success = true; + + foreach (var server in servers) + { + try + { + ServerRegistrationManager.InstallServer(server, registrationScope, codeBase); + ServerRegistrationManager.RegisterAndApproveServer(server, registrationScope); + } + catch (Exception exception) + { + Logging.Error($"Failed to uninstall and unregister a server. [{server.DisplayName}]", exception); + success = false; + } + + AddOrUpdateEntry(new ShellExtensionEntry(server)); + } + + CheckIfRegisterOrUnregisterRequiresExplorerRestart(servers); + + return success; + } + + private bool UninstallAssembly(ManagedAssemblyInfo assemblyInfo) { - Process.Start(Properties.Resources.UrlReportABug); + // Get all server types + var servers = SharpShellServerInfo.FromAssembly(assemblyInfo).ToArray(); + + var registrationScope = Environment.Is64BitOperatingSystem + ? RegistrationScope.OS64Bit + : RegistrationScope.OS32Bit; + + var success = true; + + foreach (var server in servers) + { + try + { + ServerRegistrationManager.UnregisterAndUnApproveServer(server, registrationScope); + ServerRegistrationManager.UninstallServer(server, registrationScope); + } + catch (Exception exception) + { + Logging.Error($"Failed to uninstall and unregister a server. [{server.DisplayName}]", exception); + success = false; + } + + AddOrUpdateEntry(new ShellExtensionEntry(server)); + } + + CheckIfRegisterOrUnregisterRequiresExplorerRestart(servers); + + return success; + } + + private void RemoveRecentlyUsed(string filePath) + { + if (Settings.Default.RecentlyUsedFiles != null && !string.IsNullOrEmpty(filePath)) + { + Settings.Default.RecentlyUsedFiles.Remove(filePath); + Settings.Default.Save(); + } } - private void requestAFeatureToolStripMenuItem_Click(object sender, EventArgs e) + private void AddRecentlyUsed(string filePath) { - Process.Start(Properties.Resources.URlSuggestAFeature); + if (Settings.Default.RecentlyUsedFiles == null) + { + Settings.Default.RecentlyUsedFiles = new StringCollection(); + } + + if (!string.IsNullOrEmpty(filePath) && + !Settings.Default.RecentlyUsedFiles.Contains(filePath)) + { + Settings.Default.RecentlyUsedFiles.Insert(0, filePath); + Settings.Default.Save(); + } } - private void aboutToolStripMenuItem_Click(object sender, EventArgs e) + private void ClearRecentlyUsed() { - (new AboutForm()).ShowDialog(this); + if (Settings.Default.RecentlyUsedFiles != null) + { + Settings.Default.RecentlyUsedFiles.Clear(); + Settings.Default.Save(); + } } - - private void toolStripButtonOpenTestShell_Click(object sender, EventArgs e) + + private bool InstallServer(ShellExtensionEntry entry, RegistrationScope registrationScope) { - (new TestShellForm()).ShowDialog(this); + if (entry?.SharpShellServerInfo?.AssemblyInfo == null) + { + return false; + } + + var codeBase = !string.IsNullOrEmpty(entry?.SharpShellServerInfo?.AssemblyInfo?.AssemblyPath); + + ServerRegistrationManager.InstallServer(entry.SharpShellServerInfo, registrationScope, codeBase); + + if (registrationScope == RegistrationScope.OS64Bit) + { + entry.UpdateInstallationInfo64(); + } + else + { + entry.UpdateInstallationInfo32(); + } + + AddOrUpdateEntry(entry); + + return true; } - private void toolStripButtonOpenShellDialog_Click(object sender, EventArgs e) + private bool UninstallServer(ShellExtensionEntry entry, RegistrationScope registrationScope) { - // Show a shell dialog. - var openFileDialog = new OpenFileDialog(); - openFileDialog.ShowDialog(this); + if (entry == null) + { + return false; + } + + ServerRegistrationManager.UninstallServer(entry.ServerClassId, registrationScope); + + if (registrationScope == RegistrationScope.OS64Bit) + { + entry.UpdateInstallationInfo64(); + } + else + { + entry.UpdateInstallationInfo32(); + } + + AddOrUpdateEntry(entry); + + return true; } - private void toolStripButtonShellDebugger_Click(object sender, EventArgs e) + private bool RegisterServer(ShellExtensionEntry entry, RegistrationScope registrationScope) { - // Create and show a new shell debugger. - var debugger = new ShellDebuggerForm(); - debugger.ShowDialog(this); + if (entry?.SharpShellServerInfo == null) + { + return false; + } + + ServerRegistrationManager.RegisterAndApproveServer(entry.SharpShellServerInfo, registrationScope); + + if (registrationScope == RegistrationScope.OS64Bit) + { + entry.UpdateRegistrationInfo64(); + } + else + { + entry.UpdateRegistrationInfo32(); + } + + AddOrUpdateEntry(entry); + + CheckIfRegisterOrUnregisterRequiresExplorerRestart(SelectedEntry?.SharpShellServerInfo); + + return true; } - private void toolStripButtonAttachDebugger_Click(object sender, EventArgs e) + private bool UnregisterServer(ShellExtensionEntry entry, RegistrationScope registrationScope) { - Debugger.Launch(); + if (entry == null) + { + return false; + } + + if (entry.SharpShellServerInfo == null) + { + ServerRegistrationManager.UnregisterAndUnApproveServer(entry.ServerClassId, registrationScope); + } + else + { + ServerRegistrationManager.UnregisterAndUnApproveServer(entry.SharpShellServerInfo, registrationScope); + } + + if (registrationScope == RegistrationScope.OS64Bit) + { + entry.UpdateRegistrationInfo64(); + } + else + { + entry.UpdateRegistrationInfo32(); + } + + AddOrUpdateEntry(entry); + + CheckIfRegisterOrUnregisterRequiresExplorerRestart(SelectedEntry?.SharpShellServerInfo); + + return true; } - private void installToolStripMenuItem_Click(object sender, EventArgs e) + public void PrepareServerList() { - // Bail if we have no server selected. - if (string.IsNullOrWhiteSpace(SelectedServerEntry?.ServerPath)) - return; + // Add the recently used servers. If any of them fail to load, we'll remove them from the list. + var recentlyUsedFilesToRemove = new List(); - // Get all server types - var serverEntries = AllServerEntries.Where(entry => - !string.IsNullOrWhiteSpace(entry.ServerPath) && - Path.GetFullPath(entry.ServerPath).Equals( - Path.GetFullPath(SelectedServerEntry.ServerPath), - StringComparison.InvariantCultureIgnoreCase - ) - ).ToArray(); + if (Settings.Default.RecentlyUsedFiles != null) + { + foreach (var path in Settings.Default.RecentlyUsedFiles) + { + if (!AddServersFromFile(path)) + { + recentlyUsedFilesToRemove.Add(path); + } + } + } + + foreach (var fileToRemove in recentlyUsedFilesToRemove) + { + Settings.Default.RecentlyUsedFiles?.Remove(fileToRemove); + } - var registrationType = - Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit; + Settings.Default.Save(); - var success = true; + // Check for any servers added via the command line. + var arguments = Environment.GetCommandLineArgs(); - foreach (var serverEntry in serverEntries) + for (var i = 1; i < arguments.Length; i++) { - try + var arg = arguments[i]; + + if (File.Exists(arg)) { - ServerRegistrationManager.InstallServer(serverEntry.Server, registrationType, true); - ServerRegistrationManager.RegisterServer(serverEntry.Server, registrationType); + AddServersFromFile(arg); } - catch (Exception exception) + } + + var _ = StartBlockingAction(() => + { + foreach (var shellExtensionEntry in ShellExtensionEntry.GetRegisteredEntries()) { - Logging.Error($"Failed to install and register a server. [{serverEntry.ServerName}]", exception); - success = false; + Invoke(new Action(() => + { + AddOrUpdateEntry(shellExtensionEntry); + })); } + }); + } - serverDetailsView1.Initialise(serverEntry); + private async Task StartBlockingAction(Action action) + { + splitContainer.Enabled = false; + toolStrip.Enabled = false; + menuStrip.Enabled = false; + statusStrip.Enabled = false; + panelPleaseWait.Visible = true; + + try + { + await Task.Factory.StartNew(action).ConfigureAwait(true); } + finally + { + panelPleaseWait.Visible = false; - CheckIfRegisterOrUnregisterRequiresExplorerRestart(serverEntries.Select(entry => entry.Server).ToArray()); + splitContainer.Enabled = true; + toolStrip.Enabled = true; + menuStrip.Enabled = true; + statusStrip.Enabled = true; + } + } - // Inform the user of the result. - if (success) + public bool AddServersFromFile(string path) + { + if (Entries.Any(se => se.ServerPath == path)) { - MessageBox.Show(@"Installed server successfully.", @"Install Server", MessageBoxButtons.OK, - MessageBoxIcon.Information); + return true; } - else + + try { - MessageBox.Show(@"Failed to install, check the SharpShell log for details.", @"Install Server", MessageBoxButtons.OK, - MessageBoxIcon.Error); + // Load any servers from the assembly. + var servers = SharpShellServerInfo.FromExternalAssemblyFile(path); + + foreach (var server in servers) + { + AddOrUpdateEntry(new ShellExtensionEntry(server)); + } + } + catch + { + MessageBox.Show($@"The file \'{Path.GetFileName(path)}\' is not a SharpShell Server.", @"Warning"); + + return false; } + + // We've successfully added the server - so add the path of the server to our recent files. + AddRecentlyUsed(path); + + return true; } - private void uninstallToolStripMenuItem_Click(object sender, EventArgs e) + public void AddOrUpdateEntry(ShellExtensionEntry extensionEntry) { - // Bail if we have no server selected. - if (string.IsNullOrWhiteSpace(SelectedServerEntry?.ServerPath)) + if (extensionEntry == null) + { + serverDetailsView.ExtensionEntry = null; + return; + } - // Get all server types - var serverEntries = AllServerEntries.Where(entry => - !string.IsNullOrWhiteSpace(entry.ServerPath) && - Path.GetFullPath(entry.ServerPath).Equals( - Path.GetFullPath(SelectedServerEntry.ServerPath), - StringComparison.InvariantCultureIgnoreCase - ) - ).ToArray(); + if (extensionEntry.InstallationInfo32 == null && + extensionEntry.InstallationInfo64 == null && + extensionEntry.RegistrationInfo32 == null && + extensionEntry.RegistrationInfo64 == null && + extensionEntry.SharpShellServerInfo == null) + { + RemoveExtensionEntryFromList(extensionEntry); + serverDetailsView.ExtensionEntry = null; - var registrationType = - Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit; + return; + } - var success = true; + var listViewItem = listViewServers.Items + .Cast() + .FirstOrDefault(item => + item.ExtensionEntry?.ServerClassId == extensionEntry.ServerClassId + ); - foreach (var serverEntry in serverEntries) + + if (listViewItem == null) { - try + listViewItem = new ServerListViewItem(extensionEntry); + listViewServers.Items.Add(listViewItem); + } + else + { + listViewItem.ExtensionEntry = extensionEntry; + listViewServers.Refresh(); + } + + if (!listViewServers.SelectedItems.Contains(listViewItem)) + { + if (listViewServers.SelectedIndices.Count > 0) { - ServerRegistrationManager.UnregisterServer(serverEntry.Server, registrationType); - ServerRegistrationManager.UninstallServer(serverEntry.Server, registrationType); + listViewServers.SelectedIndices.Clear(); } - catch (Exception exception) + + var itemIndex = listViewServers.Items.IndexOf(listViewItem); + + if (itemIndex >= 0) { - Logging.Error($"Failed to uninstall and unregister a server. [{serverEntry.ServerName}]", exception); - success = false; + listViewServers.SelectedIndices.Add(itemIndex); } - - serverDetailsView1.Initialise(serverEntry); } - - CheckIfRegisterOrUnregisterRequiresExplorerRestart(serverEntries.Select(entry => entry.Server).ToArray()); - // Inform the user of the result. - if (success) - { - MessageBox.Show(@"Uninstalled server successfully.", @"Uninstall Server", MessageBoxButtons.OK, - MessageBoxIcon.Information); - } - else + // Update the details view with the selected server entry. + serverDetailsView.ExtensionEntry = extensionEntry; + } + + public void RemoveExtensionEntryFromList(ShellExtensionEntry extensionEntry) + { + var listViewItem = listViewServers.Items + .Cast() + .FirstOrDefault(item => + item.ExtensionEntry?.ServerClassId == extensionEntry.ServerClassId + ); + + if (listViewItem != null) { - MessageBox.Show(@"Failed to uninstall, check the SharpShell log for details.", @"Uninstall Server", MessageBoxButtons.OK, - MessageBoxIcon.Error); + if (listViewServers.SelectedItems.OfType().Contains(listViewItem)) + { + listViewServers.SelectedIndices.Clear(); + } + + if (serverDetailsView.ExtensionEntry == extensionEntry) + { + serverDetailsView.ExtensionEntry = null; + } + + listViewServers.Items.Remove(listViewItem); } } + + #endregion } -} +} \ No newline at end of file diff --git a/SharpShell/Tools/ServerManager/ServerManagerForm.resx b/SharpShell/Tools/ServerManager/ServerManagerForm.resx index 35c12f4e..98298a40 100644 --- a/SharpShell/Tools/ServerManager/ServerManagerForm.resx +++ b/SharpShell/Tools/ServerManager/ServerManagerForm.resx @@ -117,7 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 443, 17 @@ -127,119 +127,121 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACs - FwAAAk1TRnQBSQFMAgEBBQEAAaABAQGgAQEBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABIAMAAQEBAAEgBgABIDIAAw4BEwNIAYUDXQHTA2IB9gNdAdMDSAGGAw8BFMgAAZsBVAE5Af8BgAEw - AREB/wFoAS8BDwH/AWgBLQENAf8BZwErAQsB/wFmASkBCAH/AWQBKQEKAf8BgQFYAU8B/wHBAaYBnwH/ - AcQBXQFHAf8BoQFDASwB/wGuAVYBQgH/AcMBpQGfAf8BgAFVAUsB/wMPARTEAAGeAVgBPQH/AYsB0AGY - Af8BiQHRAZgB/wFfAcUBiAH/AUgBtwFdAf8BMgGpAUwB/wFEAYwBUQH/AcEBqQGhAf8BsgExAQ4B/wHL - AYsBXgH/AfgC9wH/AbABSwE2Af8BvwEtAQ8B/wHCAaUBnwH/A0gBhsQAAaIBXgFEAf8BugHmAcIB/wGn - AeABsgH/AZIB1wGfAf8BZgHJAY4B/wFOAboBYwH/AYYBlAGHAf8ByAFlAUgB/wGwAS8BCQH/AcsBiwFf - Af8B5wHoAekB/wGwAVIBPgH/AbcBKAEGAf8BvQFTAToB/wNdAdPEAAGnAWQBSwH/AaQB3gGvAf8B0QHv - AdYB/wGnAeABsgH/AY0B1AGbAf8BYAHFAYkB/wKVAZIB/wHNAVYBMQH/AckBSwEkAf8BzwGRAWQB/wHo - AekB6gH/AbIBWQFDAf8BsAEpAQQB/wGuATIBEAH/A2IB9sQAAawBgwFTAf8BmwGkAYUB/wGnAeABsgH/ - AdEB7wHWAf8BpwHgAbIB/wGJAdEBmAH/AYwBlwGNAf8B1gGPAVsB/wHWAVoBMQH/AdoBkQFfAf8B8wHM - Ab0B/wG8AU0BLQH/AbQBNQEPAf8BvAFbAT8B/wNdAdPEAAGyAYsBXAH/Ae0B4wHdAf8BmwGeAYIB/wGl - Ad8BsAH/AdAB7gHWAf8BpQHeAbAB/wFoAaIBhgH/AckBsgGqAf8B5AGAAUAB/wHvAY0BTwH/AfoB7wHo - Af8B5QGAAUIB/wHNAVYBLgH/AcQBrAGjAf8DSAGFxAABuAGSAWUC/wH8AfsB/wHtAeMB3QH/AZsBggFa - Af8BpgHeAbAB/wGxAeIBugH/AVEBSAE1Af8BlgGMAYcB/wHJAbIBqwH/AegBngFnAf8B8gGjAYMB/wHj - AZABVwH/AcYBrgGmAf8BgQFYAU8B/wMOARPEAAG9AZoBhAL/AfwB+wL/AfwB+wH/AekB3gHYAf8BmwGC - AVoB/wGbAYIBWgH/Ae4B1gHJAf8B8gHWAcgB/wG7AagBnwH/AaQBmgGWAf8BmgGVAZQB/wGkAZgBkwH/ - AZ8BjgGGAf8BZAEpAQoB/8gAAcIBoAGLAv8B/AH7Av8B/AH7Av8B/AH7Av8B+AH1Af8B/gHzAe0B/wH+ - Ae0B5AH/AdQBxQHSAf8BCQE8AcsB/wEIAToBxgH/AdEBsQGvAf8B/AHKAbAB/wHKAacBlQH/AWYBKQEI - Af/IAAHGAaYBkgL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfgB9QH/Af4B8wHtAf8BGQFHAdQB/wFb - Ab4B+QH/AS0BjAHLAf8BCAE6AcYB/wH8AdABuQH/AdIBrQGaAf8BZwErAQsB/8gAAckBqgGWAv8B/AH7 - Av8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B+AH1Af8BGgFJAdcB/wG5AeQC/wFbAb4B+QH/AQkBPAHL - Af8B/QHXAcMB/wHZAbMBnwH/AWgBLQENAf/IAAHJAaoBlgL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/ - AfwB+wL/AfwB+wH/AdcB1AHsAf8BGgFJAdcB/wEZAUgB1AH/AdQBxQHSAf8B/QHfAc8B/wHeAbcBowH/ - AWgBLwEPAf/IAAHJAaoBlgL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/ - AfgB9QH/Af4B8wHtAf8B/gHtAeQB/wH9AeYB2gH/Af0B3wHPAf8BgAEwAREB/8gAAckBqgGWAf8ByQGq - AZYB/wHJAaoBlgH/AckBqgGWAf8BxgGmAZIB/wHCAaABiwH/Ab0BmgGEAf8BuAGSAWUB/wGyAYsBXAH/ - AawBgwFTAf8BpwFkAUsB/wGiAV4BRAH/AZ4BWAE9Af8BmwFUATkB//8A/wCOAAG6AaEBkgH/Aa0BlwGI - Af8BpgGQAYAB/wGfAYgBVgH/AZkBggFPAf8BkwFaAUgB/wGMAVIBQQH/AYYBSwE5Af8BXQFEATEB/wFW - AT0BKgH/AVABNgEiAf8BSgEwARsB/wFFASoBFgH/AUIBJwERAf9EAAGbATcBHAH/AYABEwEAAf8BSwES - AQAB/wFLARABAAH/AUoBDgEAAf8BSQEMAQAB/wFIAQkBAAH/AUcBBwEAAf8BRgEEAQAB/wFFAQEBAAH/ - AUQCAAH/AUMCAAH/AUMCAAH/AUICAAH/TAABvQGmAZgB/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEA - A/8BAAP/AQAD/wEAA/8BAAP/AQAD/wFIAS4BGQH/BAADYgHvAZkBqAGsAf8BmQGoAawB/wGZAagBrAH/ - AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGsAf8BmQGo - AawB/wNcAc8MAAGeATsBIAH/AYsB0AGYAf8BiQHRAZgB/wFCAcUBiAH/ASsBtwFAAf8BFQGpAS8B/wEA - AZwBHQH/AQABjwENAf8BAAGIAQMB/wEAAYgBAwH/AQABiAEDAf8BAAFFAQIB/wEZAQYBAAH/AUMCAAH/ - CAADKgFAAZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/AZwBmwGR - Af8BnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/A0cBgAwAAcIBqgGdAf8BAAP/ - Af0BkgE8Af8B7QGHATIB/wHZAVgBKwH/AccBTQEiAf8BswFAARgB/wGmATYBEQH/AQAD/wH9AZIBPAH/ - Ae0BhwEyAf8B2QFYASsB/wEAA/8BUQE4ASMB/wQAA2IB7wHyAfQB9Qn/A90B/wPOAf8DzgH/A+cN/wHm - AekB6gH/A1wBzwwAAaIBQQEnAf8BugHmAcIB/wGnAeABsgH/AZIB1wGfAf8BSQHJAY4B/wExAboBRgH/ - ARoBrAEyAf8BAQGcAR0B/wEAAY4BDAH/AQABiAEDAf8BDwElAQEB/wE6ASUBFgH/AS8BGgELAf8BQwIA - Af8IAAMqAUABzQHMAccB/wH+AvwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+ - AvwB/wH+AvwB/wH+AvwB/wHmAeQB4QH/A0cBgAwAAcUBrgGjAf8BAAP/AQAD/wMAAf8DAAH/AwAB/wEA - A/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BXAFDAS8B/wQAA2IB7wHyAfQB9QX/AdoB0QHJAf8BoQGN - AUkB/wEBAgAB/wEeARkBFAH/AYUBPwExAf8BPgEkARAB/wGjAZIBhQX/AeYB6QHqAf8DXAHPDAABpwFH - AS4B/wGkAd4BrwH/AdEB7wHWAf8BpwHgAbIB/wGNAdQBmwH/AUMBxQGJAf8BKwG2AUEB/wEUAagBLQH/ - AQABlQEWAf8BGwEVAQAB/wGSAUgBOwH/AY0BRAE2Af8DAAH/AUQCAAH/CAADKgFAAc0BzAHHAf8B8wL2 - Af8B7wHzAfQB/wHvAfQB9QH/Ae8B9AH1Af8B7wHzAfUB/wHwAvQB/wHwAfQB9QH/Ae8B9AH1Af8B7wL0 - Af8B7wHzAfUB/wHmAeQB4QH/A0cBgAwAAckBtAGoAf8BxAGtAaEB/wHAAagBmwH/AwAF/wMAAf8BrQGV - AYQB/wGpAZABXQH/AaQBiwFXAf8BnwGEAVEB/wGaAV0BSwH/AZYBWQFHAf8BlQFYAUUB/wGVAVgBRQH/ - BAADYgLvAvAF/wGqAZgBiQH/AdsB1AHOAf8DLAH/A0AB/wPnDf8B5gHpAeoB/wNcAc8MAAGsAYMBNgH/ - AZsBpAGFAf8BpwHgAbIB/wHRAe8B1gH/AacB4AGyAf8BiQHRAZgB/wE9AcEBhAH/ASEBsAE4Af8BLQE6 - AR4B/wG/AasBoQH/AbMBnQGQAf8DAAH/Aa4BkQGDAf8BRQEBAQAB/wgAAyoBQAHNAcwBxwH/AfQB9wH4 - Af8B8QH0AfUB/wHxAvUB/wHxAvUB/wHxAfQB9QH/AfEB9QH2Af8B8QL1Af8B8QH1AfYB/wHxAfQB9QH/ - AfEB9QH2Af8B5gHkAeEB/wNHAYAXAAX/AwAB/ygAA2IB7wHGAcMBwQH/A84B/wGdAYsBSQH/AdsB1AHO - Af8DLAH/AR4BGQEUAf8BhQE/ATEB/wE+ASQBEAH/AaMBkgGFBf8B5gHpAeoB/wNcAc8MAAGyAYsBPwH/ - Ae0B4wHdAf8BmwGeAYIB/wGlAd8BsAH/AdAB7gHWAf8BpQHeAbAB/wFLAcsBjwH/ATQBRAEmAf8BzwG8 - AbIB/wHTAcEBtwH/AwAB/wHsAbYBmQH/AbQBlgGHAf8BRgEEAQAB/wgAAyoBQAHNAcwBxwH/AfYB9wH4 - Af8B8wH2AfcB/wHzAfYB9wH/AfMB9gH3Af8B8wH2AfcB/wHzAfUB9gH/AfMB9gH3Af8B9AH2AfcB/wHz - AvYB/wHzAfYB9wH/AeYB5AHhAf8DRwGACwAB/wsABf8DAAH/KAADYgHvAwAB/wMAAf8DvwH/AxwB/wOB - Af8DzgH/A+cN/wHmAekB6gH/A1wBzwwAAbgBkgFIAv8B/AH7Af8B7QHjAd0B/wGbAYIBPQH/AaYB3gGw - Af8BsQHiAboB/wE0ASoBFgH/Ac4BrgGbAf8BMQEbAQsB/wExARsBCwH/AdgBsAGZAf8B+wHBAaIB/wG7 - AZsBjAH/AUcBBwEAAf8IAAMqAUABzQHMAccB/wH3AfgB+QH/AfYC9wH/AfUC9wH/AfUB9wH4Af8B9gH3 - AfgB/wH1AvcB/wH1AfYB+AH/AfUB9wH4Af8B9QH3AfgB/wH1AvcB/wHmAeQB4QH/A0cBgAsAAf8DAAH/ - AwAF/wMAAf8sAANiAe8B8QHuAesJ/wMcAf8DAAH/AwAB/wEkAR0BFwH/AZEBSgE6Af8BowGSAYUF/wHm - AekB6gH/A1wBzwwAAb0BmgGEAv8B/AH7Av8B/AH7Af8B6QHeAdgB/wGbAYIBPQH/AZsBggE9Af8B7gHW - AckB/wH9Ad8BzwH/Af0B1wHDAf8B/AHQAbkB/wH8AcoBsAH/AfsBxQGoAf8BwgGhAZAB/wFIAQkBAAH/ - CAADKgFAAc0BzAHHAf8C+QH6Af8B9wH4AfkB/wH2AfgB+QH/AfcB+AH5Af8B9wH4AfkB/wH3AvgB/wH3 - AfgB+QH/AfcB+AH5Af8B9wH4AfkB/wH3AfgB+QH/AeYB5AHhAf8DRwGACwAN/wMAAf8DAAH/AwAB/yQA - A2IB7wHxAe4B6w3/AywB/wOPEf8B5gHpAeoB/wNcAc8MAAHCAaABiwL/AfwB+wL/AfwB+wL/AfwB+wL/ - AfgB9QH/Af4B8wHtAf8B/gHtAeQB/wHUAcUB0gH/AQABHwHLAf8BAAEdAcYB/wHRAbEBrwH/AfwBygGw - Af8BygGnAZUB/wFJAQwBAAH/CAADKgFAAc0BzAHHAf8B+gH7AfoB/wH5AfoB+QH/A/kB/wH5AvoB/wL5 - AfoB/wL5AfoB/wH4AvkB/wH5AvoB/wP5Af8B+AH5AfoB/wHmAeQB4QH/A0cBgAsAEf8DAAH/KAADYgHv - AfEB7gHrCf8DHAH/AUMBOwE0Af8BnQGKAUcB/wFJATEBHQH/AT4BIwEPAf8BowGSAYUF/wHmAekB6gH/ - A1wBzwwAAcYBpgGSAv8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B+AH1Af8B/gHzAe0B/wEAASoB1AH/ - AT4BvgH5Af8BEAGMAcsB/wEAAR0BxgH/AfwB0AG5Af8B0gGtAZoB/wFKAQ4BAAH/CAADKgFAAc0BzAHH - Af8B/AL7Af8B+wH6AfsB/wP7Af8B/QH7AfwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+AvwB/wH+ - AvwB/wHmAeQB4QH/A0cBgAsADf8DAAH/LAADYgHvAfEB7gHrBf8DDAH/A68Z/wHmAekB6gH/A1wBzwwA - AckBqgGWAv8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B+AH1Af8BAAEsAdcB/wG5AeQC/wE+ - Ab4B+QH/AQABHwHLAf8B/QHXAcMB/wHZAbMBnwH/AUsBEAEAAf8IAAMqAUABzQHMAccB/wH9AfwB+wH/ - AvwB+wH/Af0C/AH/Af4C/AH/AbUBswGsAf8BnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wGc - AZsBkQH/A1kBvw8ACf8DAAH/MAADYgHvAfEB7gHrAf8DAAH/AZsBkQGKAf8BrQGZAYsB/wGWAUsBOQH/ - AYoBPgEsAf8BSQEwAR4B/wE9ASMBEAH/AaMBkgGFBf8B5gHpAeoB/wNcAc8MAAHJAaoBlgL/AfwB+wL/ - AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wH/AdcB1AHsAf8BAAEsAdcB/wEAASsB1AH/AdQBxQHS - Af8B/QHfAc8B/wHeAbcBowH/AUsBEgEAAf8IAAMqAUABpgHAAcUB/wGvAeQB+QH/Aa8B5AH5Af8BrwHk - AfkB/wGvAeQB+QH/AaEBrQGrAf8B9gH3AfgB/wH2AfcB+AH/AfYC+AH/AfYB9wH4Af8B9gH3AfgB/wNZ - Ab8PAAX/AwAB/zQAA2IB7wMAAf8DzyH/AeYB6QHqAf8DXAHPDAAByQGqAZYC/wH8AfsC/wH8AfsC/wH8 - AfsC/wH8AfsC/wH8AfsC/wH8AfsC/wH8AfsC/wH4AfUB/wH+AfMB7QH/Af4B7QHkAf8B/QHmAdoB/wH9 - Ad8BzwH/AYABEwEAAf8IAAMqAUABggG3AccB/wEzAdIB/AH/ATMB0gH8Af8BMwHSAfwB/wEzAdIB/AH/ - AY8BqQGsAf8BtAGnAZEB/wG0AacBkQH/AbQBpwGRAf8BtAGnAZEB/wG0AacBkQH/EwAB/wMAAf84AANi - Ae8BmAGiAaMB/wGZAagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGsAf8BmQGoAawB/wGZ - AagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/A1wBzwwAAckBqgGWAf8ByQGqAZYB/wHJAaoBlgH/ - AckBqgGWAf8BxgGmAZIB/wHCAaABiwH/Ab0BmgGEAf8BuAGSAUgB/wGyAYsBPwH/AawBgwE2Af8BpwFH - AS4B/wGiAUEBJwH/AZ4BOwEgAf8BmwE3ARwB/wwAA0cBgAGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wGc - AZsBkQH/AyoBQCcAAf//ADkAAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/8BAAH/ - AQEGAAGABwABgAcAAYAHAAGABwABgAcAAYAHAAGABwABgAEBBgABgAEBBgABgAEBBgABgAEBBgABgAEB - BgABgAEBBgABgAEBBgAC/wYABv8BwAEAAv8BgAEBAv8BwAEAAYABAwGAAQEBgAEBAcABAAGAAQMBgAEB - AYABAQHAAQABgAEDAYABAQGAAQEBwAEAAYABAwGAAQEBgAEBAfEB/wGAAQMBgAEBAYABAQGxAf8BgAED - AYABAQGAAQEBgwH/AYABAwGAAQEBgAEBAYAB/wGAAQMBgAEBAYABAQGBAf8BgAEDAYABAQGAAQEBgwH/ - AYABAwGAAQEBgAEDAYcB/wGAAQMBgAEBAYABAwGPAf8BgAEDAYABAQGAAQcBnwH/AYABAwGAAQEBwAH/ - Ab8J/ws= + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACY + FwAAAk1TRnQBSQFMAgEBBQEAAegBAQHoAQEBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABIAMAAQEBAAEgBgABIDIAAw4BEwNIAYUDXQHTA2IB9gNdAdMDSAGGAw8BFMgAAZsBSwEwAf8BgAEn + AQgB/wFfASYBBgH/AV8BJAEEAf8BXgEiAQIB/wFdASABAAH/AVsBIAEBAf8BgQFPAUYB/wHBAaYBnwH/ + AcQBVAE+Af8BoQE6ASMB/wGuAU0BOQH/AcMBpQGfAf8BgAFMAUIB/wMPARTEAAGeAU8BNAH/AYsB0AGY + Af8BiQHRAZgB/wFWAcUBiAH/AT8BtwFUAf8BKQGpAUMB/wE7AYwBSAH/AcEBqQGhAf8BsgEoAQUB/wHL + AYsBVQH/AfgC9wH/AbABQgEtAf8BvwEkAQYB/wHCAaUBnwH/A0gBhsQAAaIBVQE7Af8BugHmAcIB/wGn + AeABsgH/AZIB1wGfAf8BXQHJAY4B/wFFAboBWgH/AYYBlAGHAf8ByAFcAT8B/wGwASYBAAH/AcsBiwFW + Af8B5wHoAekB/wGwAUkBNQH/AbcBHwEAAf8BvQFKATEB/wNdAdPEAAGnAVsBQgH/AaQB3gGvAf8B0QHv + AdYB/wGnAeABsgH/AY0B1AGbAf8BVwHFAYkB/wKVAZIB/wHNAU0BKAH/AckBQgEbAf8BzwGRAVsB/wHo + AekB6gH/AbIBUAE6Af8BsAEgAQAB/wGuASkBBwH/A2IB9sQAAawBgwFKAf8BmwGkAYUB/wGnAeABsgH/ + AdEB7wHWAf8BpwHgAbIB/wGJAdEBmAH/AYwBlwGNAf8B1gGPAVIB/wHWAVEBKAH/AdoBkQFWAf8B8wHM + Ab0B/wG8AUQBJAH/AbQBLAEGAf8BvAFSATYB/wNdAdPEAAGyAYsBUwH/Ae0B4wHdAf8BmwGeAYIB/wGl + Ad8BsAH/AdAB7gHWAf8BpQHeAbAB/wFfAaIBhgH/AckBsgGqAf8B5AGAATcB/wHvAY0BRgH/AfoB7wHo + Af8B5QGAATkB/wHNAU0BJQH/AcQBrAGjAf8DSAGFxAABuAGSAVwC/wH8AfsB/wHtAeMB3QH/AZsBggFR + Af8BpgHeAbAB/wGxAeIBugH/AUgBPwEsAf8BlgGMAYcB/wHJAbIBqwH/AegBngFeAf8B8gGjAYMB/wHj + AZABTgH/AcYBrgGmAf8BgQFPAUYB/wMOARPEAAG9AZoBhAL/AfwB+wL/AfwB+wH/AekB3gHYAf8BmwGC + AVEB/wGbAYIBUQH/Ae4B1gHJAf8B8gHWAcgB/wG7AagBnwH/AaQBmgGWAf8BmgGVAZQB/wGkAZgBkwH/ + AZ8BjgGGAf8BWwEgAQEB/8gAAcIBoAGLAv8B/AH7Av8B/AH7Av8B/AH7Av8B+AH1Af8B/gHzAe0B/wH+ + Ae0B5AH/AdQBxQHSAf8BAAEzAcsB/wEAATEBxgH/AdEBsQGvAf8B/AHKAbAB/wHKAacBlQH/AV0BIAEA + Af/IAAHGAaYBkgL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfgB9QH/Af4B8wHtAf8BEAE+AdQB/wFS + Ab4B+QH/ASQBjAHLAf8BAAExAcYB/wH8AdABuQH/AdIBrQGaAf8BXgEiAQIB/8gAAckBqgGWAv8B/AH7 + Av8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B+AH1Af8BEQFAAdcB/wG5AeQC/wFSAb4B+QH/AQABMwHL + Af8B/QHXAcMB/wHZAbMBnwH/AV8BJAEEAf/IAAHJAaoBlgL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/ + AfwB+wL/AfwB+wH/AdcB1AHsAf8BEQFAAdcB/wEQAT8B1AH/AdQBxQHSAf8B/QHfAc8B/wHeAbcBowH/ + AV8BJgEGAf/IAAHJAaoBlgL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/AfwB+wL/ + AfgB9QH/Af4B8wHtAf8B/gHtAeQB/wH9AeYB2gH/Af0B3wHPAf8BgAEnAQgB/8gAAckBqgGWAf8ByQGq + AZYB/wHJAaoBlgH/AckBqgGWAf8BxgGmAZIB/wHCAaABiwH/Ab0BmgGEAf8BuAGSAVwB/wGyAYsBUwH/ + AawBgwFKAf8BpwFbAUIB/wGiAVUBOwH/AZ4BTwE0Af8BmwFLATAB//8A/wCOAAG6AaEBkgH/Aa0BlwGI + Af8BpgGQAYAB/wGfAYgBTQH/AZkBggFGAf8BkwFRAT8B/wGMAUkBOAH/AYYBQgEwAf8BVAE7ASgB/wFN + ATQBIQH/AUcBLQEZAf8BQQEnARIB/wE8ASEBDQH/ATkBHgEIAf9EAAGbAS4BEwH/AYABCgEAAf8BQgEJ + AQAB/wFCAQcBAAH/AUEBBQEAAf8BQAEDAQAB/wE/AgAB/wE+AgAB/wE9AgAB/wE8AgAB/wE7AgAB/wE6 + AgAB/wE6AgAB/wE5AgAB/0wAAb0BpgGYAf8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEA + A/8BAAP/AQAD/wEAA/8BPwElARAB/wQAA2IB7wGZAagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/ + AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGsAf8DXAHP + DAABngEyARcB/wGLAdABmAH/AYkB0QGYAf8BOQHFAYgB/wEiAbcBNwH/AQwBqQEmAf8BAAGcARQB/wEA + AY8BBAH/AQABiAEAAf8BAAGIAQAB/wEAAYgBAAH/AQABPAEAAf8BEAIAAf8BOgIAAf8IAAMqAUABnAGb + AZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/ + AZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8DRwGADAABwgGqAZ0B/wEAA/8B/QGSATMB/wHt + AYcBKQH/AdkBTwEiAf8BxwFEARkB/wGzATcBDwH/AaYBLQEIAf8BAAP/Af0BkgEzAf8B7QGHASkB/wHZ + AU8BIgH/AQAD/wFIAS8BGgH/BAADYgHvAfIB9AH1Cf8D3QH/A84B/wPOAf8D5w3/AeYB6QHqAf8DXAHP + DAABogE4AR4B/wG6AeYBwgH/AacB4AGyAf8BkgHXAZ8B/wFAAckBjgH/ASgBugE9Af8BEQGsASkB/wEA + AZwBFAH/AQABjgEDAf8BAAGIAQAB/wEGARwBAAH/ATEBHAENAf8BJgERAQIB/wE6AgAB/wgAAyoBQAHN + AcwBxwH/Af4C/AH/Af4C/AH/Af4C/AH/Af4C/AH/Af4C/AH/Af4C/AH/Af4C/AH/Af4C/AH/Af4C/AH/ + Af4C/AH/AeYB5AHhAf8DRwGADAABxQGuAaMB/wEAA/8BAAP/AwAB/wMAAf8DAAH/AQAD/wEAA/8BAAP/ + AQAD/wEAA/8BAAP/AQAD/wFTAToBJgH/BAADYgHvAfIB9AH1Bf8B2gHRAckB/wGhAY0BQAH/AwAB/wEV + ARABCwH/AYUBNgEoAf8BNQEbAQcB/wGjAZIBhQX/AeYB6QHqAf8DXAHPDAABpwE+ASUB/wGkAd4BrwH/ + AdEB7wHWAf8BpwHgAbIB/wGNAdQBmwH/AToBxQGJAf8BIgG2ATgB/wELAagBJAH/AQABlQENAf8BEgEM + AQAB/wGSAT8BMgH/AY0BOwEtAf8DAAH/ATsCAAH/CAADKgFAAc0BzAHHAf8B8wL2Af8B7wHzAfQB/wHv + AfQB9QH/Ae8B9AH1Af8B7wHzAfUB/wHwAvQB/wHwAfQB9QH/Ae8B9AH1Af8B7wL0Af8B7wHzAfUB/wHm + AeQB4QH/A0cBgAwAAckBtAGoAf8BxAGtAaEB/wHAAagBmwH/AwAF/wMAAf8BrQGVAYQB/wGpAZABVAH/ + AaQBiwFOAf8BnwGEAUgB/wGaAVQBQgH/AZYBUAE+Af8BlQFPATwB/wGVAU8BPAH/BAADYgLvAvAF/wGq + AZgBiQH/AdsB1AHOAf8DIwH/AzcB/wPnDf8B5gHpAeoB/wNcAc8MAAGsAYMBLQH/AZsBpAGFAf8BpwHg + AbIB/wHRAe8B1gH/AacB4AGyAf8BiQHRAZgB/wE0AcEBhAH/ARgBsAEvAf8BJAExARUB/wG/AasBoQH/ + AbMBnQGQAf8DAAH/Aa4BkQGDAf8BPAIAAf8IAAMqAUABzQHMAccB/wH0AfcB+AH/AfEB9AH1Af8B8QL1 + Af8B8QL1Af8B8QH0AfUB/wHxAfUB9gH/AfEC9QH/AfEB9QH2Af8B8QH0AfUB/wHxAfUB9gH/AeYB5AHh + Af8DRwGAFwAF/wMAAf8oAANiAe8BxgHDAcEB/wPOAf8BnQGLAUAB/wHbAdQBzgH/AyMB/wEVARABCwH/ + AYUBNgEoAf8BNQEbAQcB/wGjAZIBhQX/AeYB6QHqAf8DXAHPDAABsgGLATYB/wHtAeMB3QH/AZsBngGC + Af8BpQHfAbAB/wHQAe4B1gH/AaUB3gGwAf8BQgHLAY8B/wErATsBHQH/Ac8BvAGyAf8B0wHBAbcB/wMA + Af8B7AG2AZkB/wG0AZYBhwH/AT0CAAH/CAADKgFAAc0BzAHHAf8B9gH3AfgB/wHzAfYB9wH/AfMB9gH3 + Af8B8wH2AfcB/wHzAfYB9wH/AfMB9QH2Af8B8wH2AfcB/wH0AfYB9wH/AfMC9gH/AfMB9gH3Af8B5gHk + AeEB/wNHAYALAAH/CwAF/wMAAf8oAANiAe8DAAH/AwAB/wO/Af8DEwH/A4EB/wPOAf8D5w3/AeYB6QHq + Af8DXAHPDAABuAGSAT8C/wH8AfsB/wHtAeMB3QH/AZsBggE0Af8BpgHeAbAB/wGxAeIBugH/ASsBIQEN + Af8BzgGuAZsB/wEoARIBAgH/ASgBEgECAf8B2AGwAZkB/wH7AcEBogH/AbsBmwGMAf8BPgIAAf8IAAMq + AUABzQHMAccB/wH3AfgB+QH/AfYC9wH/AfUC9wH/AfUB9wH4Af8B9gH3AfgB/wH1AvcB/wH1AfYB+AH/ + AfUB9wH4Af8B9QH3AfgB/wH1AvcB/wHmAeQB4QH/A0cBgAsAAf8DAAH/AwAF/wMAAf8sAANiAe8B8QHu + AesJ/wMTAf8DAAH/AwAB/wEbARQBDgH/AZEBQQExAf8BowGSAYUF/wHmAekB6gH/A1wBzwwAAb0BmgGE + Av8B/AH7Av8B/AH7Af8B6QHeAdgB/wGbAYIBNAH/AZsBggE0Af8B7gHWAckB/wH9Ad8BzwH/Af0B1wHD + Af8B/AHQAbkB/wH8AcoBsAH/AfsBxQGoAf8BwgGhAZAB/wE/AgAB/wgAAyoBQAHNAcwBxwH/AvkB+gH/ + AfcB+AH5Af8B9gH4AfkB/wH3AfgB+QH/AfcB+AH5Af8B9wL4Af8B9wH4AfkB/wH3AfgB+QH/AfcB+AH5 + Af8B9wH4AfkB/wHmAeQB4QH/A0cBgAsADf8DAAH/AwAB/wMAAf8kAANiAe8B8QHuAesN/wMjAf8DjxH/ + AeYB6QHqAf8DXAHPDAABwgGgAYsC/wH8AfsC/wH8AfsC/wH8AfsC/wH4AfUB/wH+AfMB7QH/Af4B7QHk + Af8B1AHFAdIB/wEAARYBywH/AQABFAHGAf8B0QGxAa8B/wH8AcoBsAH/AcoBpwGVAf8BQAEDAQAB/wgA + AyoBQAHNAcwBxwH/AfoB+wH6Af8B+QH6AfkB/wP5Af8B+QL6Af8C+QH6Af8C+QH6Af8B+AL5Af8B+QL6 + Af8D+QH/AfgB+QH6Af8B5gHkAeEB/wNHAYALABH/AwAB/ygAA2IB7wHxAe4B6wn/AxMB/wE6ATIBKwH/ + AZ0BigE+Af8BQAEoARQB/wE1ARoBBgH/AaMBkgGFBf8B5gHpAeoB/wNcAc8MAAHGAaYBkgL/AfwB+wL/ + AfwB+wL/AfwB+wL/AfwB+wL/AfgB9QH/Af4B8wHtAf8BAAEhAdQB/wE1Ab4B+QH/AQcBjAHLAf8BAAEU + AcYB/wH8AdABuQH/AdIBrQGaAf8BQQEFAQAB/wgAAyoBQAHNAcwBxwH/AfwC+wH/AfsB+gH7Af8D+wH/ + Af0B+wH8Af8B/gL8Af8B/gL8Af8B/gL8Af8B/gL8Af8B/gL8Af8B/gL8Af8B5gHkAeEB/wNHAYALAA3/ + AwAB/ywAA2IB7wHxAe4B6wX/AwMB/wOvGf8B5gHpAeoB/wNcAc8MAAHJAaoBlgL/AfwB+wL/AfwB+wL/ + AfwB+wL/AfwB+wL/AfwB+wL/AfgB9QH/AQABIwHXAf8BuQHkAv8BNQG+AfkB/wEAARYBywH/Af0B1wHD + Af8B2QGzAZ8B/wFCAQcBAAH/CAADKgFAAc0BzAHHAf8B/QH8AfsB/wL8AfsB/wH9AvwB/wH+AvwB/wG1 + AbMBrAH/AZwBmwGRAf8BnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wNZAb8PAAn/AwAB/zAA + A2IB7wHxAe4B6wH/AwAB/wGbAZEBigH/Aa0BmQGLAf8BlgFCATAB/wGKATUBIwH/AUABJwEVAf8BNAEa + AQcB/wGjAZIBhQX/AeYB6QHqAf8DXAHPDAAByQGqAZYC/wH8AfsC/wH8AfsC/wH8AfsC/wH8AfsC/wH8 + AfsC/wH8AfsB/wHXAdQB7AH/AQABIwHXAf8BAAEiAdQB/wHUAcUB0gH/Af0B3wHPAf8B3gG3AaMB/wFC + AQkBAAH/CAADKgFAAaYBwAHFAf8BrwHkAfkB/wGvAeQB+QH/Aa8B5AH5Af8BrwHkAfkB/wGhAa0BqwH/ + AfYB9wH4Af8B9gH3AfgB/wH2AvgB/wH2AfcB+AH/AfYB9wH4Af8DWQG/DwAF/wMAAf80AANiAe8DAAH/ + A88h/wHmAekB6gH/A1wBzwwAAckBqgGWAv8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7Av8B/AH7 + Av8B/AH7Av8B+AH1Af8B/gHzAe0B/wH+Ae0B5AH/Af0B5gHaAf8B/QHfAc8B/wGAAQoBAAH/CAADKgFA + AYIBtwHHAf8BKgHSAfwB/wEqAdIB/AH/ASoB0gH8Af8BKgHSAfwB/wGPAakBrAH/AbQBpwGRAf8BtAGn + AZEB/wG0AacBkQH/AbQBpwGRAf8BtAGnAZEB/xMAAf8DAAH/OAADYgHvAZgBogGjAf8BmQGoAawB/wGZ + AagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGsAf8BmQGoAawB/wGZAagBrAH/AZkBqAGs + Af8BmQGoAawB/wNcAc8MAAHJAaoBlgH/AckBqgGWAf8ByQGqAZYB/wHJAaoBlgH/AcYBpgGSAf8BwgGg + AYsB/wG9AZoBhAH/AbgBkgE/Af8BsgGLATYB/wGsAYMBLQH/AacBPgElAf8BogE4AR4B/wGeATIBFwH/ + AZsBLgETAf8MAANHAYABnAGbAZEB/wGcAZsBkQH/AZwBmwGRAf8BnAGbAZEB/wMqAUAnAAH//wA5AAFC + AU0BPgcAAT4DAAEoAwABQAMAASADAAEBAQABAQYAAQEWAAP/AQAB/wEBBgABgAcAAYAHAAGABwABgAcA + AYAHAAGABwABgAcAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAv8GAAb/ + AcABAAL/AYABAQL/AcABAAGAAQMBgAEBAYABAQHAAQABgAEDAYABAQGAAQEBwAEAAYABAwGAAQEBgAEB + AcABAAGAAQMBgAEBAYABAQHxAf8BgAEDAYABAQGAAQEBsQH/AYABAwGAAQEBgAEBAYMB/wGAAQMBgAEB + AYABAQGAAf8BgAEDAYABAQGAAQEBgQH/AYABAwGAAQEBgAEBAYMB/wGAAQMBgAEBAYABAwGHAf8BgAED + AYABAQGAAQMBjwH/AYABAwGAAQEBgAEHAZ8B/wGAAQMBgAEBAcAB/wG/Cf8L - + + 328, 17 + + 669, 17 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAAHYcAAB2HAY/l8WUAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc @@ -251,9 +253,6 @@ TgDQASA1MVpwzwAAAABJRU5ErkJggg== - - 328, 17 - AAABAAgAICAQAAEABADoAgAAhgAAABAQEAABAAQAKAEAAG4DAAAwMAAAAQAIAKgOAACWBAAAICAAAAEA diff --git a/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.Designer.cs b/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.Designer.cs index b02b209b..dd2cec9f 100644 --- a/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.Designer.cs +++ b/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.Designer.cs @@ -29,9 +29,9 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.splitContainerTreeAndDetails = new System.Windows.Forms.SplitContainer(); - this.shellTreeView = new ServerManager.ShellDebugger.ShellTreeView(); this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer(); this.toolStripViewMode = new System.Windows.Forms.ToolStrip(); + this.shellTreeView = new ServerManager.ShellDebugger.ShellTreeView(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerTreeAndDetails)).BeginInit(); this.splitContainerTreeAndDetails.Panel1.SuspendLayout(); this.splitContainerTreeAndDetails.SuspendLayout(); @@ -49,19 +49,13 @@ private void InitializeComponent() // splitContainerTreeAndDetails.Panel1 // this.splitContainerTreeAndDetails.Panel1.Controls.Add(this.shellTreeView); - this.splitContainerTreeAndDetails.Size = new System.Drawing.Size(584, 416); - this.splitContainerTreeAndDetails.SplitterDistance = 194; - this.splitContainerTreeAndDetails.TabIndex = 2; // - // shellTreeView + // splitContainerTreeAndDetails.Panel2 // - this.shellTreeView.Dock = System.Windows.Forms.DockStyle.Fill; - this.shellTreeView.Location = new System.Drawing.Point(0, 0); - this.shellTreeView.Name = "shellTreeView"; - this.shellTreeView.ShowFiles = false; - this.shellTreeView.ShowHiddenFilesAndFolders = false; - this.shellTreeView.Size = new System.Drawing.Size(194, 416); - this.shellTreeView.TabIndex = 0; + this.splitContainerTreeAndDetails.Panel2.Resize += new System.EventHandler(this.splitContainerTreeAndDetails_Panel2_Resize); + this.splitContainerTreeAndDetails.Size = new System.Drawing.Size(584, 416); + this.splitContainerTreeAndDetails.SplitterDistance = 140; + this.splitContainerTreeAndDetails.TabIndex = 2; // // toolStripContainer1 // @@ -86,9 +80,19 @@ private void InitializeComponent() this.toolStripViewMode.Dock = System.Windows.Forms.DockStyle.None; this.toolStripViewMode.Location = new System.Drawing.Point(3, 0); this.toolStripViewMode.Name = "toolStripViewMode"; - this.toolStripViewMode.Size = new System.Drawing.Size(43, 25); + this.toolStripViewMode.Size = new System.Drawing.Size(111, 25); this.toolStripViewMode.TabIndex = 0; // + // shellTreeView + // + this.shellTreeView.Dock = System.Windows.Forms.DockStyle.Fill; + this.shellTreeView.Location = new System.Drawing.Point(0, 0); + this.shellTreeView.Name = "shellTreeView"; + this.shellTreeView.ShowFiles = false; + this.shellTreeView.ShowHiddenFilesAndFolders = false; + this.shellTreeView.Size = new System.Drawing.Size(140, 416); + this.shellTreeView.TabIndex = 0; + // // ShellDebuggerForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.cs b/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.cs index fdbc4615..edd09f6d 100644 --- a/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.cs +++ b/SharpShell/Tools/ServerManager/ShellDebugger/ShellDebuggerForm.cs @@ -173,11 +173,11 @@ int IShellBrowser.BrowseObject(IntPtr pidl, SBSP wFlags) } // Check that we have a new pidl - if (Shell32.ILIsEqual(pidlTmp, currentAbsolutePidl)) - { - Shell32.ILFree(pidlTmp); - return WinError.S_OK; - } + //if (Shell32.ILIsEqual(pidlTmp, currentAbsolutePidl)) + //{ + // Shell32.ILFree(pidlTmp); + // return WinError.S_OK; + //} currentFolder = folderTmp; @@ -331,5 +331,17 @@ int ICommDlgBrowser.IncludeObject(IntPtr ppshv, IntPtr pidl) { return WinError.S_OK; } + + private void splitContainerTreeAndDetails_Panel2_Resize(object sender, EventArgs e) + { + var selectedNode = shellTreeView.SelectedNode; + + if (selectedNode != null) + { + var shellItem = shellTreeView.GetShellItem(selectedNode); + // Browse to the selected item if it is a folder. + ((IShellBrowser) this).BrowseObject(shellItem.PIDL, SBSP.SBSP_SAMEBROWSER | SBSP.SBSP_ABSOLUTE); + } + } } } diff --git a/SharpShell/Tools/ServerManager/ShellDebugger/ShellTreeView.cs b/SharpShell/Tools/ServerManager/ShellDebugger/ShellTreeView.cs index 08000c09..1115e151 100644 --- a/SharpShell/Tools/ServerManager/ShellDebugger/ShellTreeView.cs +++ b/SharpShell/Tools/ServerManager/ShellDebugger/ShellTreeView.cs @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; -using System.Windows.Forms.VisualStyles; using SharpShell.Interop; using SharpShell.Pidl; @@ -28,7 +27,7 @@ public ShellTreeView() // Set the image list to the shell image list. this.SetImageList(TreeViewExtensions.ImageListType.Normal, ShellImageList.GetImageList(ShellImageListSize.Small)); - this.AfterSelect += ShellTreeView_AfterSelect; + AfterSelect += ShellTreeView_AfterSelect; } @@ -68,7 +67,7 @@ private void AddDesktopNode() }; // Map it and add it. - nodesToFolders[desktopNode] = desktopFolder; + _nodesToFolders[desktopNode] = desktopFolder; Nodes.Add(desktopNode); // Fire the event. @@ -92,7 +91,7 @@ protected override void OnBeforeExpand(TreeViewCancelEventArgs e) node.Nodes.Clear(); // Get the shell folder. - var shellFolder = nodesToFolders[node]; + var shellFolder = _nodesToFolders[node]; // Create the enum flags. var childFlags = ChildTypes.Folders | ChildTypes.Files; @@ -109,14 +108,14 @@ protected override void OnBeforeExpand(TreeViewCancelEventArgs e) { // Create a child node. var childNode = new TreeNode - { - Text = child.DisplayName, - ImageIndex = child.IconIndex, - SelectedImageIndex = child.IconIndex, - }; + { + Text = child.DisplayName, + ImageIndex = child.IconIndex, + SelectedImageIndex = child.IconIndex, + }; // Map the node to the shell folder. - nodesToFolders[childNode] = child; + _nodesToFolders[childNode] = child; // If this item has children, add a child node as a placeholder. if (child.HasSubFolders) @@ -143,8 +142,7 @@ protected override void OnBeforeExpand(TreeViewCancelEventArgs e) /// The shell item for the tree node. public ShellItem GetShellItem(TreeNode node) { - ShellItem shellFolder; - if(nodesToFolders.TryGetValue(node, out shellFolder)) + if(_nodesToFolders.TryGetValue(node, out var shellFolder)) return shellFolder; return null; } @@ -156,22 +154,18 @@ public ShellItem GetShellItem(TreeNode node) private void FireOnShellItemAdded(TreeNode nodeAdded) { // Fire the event if we have it. - var theEvent = OnShellItemAdded; - if(theEvent != null) - theEvent(this, new TreeViewEventArgs(nodeAdded)); + OnShellItemAdded?.Invoke(this, new TreeViewEventArgs(nodeAdded)); } private void FireOnShellItemSelected(ShellItem shellItem) { - var theEvent = OnShellItemSelected; - if(theEvent != null) - theEvent(this, new ShellTreeEventArgs(shellItem)); + OnShellItemSelected?.Invoke(this, new ShellTreeEventArgs(shellItem)); } /// /// A map of tree nodes to the Shell Folders. /// - private readonly Dictionary nodesToFolders = new Dictionary(); + private readonly Dictionary _nodesToFolders = new Dictionary(); /// /// Gets or sets a value indicating whether to show hidden files and folders. @@ -199,7 +193,7 @@ private void FireOnShellItemSelected(ShellItem shellItem) /// true if the is in design mode; otherwise, false. [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public new bool DesignMode { get { return (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv"); } } + public new bool DesignMode { get => System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv"; } /// /// Occurs when a shell item is added. @@ -212,11 +206,11 @@ private void FireOnShellItemSelected(ShellItem shellItem) private void InitializeComponent() { - this.SuspendLayout(); + SuspendLayout(); // // ShellTreeView // - this.ResumeLayout(false); + ResumeLayout(false); } @@ -253,7 +247,7 @@ private void OpenItemContextMenu(ShellItem itemHit, int x, int y) // Get the UI object of the context menu. - IntPtr apidl = PidlManager.PidlsToAPidl(new IntPtr[] {PidlManager.IdListToPidl(fullIdList)}); + IntPtr apidl = PidlManager.PidlsToAPidl(new[] {PidlManager.IdListToPidl(fullIdList)}); IntPtr ppv = IntPtr.Zero; @@ -362,15 +356,14 @@ static ShellImageList() public static IntPtr GetImageList(ShellImageListSize imageListSize) { // Do we have the image list? - IImageList imageList; - if (imageLists.TryGetValue(imageListSize, out imageList)) + if (ImageLists.TryGetValue(imageListSize, out var imageList)) return GetImageListHandle(imageList); // We don't have the image list, create it. Shell32.SHGetImageList((int)imageListSize, ref Shell32.IID_IImageList, ref imageList); // Add it to the dictionary. - imageLists.Add(imageListSize, imageList); + ImageLists.Add(imageListSize, imageList); // Return it. return GetImageListHandle(imageList); @@ -389,7 +382,7 @@ private static IntPtr GetImageListHandle(IImageList imageList) /// /// The shell image lists. /// - private readonly static Dictionary imageLists = new Dictionary(); + private static readonly Dictionary ImageLists = new Dictionary(); } /// @@ -444,8 +437,8 @@ static ShellItem() public ShellItem() { // Create the lazy path. - path = new Lazy(CreatePath); - overlayIcon = new Lazy(CreateOverlayIcon); + _path = new Lazy(CreatePath); + _overlayIcon = new Lazy(CreateOverlayIcon); } /// @@ -468,8 +461,7 @@ private Icon CreateOverlayIcon() private static ShellItem CreateDesktopShellFolder() { // Get the desktop shell folder interface. - IShellFolder desktopShellFolderInterface = null; - var result = Shell32.SHGetDesktopFolder(out desktopShellFolderInterface); + var result = Shell32.SHGetDesktopFolder(out var desktopShellFolderInterface); // Validate the result. if (result != 0) @@ -478,10 +470,10 @@ private static ShellItem CreateDesktopShellFolder() Marshal.ThrowExceptionForHR(result); } - // Get the dekstop PDIL. - var desktopPIDL = IntPtr.Zero; - result = Shell32.SHGetSpecialFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, ref desktopPIDL); - result = Shell32.SHGetFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, IntPtr.Zero, 0, out desktopPIDL); + // Get the desktop PDIL. + // TODO + //result = Shell32.SHGetSpecialFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, ref desktopPIDL); + result = Shell32.SHGetFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, IntPtr.Zero, 0, out var desktopPIDL); // Validate the result. if (result != 0) @@ -509,11 +501,11 @@ private static ShellItem CreateDesktopShellFolder() } /// - /// Initialises the ShellItem, from its PIDL and parent. + /// Initializes the ShellItem, from its PIDL and parent. /// /// The pidl. /// The parent folder. - private void Initialise(IntPtr pidl, ShellItem parentFolder) + private void Initialize(IntPtr pidl, ShellItem parentFolder) { // Set the parent item and relative pidl. ParentItem = parentFolder; @@ -549,18 +541,20 @@ private void Initialise(IntPtr pidl, ShellItem parentFolder) if (IsFolder) { // Bind the shell folder interface. - IShellFolder shellFolderInterface; - IntPtr ppv = IntPtr.Zero; - var result = parentFolder.ShellFolderInterface.BindToObject(pidl, IntPtr.Zero, ref Shell32.IID_IShellFolder, - out ppv);//out shellFolderInterface); - shellFolderInterface = ((IShellFolder) Marshal.GetObjectForIUnknown(ppv)); + var result = parentFolder.ShellFolderInterface.BindToObject( + pidl, + IntPtr.Zero, + ref Shell32.IID_IShellFolder, + out var ppv + );//out shellFolderInterface); + var shellFolderInterface = ((IShellFolder) Marshal.GetObjectForIUnknown(ppv)); ShellFolderInterface = shellFolderInterface; // Validate the result. if (result != 0) { // Throw the failure as an exception. - Marshal.ThrowExceptionForHR((int)result); + Marshal.ThrowExceptionForHR(result); } } } @@ -588,7 +582,7 @@ public IEnumerable GetChildren(ChildTypes childTypes) // We'll return a list of children. var children = new List(); - // Create the enum flags from the childtypes. + // Create the enum flags from the child-types. SHCONTF enumFlags = 0; if (childTypes.HasFlag(ChildTypes.Folders)) enumFlags |= SHCONTF.SHCONTF_FOLDERS; @@ -607,7 +601,7 @@ public IEnumerable GetChildren(ChildTypes childTypes) if (result != 0) { // Throw the failure as an exception. - Marshal.ThrowExceptionForHR((int)result); + Marshal.ThrowExceptionForHR(result); } // TODO: This logic should go in the pidl manager. @@ -615,11 +609,10 @@ public IEnumerable GetChildren(ChildTypes childTypes) // Enumerate the children, ten at a time. const int batchSize = 10; var pidlArray = Marshal.AllocCoTaskMem(IntPtr.Size * 10); - uint itemsFetched; - result = WinError.S_OK; + do { - result = pEnum.Next(batchSize, pidlArray, out itemsFetched); + result = pEnum.Next(batchSize, pidlArray, out var itemsFetched); // Get each pidl. var pidls = new IntPtr[itemsFetched]; @@ -632,11 +625,11 @@ public IEnumerable GetChildren(ChildTypes childTypes) // Initialize it. try { - childShellFolder.Initialise(childPidl, this); + childShellFolder.Initialize(childPidl, this); } catch (Exception exception) { - throw new InvalidOperationException("Failed to initialise child.", exception); + throw new InvalidOperationException("Failed to initialize child.", exception); } // Add the child. @@ -659,15 +652,17 @@ public IEnumerable GetChildren(ChildTypes childTypes) } // Sort the children. - var sortedChildren = children.Where(c => c.IsFolder).ToList(); - sortedChildren.AddRange(children.Where(c => !c.IsFolder)); + var sortedChildren = children + .Where(c => c.IsFolder) + .Concat(children.Where(c => !c.IsFolder)) + .ToList(); // Return the children. return sortedChildren; } /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// Performs application-defined tasks associated with freeing, releasing, or resetting un-managed resources. /// public void Dispose() { @@ -702,12 +697,12 @@ public override string ToString() /// /// The lazy path. /// - private readonly Lazy path; + private readonly Lazy _path; /// /// The overlay icon. /// - private readonly Lazy overlayIcon; + private readonly Lazy _overlayIcon; /// /// Gets the parent item. @@ -751,7 +746,10 @@ public override string ToString() /// /// Gets the ShellFolder of the Desktop. /// - public static ShellItem DesktopShellFolder { get { return desktopShellFolder.Value; } } + public static ShellItem DesktopShellFolder + { + get => desktopShellFolder.Value; + } /// /// Gets the shell folder interface. @@ -779,7 +777,10 @@ public override string ToString() /// /// Gets the path. /// - public string Path { get { return path.Value; } } + public string Path + { + get => _path.Value; + } /// /// Gets the overlay icon. @@ -787,7 +788,10 @@ public override string ToString() /// /// The overlay icon. /// - public Icon OverlayIcon { get { return overlayIcon.Value; } } + public Icon OverlayIcon + { + get => _overlayIcon.Value; + } } /// /// The Child Type flags. diff --git a/SharpShell/Tools/ServerManager/ShellExtensionEntry.cs b/SharpShell/Tools/ServerManager/ShellExtensionEntry.cs new file mode 100644 index 00000000..d6dd9fcd --- /dev/null +++ b/SharpShell/Tools/ServerManager/ShellExtensionEntry.cs @@ -0,0 +1,419 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using SharpShell.ServerRegistration; + +namespace ServerManager +{ + internal class ShellExtensionEntry : INotifyPropertyChanged, IEquatable + { + private ServerInstallationInfo _installationInfo32; + private ServerInstallationInfo _installationInfo64; + private bool _isNative; + private ShellExtensionRegistrationInfo _registrationInfo32; + private ShellExtensionRegistrationInfo _registrationInfo64; + private SharpShellServerInfo _sharpShellServerInfo; + + public ShellExtensionEntry(Guid serverClassId) + { + ServerClassId = serverClassId; + } + + public ShellExtensionEntry(SharpShellServerInfo serverInfo) : this(serverInfo.ClassId) + { + SharpShellServerInfo = serverInfo; + UpdateInstallationInfo32(); + UpdateInstallationInfo64(); + UpdateRegistrationInfo32(); + UpdateRegistrationInfo64(); + } + + public ServerInstallationInfo InstallationInfo32 + { + get => _installationInfo32; + private set + { + _installationInfo32 = value; + OnPropertyChanged(nameof(InstallationInfo32)); + OnPropertyChanged(nameof(ServerPath)); + OnPropertyChanged(nameof(IsNative)); + OnPropertyChanged(nameof(ServerDisplayName)); + } + } + + public ServerInstallationInfo InstallationInfo64 + { + get => _installationInfo64; + private set + { + _installationInfo64 = value; + OnPropertyChanged(nameof(InstallationInfo64)); + OnPropertyChanged(nameof(ServerPath)); + OnPropertyChanged(nameof(IsNative)); + OnPropertyChanged(nameof(ServerDisplayName)); + } + } + + public bool IsNative + { + get + { + if (_isNative) + { + return true; + } + + if (InstallationInfo32 != null) + { + return InstallationInfo32.ServerInstallationType != ServerInstallationType.ManagedInProcess32; + } + + if (InstallationInfo64 != null) + { + return InstallationInfo64.ServerInstallationType != ServerInstallationType.ManagedInProcess32; + } + + return false; + } + set + { + _isNative = value; + OnPropertyChanged(nameof(IsNative)); + } + } + + public ShellExtensionRegistrationInfo RegistrationInfo32 + { + get => _registrationInfo32; + private set + { + _registrationInfo32 = value; + OnPropertyChanged(nameof(RegistrationInfo32)); + OnPropertyChanged(nameof(ShellAssociatedClassNames)); + OnPropertyChanged(nameof(ServerDisplayName)); + } + } + + public ShellExtensionRegistrationInfo RegistrationInfo64 + { + get => _registrationInfo64; + private set + { + _registrationInfo64 = value; + OnPropertyChanged(nameof(RegistrationInfo64)); + OnPropertyChanged(nameof(ShellAssociatedClassNames)); + OnPropertyChanged(nameof(ServerDisplayName)); + } + } + + public Guid ServerClassId { get; } + + public string ServerDisplayName + { + get + { + return SharpShellServerInfo?.DisplayName ?? + SharpShellServerInfo?.RegistrationName ?? + SharpShellServerInfo?.ClassName ?? + RegistrationInfo32?.Associations + .FirstOrDefault(info => !string.IsNullOrWhiteSpace(info.RegistrationName)) + ?.RegistrationName ?? + RegistrationInfo64?.Associations + .FirstOrDefault(info => !string.IsNullOrWhiteSpace(info.RegistrationName)) + ?.RegistrationName ?? + InstallationInfo32?.ManagedClassName ?? + InstallationInfo64?.ManagedClassName ?? + ServerClassId.ToString("B"); + } + } + + public string ServerPath + { + get => InstallationInfo32?.ServerPath ?? InstallationInfo64?.ServerPath; + } + + public SharpShellServerInfo SharpShellServerInfo + { + get => _sharpShellServerInfo; + private set + { + _sharpShellServerInfo = value; + OnPropertyChanged(nameof(SharpShellServerInfo)); + OnPropertyChanged(nameof(ServerDisplayName)); + } + } + + public string[] ShellAssociatedClassNames + { + get + { + if (RegistrationInfo32 != null || RegistrationInfo64 != null) + { + return (RegistrationInfo32?.Associations ?? new ShellExtensionRegisteredAssociationInfo[0]) + .Concat(RegistrationInfo64?.Associations ?? new ShellExtensionRegisteredAssociationInfo[0]) + .Select(info => info.AssociationClassName).Distinct().ToArray(); + } + + return (SharpShellServerInfo?.AssociationClassNamesX32 ?? new string[0]) + .Concat(SharpShellServerInfo?.AssociationClassNamesX64 ?? new string[0]) + .Distinct().ToArray(); + } + } + + public ShellExtensionType[] ShellExtensionTypes + { + get + { + var extensionTypes = new List(); + + if (SharpShellServerInfo?.ShellExtensionType != null) + { + extensionTypes.Add(SharpShellServerInfo.ShellExtensionType); + } + + if (RegistrationInfo32 != null) + { + extensionTypes.AddRange(RegistrationInfo32.Associations.Select(info => info.ShellExtensionType)); + } + + if (RegistrationInfo64 != null) + { + extensionTypes.AddRange(RegistrationInfo64.Associations.Select(info => info.ShellExtensionType)); + } + + if (extensionTypes.Count == 0) + { + return new[] {ShellExtensionType.None}; + } + + return extensionTypes.Distinct().Where(type => type != ShellExtensionType.None).ToArray(); + } + } + + /// + public bool Equals(ShellExtensionEntry other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return ServerClassId.Equals(other.ServerClassId); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public static IEnumerable GetRegisteredEntries() + { + var extensions32 = ServerRegistrationManager.EnumerateRegisteredExtensions(RegistrationScope.OS32Bit) + .Select(info => + new Tuple(RegistrationScope.OS32Bit, info) + ); + + var extensions64 = ServerRegistrationManager.EnumerateRegisteredExtensions(RegistrationScope.OS64Bit) + .Select(info => + new Tuple(RegistrationScope.OS64Bit, info) + ); + + var extensions = extensions32.Concat(extensions64).GroupBy(info => info.Item2.ServerClassId); + + foreach (var extensionGroup in extensions) + { + var extension = new ShellExtensionEntry(extensionGroup.Key) + { + RegistrationInfo64 = + extensionGroup.FirstOrDefault(t => t.Item1 == RegistrationScope.OS64Bit)?.Item2, + RegistrationInfo32 = extensionGroup.FirstOrDefault(t => t.Item1 == RegistrationScope.OS32Bit)?.Item2 + }; + + extension.UpdateManagedServerInfo(); + + yield return extension; + } + } + + public static bool operator ==(ShellExtensionEntry left, ShellExtensionEntry right) + { + return Equals(left, right) || left?.Equals(right) == true; + } + + public static bool operator !=(ShellExtensionEntry left, ShellExtensionEntry right) + { + return !(left == right); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + return Equals(obj as ShellExtensionEntry); + } + + /// + public override int GetHashCode() + { + return ServerClassId.GetHashCode(); + } + + public void UpdateInstallationInfo32() + { + var installation = ServerRegistrationManager.GetExtensionInstallationInfo( + ServerClassId, + RegistrationScope.OS32Bit + ); + + if (installation?.ServerInstallationType != ServerInstallationType.PartiallyInstalled) + { + InstallationInfo32 = installation; + } + else + { + InstallationInfo32 = null; + } + } + + public void UpdateInstallationInfo64() + { + var installation = ServerRegistrationManager.GetExtensionInstallationInfo( + ServerClassId, + RegistrationScope.OS64Bit + ); + + if (installation?.ServerInstallationType != ServerInstallationType.PartiallyInstalled) + { + InstallationInfo64 = installation; + } + else + { + InstallationInfo64 = null; + } + } + + public void UpdateManagedServerInfo() + { + if (SharpShellServerInfo != null || IsNative) + { + return; + } + + UpdateInstallationInfo32(); + UpdateInstallationInfo64(); + + try + { + if (InstallationInfo64?.ServerInstallationType == ServerInstallationType.ManagedInProcess32) + { + SharpShellServerInfo = InstallationInfo64.GetSharpShellServerInformation(); + } + else if (InstallationInfo32?.ServerInstallationType == ServerInstallationType.ManagedInProcess32) + { + SharpShellServerInfo = InstallationInfo32.GetSharpShellServerInformation(); + } + } + catch + { + IsNative = true; + } + } + + public void UpdateRegistrationInfo32() + { + if (SharpShellServerInfo != null) + { + var registration = ServerRegistrationManager.GetExtensionRegistrationInfo( + SharpShellServerInfo, + RegistrationScope.OS32Bit + ); + + if (registration?.Associations.Any() == true) + { + RegistrationInfo32 = registration; + } + else + { + RegistrationInfo32 = null; + } + } + else + { + var registration = ServerRegistrationManager.GetExtensionRegistrationInfo( + ServerClassId, + RegistrationScope.OS32Bit + ); + + if (registration?.Associations.Any() == true) + { + RegistrationInfo32 = registration; + } + else + { + RegistrationInfo32 = null; + } + } + } + + public void UpdateRegistrationInfo64() + { + if (SharpShellServerInfo != null) + { + var registration = ServerRegistrationManager.GetExtensionRegistrationInfo( + SharpShellServerInfo, + RegistrationScope.OS64Bit + ); + + if (registration?.Associations.Any() == true) + { + RegistrationInfo64 = registration; + } + else + { + RegistrationInfo64 = null; + } + } + else + { + var registration = ServerRegistrationManager.GetExtensionRegistrationInfo( + ServerClassId, + RegistrationScope.OS64Bit + ); + + if (registration?.Associations.Any() == true) + { + RegistrationInfo64 = registration; + } + else + { + RegistrationInfo64 = null; + } + } + } + + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + try + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + catch + { + // ignored + } + } + } +} \ No newline at end of file diff --git a/SharpShell/Tools/ServerManager/TestShell/TestShellForm.cs b/SharpShell/Tools/ServerManager/TestShell/TestShellForm.cs index f3a5f7ef..0ca1a850 100644 --- a/SharpShell/Tools/ServerManager/TestShell/TestShellForm.cs +++ b/SharpShell/Tools/ServerManager/TestShell/TestShellForm.cs @@ -4,11 +4,9 @@ using System.Drawing; using System.IO; using System.Linq; -using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Windows.Forms; -using Apex.WinForms.Interop; using Apex.WinForms.Shell; using Microsoft.Win32; using SharpShell; @@ -41,19 +39,19 @@ public TestShellForm() { InitializeComponent(); - lazyBoldFont = new Lazy(() => new Font(Font, FontStyle.Bold)); + _lazyBoldFont = new Lazy(() => new Font(Font, FontStyle.Bold)); - shellTreeView.OnShellItemAdded += new TreeViewEventHandler(shellTreeView_OnShellItemAdded); - shellListView.OnShellItemAdded += new Apex.WinForms.Controls.ListViewItemEventHandler(shellListView_OnShellItemAdded); + shellTreeView.OnShellItemAdded += shellTreeView_OnShellItemAdded; + shellListView.OnShellItemAdded += shellListView_OnShellItemAdded; // Create the ordered view menu items. - orderedViewMenuItems.Add(largeIconsToolStripMenuItem); - orderedViewMenuItems.Add(toolStripMenuItemSmallIcons); - orderedViewMenuItems.Add(listToolStripMenuItem); - orderedViewMenuItems.Add(detailsToolStripMenuItem); - orderedViewMenuItems.Add(tileToolStripMenuItem); + _orderedViewMenuItems.Add(largeIconsToolStripMenuItem); + _orderedViewMenuItems.Add(toolStripMenuItemSmallIcons); + _orderedViewMenuItems.Add(listToolStripMenuItem); + _orderedViewMenuItems.Add(detailsToolStripMenuItem); + _orderedViewMenuItems.Add(tileToolStripMenuItem); - shellListView.Columns.Add(new ColumnHeader {Text = "Name"}); + shellListView.Columns.Add(new ColumnHeader {Text = @"Name"}); } void shellTreeView_OnShellItemAdded(object sender, TreeViewEventArgs e) @@ -71,27 +69,39 @@ void shellListView_OnShellItemAdded(object sender, Apex.WinForms.Controls.ListVi // If the icon handler is associated with the the item, test it. if (IsServerAssociatedWithShellItem(TestIconHandler, shellItem)) + { DoTestIconHandler(args.Item); + } // If the info tip handler is associated with the item, test it. if (IsServerAssociatedWithShellItem(TestInfoTipHandler, shellItem)) + { DoTestInfoTipHandler(args.Item); + } // If the drop handler is associated with the item, test it. if (IsServerAssociatedWithShellItem(TestDropHandler, shellItem)) + { DoTestDropHandler(args.Item); + } // If the preview handler is associated with the item, test it. if (IsServerAssociatedWithShellItem(TestPreviewHandler, shellItem)) + { DoTestPreviewHandler(args.Item); + } // If a thumbnail handleris associated with the item, highlight it. - if(IsServerAssociatedWithShellItem(TestThumbnailHandler, shellItem)) + if (IsServerAssociatedWithShellItem(TestThumbnailHandler, shellItem)) + { HighlightItem(args.Item); + } // If an icon overlay handler is associated with the item, highlight it. - if(IsServerAssociatedWithShellItem(TestIconOverlayHandler, shellItem)) + if (IsServerAssociatedWithShellItem(TestIconOverlayHandler, shellItem)) + { HighlightItem(args.Item); + } } private void shellTreeView1_MouseUp(object sender, MouseEventArgs e) @@ -100,7 +110,7 @@ private void shellTreeView1_MouseUp(object sender, MouseEventArgs e) { if (shellTreeView.SelectedNode == null) return; - // Get the point in screen coords. + // Get the point in screen coordination. var screenPoint = shellTreeView.PointToScreen(new Point(e.X, e.Y)); // Get the shell item. @@ -118,7 +128,7 @@ private void shellListView1_MouseUp(object sender, MouseEventArgs e) // Get the highlighted items. var items = shellListView.SelectedItems.OfType().Select(lvi => shellListView.GetShellItem(lvi)).ToArray(); - // Get the point in screen coords. + // Get the point in screen coordination. var screenPoint = shellListView.PointToScreen(new Point(e.X, e.Y)); // Test it. @@ -136,7 +146,9 @@ private void DoTestMenu(ShellItem[] items, int x, int y) { // If we don't have a context menu, we can bail now. if (TestContextMenu == null) + { return; + } // Get the interfaces we need to test with. var shellExtInitInterface = (IShellExtInit) TestContextMenu; @@ -156,7 +168,7 @@ private void DoTestMenu(ShellItem[] items, int x, int y) // Get the IUnknown COM interface address. Jesus .NET makes this easy. var dataObjectInterfacePointer = Marshal.GetIUnknownForObject(dataObject); - // Pass the data to the shell extension, attempt to initialise it. + // Pass the data to the shell extension, attempt to initialize it. // We must provide the data object as well as the parent folder PIDL. if (items.Any()) { @@ -189,19 +201,19 @@ protected override void WndProc(ref Message m) { base.WndProc(ref m); - // Do we have a comamnd and a shell context menu we're testing? + // Do we have a command and a shell context menu we're testing? if (m.Msg == WM_COMMAND && TestContextMenu != null) { - var loword = LowWord(m.WParam.ToInt32()); - var hiword = HighWord(m.WParam.ToInt32()); + var lowWord = LowWord(m.WParam.ToInt32()); + var highWord = HighWord(m.WParam.ToInt32()); - // If the hiword is 0 it's a menu command. - if (hiword == 0) + // If the high is 0 it's a menu command. + if (highWord == 0) { // Create command info. var commandInfo = new CMINVOKECOMMANDINFO(); commandInfo.cbSize = (uint) Marshal.SizeOf(commandInfo); - commandInfo.verb = new IntPtr(loword); + commandInfo.verb = new IntPtr(lowWord); // Get a pointer to the structure. var commandInfoPointer = Marshal.AllocHGlobal(Marshal.SizeOf(commandInfo)); @@ -214,8 +226,7 @@ protected override void WndProc(ref Message m) public static int HighWord(int number) { - return ((number & 0x80000000) == 0x80000000) ? - (number >> 16) : ((number >> 16) & 0xffff); + return (number & 0x80000000) == 0x80000000 ? number >> 16 : (number >> 16) & 0xffff; } public static int LowWord(int number) @@ -228,13 +239,20 @@ private void shellListView_SelectedIndexChanged(object sender, EventArgs e) var shellItem = shellListView.SelectedItems.Count > 0 ? shellListView.GetShellItem(shellListView.SelectedItems[0]) : null; if (shellItem != null) - toolStripStatusLabelAttributes.Text = "Attributes: " + shellItem.Attributes.ToString(); + { + toolStripStatusLabelAttributes.Text = @"Attributes: " + shellItem.Attributes; + } propertyGridSelectedObject.SelectedObject = shellItem; - + + if (shellItem?.Path == null) + { + return; + } + if (IsServerAssociatedWithShellItem(TestPreviewHandler, shellItem)) { - shellPreviewHost1.SetPreviewHandler(TestPreviewHandler.ServerClsid); + shellPreviewHost1.SetPreviewHandler(TestPreviewHandler.ServerClassId); shellPreviewHost1.SetPreviewItem(shellItem.Path); } @@ -273,11 +291,10 @@ private void DoTestIconHandler(ListViewItem item) { var shellItem = shellListView.GetShellItem(item); - IntPtr iconSmall, iconLarge; - GetIconHandlerIcons(TestIconHandler, shellItem.Path, out iconSmall, out iconLarge); + GetIconHandlerIcons(TestIconHandler, shellItem.Path, out var iconSmall, out var iconLarge); // We're testing the item, so make it bold. - item.Font = lazyBoldFont.Value; + item.Font = _lazyBoldFont.Value; // Add the icons. var largeIcon = Icon.FromHandle(iconLarge); @@ -291,6 +308,7 @@ private void DoTestIconHandler(ListViewItem item) } catch (Exception) { + // ignored } } @@ -309,28 +327,30 @@ private void GetIconHandlerIcons(SharpIconHandler iconHandler, string path, out private void DoTestInfoTipHandler(ListViewItem item) { if (TestInfoTipHandler == null) + { return; + } // Get the shell item. try { var shellItem = shellListView.GetShellItem(item); - // Initialise the icon handler. + // Initialize the icon handler. var persistFileInterface = (IPersistFile)TestInfoTipHandler; persistFileInterface.Load(shellItem.Path, 0); // Get the info tip. var queryInfoInterface = (IQueryInfo)TestInfoTipHandler; - string infoTip; - queryInfoInterface.GetInfoTip(QITIPF.QITIPF_DEFAULT, out infoTip); + queryInfoInterface.GetInfoTip(QITIPF.QITIPF_DEFAULT, out var infoTip); // Set the tooltip. - item.Font = lazyBoldFont.Value; + item.Font = _lazyBoldFont.Value; item.ToolTipText = infoTip; } catch (Exception) { + // ignored } } @@ -339,13 +359,15 @@ private void DoTestInfoTipHandler(ListViewItem item) private void DoTestDropHandler(ListViewItem item) { if (TestDropHandler == null) + { return; + } - // Add the item to the set of test drop items. - testDropItems.Add(item); + // Add the item to the set of test drop items. + _testDropItems.Add(item); - // Highlight the item. - HighlightItem(item); + // Highlight the item. + HighlightItem(item); } private void DoTestPreviewHandler(ListViewItem item) @@ -364,10 +386,10 @@ private void DoTestPreviewHandler(ListViewItem item) private void HighlightItem(ListViewItem listViewItem) { // Set the font to bold. - listViewItem.Font = lazyBoldFont.Value; + listViewItem.Font = _lazyBoldFont.Value; } - private readonly List testDropItems = new List(); + private readonly List _testDropItems = new List(); /// /// Determines whether a server is associated with a shell item. @@ -384,18 +406,26 @@ private bool IsServerAssociatedWithShellItem(ISharpShellServer server, ShellItem return false; // Get the associations. - var associationType = COMServerAssociationAttribute.GetAssociationType(server.GetType()); + var associationType = COMServerAssociationAttribute.GetAssociationTypes(server.GetType()).FirstOrDefault(); var associations = COMServerAssociationAttribute.GetAssociations(server.GetType()); // TODO: This is potentially a very useful check - maybe it should be moved into the // COMServerAssociationAttribute class so that it can be reused. // We have a special case for icon overlays. - if (server is SharpIconOverlayHandler && TestIconOverlayHandler != null && shellItem.Attributes.HasFlag(SFGAO.SFGAO_FILESYSTEM)) - if (((IShellIconOverlayIdentifier)TestIconOverlayHandler).IsMemberOf(shellItem.Path, FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL) == 0) + if (server is SharpIconOverlayHandler && + TestIconOverlayHandler != null && + shellItem.Attributes.HasFlag(SFGAO.SFGAO_FILESYSTEM)) + { + if (((IShellIconOverlayIdentifier) TestIconOverlayHandler).IsMemberOf(shellItem.Path, + FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL) == + 0) + { return true; + } + } - // Based on the assocation type, we can check the shell item. + // Based on the association type, we can check the shell item. switch (associationType) { // This is checked for backwards compatibility. @@ -407,10 +437,11 @@ private bool IsServerAssociatedWithShellItem(ISharpShellServer server, ShellItem if (shellItem.Attributes.HasFlag(SFGAO.SFGAO_FILESYSTEM)) { return - associations.Any( - a => - string.Compare(Path.GetExtension(shellItem.DisplayName), a, - StringComparison.OrdinalIgnoreCase) == 0); + associations.Any(a => string.Equals( + Path.GetExtension(shellItem.DisplayName), + a, + StringComparison.OrdinalIgnoreCase + )); } break; @@ -429,8 +460,6 @@ private bool IsServerAssociatedWithShellItem(ISharpShellServer server, ShellItem // Do we match it? return associations.Any(a => string.Compare(fileClass, FileExtensionClass.Get(classesRoot, a, false), StringComparison.InvariantCultureIgnoreCase) == 0); } - - } break; @@ -495,9 +524,9 @@ private void listToolStripMenuItem_Click(object sender, EventArgs e) /// /// The view menu items, in order. /// - private List orderedViewMenuItems = new List(); + private readonly List _orderedViewMenuItems = new List(); - private readonly Lazy lazyBoldFont; + private readonly Lazy _lazyBoldFont; private const uint WM_CONTEXTMENU = 0x007B; private const uint WM_COMMAND = 0x0111; @@ -530,7 +559,7 @@ internal static extern bool TrackPopupMenu(IntPtr hMenu, /// /// The test context menu. /// - public SharpContextMenu TestContextMenu { get { return TestServer as SharpContextMenu; } } + public SharpContextMenu TestContextMenu { get => TestServer as SharpContextMenu; } /// /// Gets or sets the test icon handler. @@ -538,7 +567,7 @@ internal static extern bool TrackPopupMenu(IntPtr hMenu, /// /// The test icon handler. /// - public SharpIconHandler TestIconHandler { get { return TestServer as SharpIconHandler; } } + public SharpIconHandler TestIconHandler { get => TestServer as SharpIconHandler; } /// /// Gets the test thumbnail handler. @@ -546,7 +575,7 @@ internal static extern bool TrackPopupMenu(IntPtr hMenu, /// /// The test thumbnail handler. /// - public SharpThumbnailHandler TestThumbnailHandler { get { return TestServer as SharpThumbnailHandler; } } + public SharpThumbnailHandler TestThumbnailHandler { get => TestServer as SharpThumbnailHandler; } /// /// Gets or sets the test info tip handler. @@ -554,12 +583,12 @@ internal static extern bool TrackPopupMenu(IntPtr hMenu, /// /// The test info tip handler. /// - public SharpInfoTipHandler TestInfoTipHandler { get { return TestServer as SharpInfoTipHandler; } } + public SharpInfoTipHandler TestInfoTipHandler { get => TestServer as SharpInfoTipHandler; } /// /// Gets the test drop handler. /// - public SharpDropHandler TestDropHandler { get { return TestServer as SharpDropHandler; } } + public SharpDropHandler TestDropHandler { get => TestServer as SharpDropHandler; } /// /// Gets the test preview handler. @@ -567,36 +596,39 @@ internal static extern bool TrackPopupMenu(IntPtr hMenu, /// /// The test preview handler. /// - public SharpPreviewHandler TestPreviewHandler { get { return TestServer as SharpPreviewHandler; } } + public SharpPreviewHandler TestPreviewHandler { get => TestServer as SharpPreviewHandler; } /// /// Gets the test icon overlay handler. /// - public SharpIconOverlayHandler TestIconOverlayHandler { get { return TestServer as SharpIconOverlayHandler; } } + public SharpIconOverlayHandler TestIconOverlayHandler { get => TestServer as SharpIconOverlayHandler; } private void toolStripSplitButtonChangeYourView_ButtonClick(object sender, EventArgs e) { // Update it. - currentViewIndex++; - if (currentViewIndex >= orderedViewMenuItems.Count) - currentViewIndex = 0; + _currentViewIndex++; + + if (_currentViewIndex >= _orderedViewMenuItems.Count) + { + _currentViewIndex = 0; + } - SetViewIndex(currentViewIndex); - orderedViewMenuItems[currentViewIndex].PerformClick(); + SetViewIndex(_currentViewIndex); + _orderedViewMenuItems[_currentViewIndex].PerformClick(); } private void SetViewIndex(int index) { - currentViewIndex = index; + _currentViewIndex = index; // Get the menu item to change to. - var newItem = orderedViewMenuItems[currentViewIndex]; + var newItem = _orderedViewMenuItems[_currentViewIndex]; // Set the icon. toolStripSplitButtonChangeYourView.Image = newItem.Image; } - private int currentViewIndex = 0; + private int _currentViewIndex; private void shellListView_ItemDrag(object sender, ItemDragEventArgs e) { @@ -606,7 +638,7 @@ private void shellListView_ItemDrag(object sender, ItemDragEventArgs e) //shellListView.DoDragDrop(e.Item, DragDropEffects.All); } - private List dragItems = new List(); + private List _dragItems = new List(); private void shellListView_QueryContinueDrag(object sender, QueryContinueDragEventArgs e) { @@ -647,7 +679,7 @@ private void toolStripButtonShowProperties_Click(object sender, EventArgs e) const int SW_SHOW = 5; - var shell_ex = new SHELLEXECUTEINFO + var shellExecuteInfo = new SHELLEXECUTEINFO { cbSize = Marshal.SizeOf(new SHELLEXECUTEINFO()), lpFile = path, @@ -656,7 +688,7 @@ private void toolStripButtonShowProperties_Click(object sender, EventArgs e) lpVerb = "Properties" }; - Shell32.ShellExecuteEx(ref shell_ex); + Shell32.ShellExecuteEx(ref shellExecuteInfo); } private void toolStripButtonShellOpenDialog_Click(object sender, EventArgs e) diff --git a/SharpShell/Tools/ServerManager/Views/ServerDetailsView.Designer.cs b/SharpShell/Tools/ServerManager/Views/ServerDetailsView.Designer.cs new file mode 100644 index 00000000..214f3492 --- /dev/null +++ b/SharpShell/Tools/ServerManager/Views/ServerDetailsView.Designer.cs @@ -0,0 +1,537 @@ +namespace ServerManager.Views +{ + partial class ServerDetailsView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label5 = new System.Windows.Forms.Label(); + this.textBox32BitServerInstallation = new System.Windows.Forms.TextBox(); + this.textBox64BitServerInstallation = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBoxAssociations = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.textBoxServerPath = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.textBoxServerClassId = new System.Windows.Forms.TextBox(); + this.textBoxExntensionTypes = new System.Windows.Forms.TextBox(); + this.textBoxServerName = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.groupBoxRegistration = new System.Windows.Forms.GroupBox(); + this.textBox32BitServerRegistration = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.textBox64BitServerRegistration = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.label12 = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.textBoxManagedName = new System.Windows.Forms.TextBox(); + this.textBoxManagedVersion = new System.Windows.Forms.TextBox(); + this.textBoxManagedRuntime = new System.Windows.Forms.TextBox(); + this.label14 = new System.Windows.Forms.Label(); + this.textBoxManagedClassName = new System.Windows.Forms.TextBox(); + this.label16 = new System.Windows.Forms.Label(); + this.textBoxManagedSecurity = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.textBoxSharpShellVersion = new System.Windows.Forms.TextBox(); + this.textBoxSharpShellServerType = new System.Windows.Forms.TextBox(); + this.label20 = new System.Windows.Forms.Label(); + this.label21 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBoxRegistration.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.SuspendLayout(); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(18, 33); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(68, 13); + this.label5.TabIndex = 0; + this.label5.Text = "32 Bit Server"; + // + // textBox32BitServerInstallation + // + this.textBox32BitServerInstallation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox32BitServerInstallation.Location = new System.Drawing.Point(120, 30); + this.textBox32BitServerInstallation.Multiline = true; + this.textBox32BitServerInstallation.Name = "textBox32BitServerInstallation"; + this.textBox32BitServerInstallation.ReadOnly = true; + this.textBox32BitServerInstallation.Size = new System.Drawing.Size(250, 46); + this.textBox32BitServerInstallation.TabIndex = 1; + // + // textBox64BitServerInstallation + // + this.textBox64BitServerInstallation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox64BitServerInstallation.Location = new System.Drawing.Point(120, 82); + this.textBox64BitServerInstallation.Multiline = true; + this.textBox64BitServerInstallation.Name = "textBox64BitServerInstallation"; + this.textBox64BitServerInstallation.ReadOnly = true; + this.textBox64BitServerInstallation.Size = new System.Drawing.Size(250, 46); + this.textBox64BitServerInstallation.TabIndex = 3; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(18, 85); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(68, 13); + this.label7.TabIndex = 2; + this.label7.Text = "64 Bit Server"; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.textBoxAssociations); + this.groupBox1.Controls.Add(this.label8); + this.groupBox1.Controls.Add(this.textBoxServerPath); + this.groupBox1.Controls.Add(this.label6); + this.groupBox1.Controls.Add(this.textBoxServerClassId); + this.groupBox1.Controls.Add(this.textBoxExntensionTypes); + this.groupBox1.Controls.Add(this.textBoxServerName); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(3, 3); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(376, 240); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Shell Extension"; + // + // textBoxAssociations + // + this.textBoxAssociations.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxAssociations.Location = new System.Drawing.Point(120, 187); + this.textBoxAssociations.Multiline = true; + this.textBoxAssociations.Name = "textBoxAssociations"; + this.textBoxAssociations.ReadOnly = true; + this.textBoxAssociations.Size = new System.Drawing.Size(250, 46); + this.textBoxAssociations.TabIndex = 11; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(18, 190); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(66, 13); + this.label8.TabIndex = 10; + this.label8.Text = "Associations"; + // + // textBoxServerPath + // + this.textBoxServerPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxServerPath.Location = new System.Drawing.Point(120, 83); + this.textBoxServerPath.Multiline = true; + this.textBoxServerPath.Name = "textBoxServerPath"; + this.textBoxServerPath.ReadOnly = true; + this.textBoxServerPath.Size = new System.Drawing.Size(250, 46); + this.textBoxServerPath.TabIndex = 9; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(18, 86); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(29, 13); + this.label6.TabIndex = 8; + this.label6.Text = "Path"; + // + // textBoxServerClassId + // + this.textBoxServerClassId.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxServerClassId.Location = new System.Drawing.Point(120, 57); + this.textBoxServerClassId.Name = "textBoxServerClassId"; + this.textBoxServerClassId.ReadOnly = true; + this.textBoxServerClassId.Size = new System.Drawing.Size(250, 20); + this.textBoxServerClassId.TabIndex = 5; + // + // textBoxExntensionTypes + // + this.textBoxExntensionTypes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxExntensionTypes.Location = new System.Drawing.Point(120, 135); + this.textBoxExntensionTypes.Multiline = true; + this.textBoxExntensionTypes.Name = "textBoxExntensionTypes"; + this.textBoxExntensionTypes.ReadOnly = true; + this.textBoxExntensionTypes.Size = new System.Drawing.Size(250, 46); + this.textBoxExntensionTypes.TabIndex = 3; + // + // textBoxServerName + // + this.textBoxServerName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxServerName.Location = new System.Drawing.Point(120, 31); + this.textBoxServerName.Name = "textBoxServerName"; + this.textBoxServerName.ReadOnly = true; + this.textBoxServerName.Size = new System.Drawing.Size(250, 20); + this.textBoxServerName.TabIndex = 1; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(18, 60); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(44, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Class Id"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(18, 138); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(85, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Extension Types"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(18, 34); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(35, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Name"; + // + // groupBox2 + // + this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox2.Controls.Add(this.textBox32BitServerInstallation); + this.groupBox2.Controls.Add(this.label5); + this.groupBox2.Controls.Add(this.textBox64BitServerInstallation); + this.groupBox2.Controls.Add(this.label7); + this.groupBox2.Location = new System.Drawing.Point(3, 509); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(376, 138); + this.groupBox2.TabIndex = 1; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Installation"; + // + // groupBoxRegistration + // + this.groupBoxRegistration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBoxRegistration.Controls.Add(this.textBox32BitServerRegistration); + this.groupBoxRegistration.Controls.Add(this.label9); + this.groupBoxRegistration.Controls.Add(this.textBox64BitServerRegistration); + this.groupBoxRegistration.Controls.Add(this.label10); + this.groupBoxRegistration.Location = new System.Drawing.Point(3, 653); + this.groupBoxRegistration.Name = "groupBoxRegistration"; + this.groupBoxRegistration.Size = new System.Drawing.Size(376, 87); + this.groupBoxRegistration.TabIndex = 2; + this.groupBoxRegistration.TabStop = false; + this.groupBoxRegistration.Text = "Registration"; + // + // textBox32BitServerRegistration + // + this.textBox32BitServerRegistration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox32BitServerRegistration.Location = new System.Drawing.Point(120, 30); + this.textBox32BitServerRegistration.Name = "textBox32BitServerRegistration"; + this.textBox32BitServerRegistration.ReadOnly = true; + this.textBox32BitServerRegistration.Size = new System.Drawing.Size(250, 20); + this.textBox32BitServerRegistration.TabIndex = 1; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(18, 33); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(68, 13); + this.label9.TabIndex = 0; + this.label9.Text = "32 Bit Server"; + // + // textBox64BitServerRegistration + // + this.textBox64BitServerRegistration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox64BitServerRegistration.Location = new System.Drawing.Point(120, 56); + this.textBox64BitServerRegistration.Name = "textBox64BitServerRegistration"; + this.textBox64BitServerRegistration.ReadOnly = true; + this.textBox64BitServerRegistration.Size = new System.Drawing.Size(250, 20); + this.textBox64BitServerRegistration.TabIndex = 3; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(18, 59); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(68, 13); + this.label10.TabIndex = 2; + this.label10.Text = "64 Bit Server"; + // + // groupBox3 + // + this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox3.Controls.Add(this.textBoxManagedSecurity); + this.groupBox3.Controls.Add(this.label4); + this.groupBox3.Controls.Add(this.textBoxManagedClassName); + this.groupBox3.Controls.Add(this.label16); + this.groupBox3.Controls.Add(this.textBoxManagedRuntime); + this.groupBox3.Controls.Add(this.label14); + this.groupBox3.Controls.Add(this.textBoxManagedVersion); + this.groupBox3.Controls.Add(this.textBoxManagedName); + this.groupBox3.Controls.Add(this.label12); + this.groupBox3.Controls.Add(this.label13); + this.groupBox3.Location = new System.Drawing.Point(3, 249); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(376, 161); + this.groupBox3.TabIndex = 4; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Managed Server"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(18, 33); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(35, 13); + this.label12.TabIndex = 0; + this.label12.Text = "Name"; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(18, 59); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(42, 13); + this.label13.TabIndex = 2; + this.label13.Text = "Version"; + // + // textBoxManagedDisplayName + // + this.textBoxManagedName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxManagedName.Location = new System.Drawing.Point(120, 30); + this.textBoxManagedName.Name = "textBoxManagedName"; + this.textBoxManagedName.ReadOnly = true; + this.textBoxManagedName.Size = new System.Drawing.Size(250, 20); + this.textBoxManagedName.TabIndex = 14; + // + // textBoxManagedVersion + // + this.textBoxManagedVersion.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxManagedVersion.Location = new System.Drawing.Point(120, 56); + this.textBoxManagedVersion.Name = "textBoxManagedVersion"; + this.textBoxManagedVersion.ReadOnly = true; + this.textBoxManagedVersion.Size = new System.Drawing.Size(250, 20); + this.textBoxManagedVersion.TabIndex = 15; + // + // textBoxManagedRuntime + // + this.textBoxManagedRuntime.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxManagedRuntime.Location = new System.Drawing.Point(120, 82); + this.textBoxManagedRuntime.Name = "textBoxManagedRuntime"; + this.textBoxManagedRuntime.ReadOnly = true; + this.textBoxManagedRuntime.Size = new System.Drawing.Size(250, 20); + this.textBoxManagedRuntime.TabIndex = 17; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(18, 85); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(46, 13); + this.label14.TabIndex = 16; + this.label14.Text = "Runtime"; + // + // textBoxManagedClassName + // + this.textBoxManagedClassName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxManagedClassName.Location = new System.Drawing.Point(120, 108); + this.textBoxManagedClassName.Name = "textBoxManagedClassName"; + this.textBoxManagedClassName.ReadOnly = true; + this.textBoxManagedClassName.Size = new System.Drawing.Size(250, 20); + this.textBoxManagedClassName.TabIndex = 21; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(18, 111); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(63, 13); + this.label16.TabIndex = 20; + this.label16.Text = "Class Name"; + // + // textBoxManagedSecurity + // + this.textBoxManagedSecurity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxManagedSecurity.Location = new System.Drawing.Point(120, 134); + this.textBoxManagedSecurity.Name = "textBoxManagedSecurity"; + this.textBoxManagedSecurity.ReadOnly = true; + this.textBoxManagedSecurity.Size = new System.Drawing.Size(250, 20); + this.textBoxManagedSecurity.TabIndex = 9; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(18, 137); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(45, 13); + this.label4.TabIndex = 8; + this.label4.Text = "Security"; + // + // groupBox4 + // + this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox4.Controls.Add(this.textBoxSharpShellVersion); + this.groupBox4.Controls.Add(this.textBoxSharpShellServerType); + this.groupBox4.Controls.Add(this.label20); + this.groupBox4.Controls.Add(this.label21); + this.groupBox4.Location = new System.Drawing.Point(3, 416); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(376, 87); + this.groupBox4.TabIndex = 22; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Sharp Shell Server"; + // + // textBoxSharpShellVersion + // + this.textBoxSharpShellVersion.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxSharpShellVersion.Location = new System.Drawing.Point(120, 56); + this.textBoxSharpShellVersion.Name = "textBoxSharpShellVersion"; + this.textBoxSharpShellVersion.ReadOnly = true; + this.textBoxSharpShellVersion.Size = new System.Drawing.Size(250, 20); + this.textBoxSharpShellVersion.TabIndex = 15; + // + // textBoxSharpShellServerType + // + this.textBoxSharpShellServerType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxSharpShellServerType.Location = new System.Drawing.Point(120, 30); + this.textBoxSharpShellServerType.Name = "textBoxSharpShellServerType"; + this.textBoxSharpShellServerType.ReadOnly = true; + this.textBoxSharpShellServerType.Size = new System.Drawing.Size(250, 20); + this.textBoxSharpShellServerType.TabIndex = 14; + // + // label20 + // + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(18, 33); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(65, 13); + this.label20.TabIndex = 0; + this.label20.Text = "Server Type"; + // + // label21 + // + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(18, 59); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(96, 13); + this.label21.TabIndex = 2; + this.label21.Text = "SharpShell Version"; + // + // ServerDetailsView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScroll = true; + this.Controls.Add(this.groupBox4); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.groupBoxRegistration); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Name = "ServerDetailsView"; + this.Size = new System.Drawing.Size(382, 748); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBoxRegistration.ResumeLayout(false); + this.groupBoxRegistration.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox textBox32BitServerInstallation; + private System.Windows.Forms.TextBox textBox64BitServerInstallation; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBoxServerClassId; + private System.Windows.Forms.TextBox textBoxExntensionTypes; + private System.Windows.Forms.TextBox textBoxServerName; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.TextBox textBoxServerPath; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox textBoxAssociations; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.GroupBox groupBoxRegistration; + private System.Windows.Forms.TextBox textBox32BitServerRegistration; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox textBox64BitServerRegistration; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.TextBox textBoxManagedRuntime; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.TextBox textBoxManagedVersion; + private System.Windows.Forms.TextBox textBoxManagedName; + private System.Windows.Forms.TextBox textBoxManagedClassName; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.TextBox textBoxManagedSecurity; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.TextBox textBoxSharpShellVersion; + private System.Windows.Forms.TextBox textBoxSharpShellServerType; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.Label label21; + } +} diff --git a/SharpShell/Tools/ServerManager/Views/ServerDetailsView.cs b/SharpShell/Tools/ServerManager/Views/ServerDetailsView.cs new file mode 100644 index 00000000..fcf4de69 --- /dev/null +++ b/SharpShell/Tools/ServerManager/Views/ServerDetailsView.cs @@ -0,0 +1,151 @@ +using System.ComponentModel; +using System.Linq; +using System.Windows.Forms; + +namespace ServerManager.Views +{ + internal partial class ServerDetailsView : UserControl + { + + public ServerDetailsView() + { + InitializeComponent(); + } + private ShellExtensionEntry _extensionEntry; + + public ShellExtensionEntry ExtensionEntry + { + get => _extensionEntry; + set + { + if (!ReferenceEquals(_extensionEntry, value)) + { + if (_extensionEntry != null) + { + _extensionEntry.PropertyChanged -= ExtensionEntryOnPropertyChanged; + } + + _extensionEntry = value; + + if (_extensionEntry != null) + { + _extensionEntry.PropertyChanged += ExtensionEntryOnPropertyChanged; + } + } + + UpdateUI(); + } + } + + private void ExtensionEntryOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) + { + UpdateUI(); + } + + private void UpdateUI() + { + // Setting default values for text boxes + textBoxServerName.Text = @"[N/A]"; + textBoxServerClassId.Text = @"[N/A]"; + textBoxServerPath.Text = @"[N/A]"; + textBoxExntensionTypes.Text = @"[N/A]"; + textBoxAssociations.Text = @"[N/A]"; + + textBoxManagedName.Text = @"[N/A]"; + textBoxManagedVersion.Text = @"[N/A]"; + textBoxManagedRuntime.Text = @"[N/A]"; + textBoxManagedClassName.Text = @"[N/A]"; + textBoxManagedSecurity.Text = @"[N/A]"; + + textBoxSharpShellServerType.Text = @"[N/A]"; + textBoxSharpShellVersion.Text = @"[N/A]"; + + textBox32BitServerInstallation.Text = @"[Not Installed]"; + textBox64BitServerInstallation.Text = @"[Not Installed]"; + + textBox32BitServerRegistration.Text = @"[Not Registered]"; + textBox64BitServerRegistration.Text = @"[Not Registered]"; + + if (ExtensionEntry != null) + { + // General information + textBoxServerName.Text = ExtensionEntry.ServerDisplayName; + textBoxServerClassId.Text = ExtensionEntry.ServerClassId.ToString("B"); + textBoxServerPath.Text = ExtensionEntry.ServerPath; + textBoxAssociations.Text = string.Join(", ", ExtensionEntry.ShellAssociatedClassNames); + textBoxExntensionTypes.Text = string.Join(", ", ExtensionEntry.ShellExtensionTypes.Select(type => type.ToString())); + + // Managed information + if (ExtensionEntry.SharpShellServerInfo != null) + { + textBoxManagedName.Text = ExtensionEntry.SharpShellServerInfo?.AssemblyInfo.FullName; + textBoxManagedVersion.Text = ExtensionEntry.SharpShellServerInfo.AssemblyInfo.Version; + textBoxManagedRuntime.Text = ExtensionEntry.SharpShellServerInfo.AssemblyInfo.RuntimeVersion; + textBoxManagedClassName.Text = ExtensionEntry.SharpShellServerInfo.ClassFullName; + textBoxManagedSecurity.Text = ExtensionEntry.SharpShellServerInfo.AssemblyInfo.IsSigned + ? "Signed" + : "Unsigned"; + + textBoxSharpShellServerType.Text = ExtensionEntry.SharpShellServerInfo.ServerType.ToString(); + if (ExtensionEntry.SharpShellServerInfo.SharpShellAssemblyInfo != null) + { + textBoxSharpShellVersion.Text = + ExtensionEntry.SharpShellServerInfo.SharpShellAssemblyInfo.Version; + } + } + + // Do we have 32 bit registration info? + if (ExtensionEntry.InstallationInfo32 != null) + { + // Do we have a codebase? + if (!string.IsNullOrEmpty(ExtensionEntry.InstallationInfo32?.ManagedAssembly?.AssemblyPath)) + { + textBox32BitServerInstallation.Text = ExtensionEntry.InstallationInfo32.ManagedAssembly.AssemblyPath; + } + else if (!string.IsNullOrEmpty(ExtensionEntry.InstallationInfo32?.ManagedAssembly?.FullName)) + { + textBox32BitServerInstallation.Text = ExtensionEntry.InstallationInfo32.ManagedAssembly.FullName + @" (GAC)"; + } + else if (!string.IsNullOrEmpty(ExtensionEntry.InstallationInfo32?.ServerPath)) + { + textBox32BitServerInstallation.Text = ExtensionEntry.InstallationInfo32.ServerPath + @" (Native)"; + } + } + + // Do we have 64 bit registration info? + if (ExtensionEntry.InstallationInfo64 != null) + { + // Do we have a codebase? + if (!string.IsNullOrEmpty(ExtensionEntry.InstallationInfo64?.ManagedAssembly?.AssemblyPath)) + { + textBox64BitServerInstallation.Text = ExtensionEntry.InstallationInfo64.ManagedAssembly?.AssemblyPath; + } + else if (!string.IsNullOrEmpty(ExtensionEntry.InstallationInfo64?.ManagedAssembly?.FullName)) + { + textBox64BitServerInstallation.Text = ExtensionEntry.InstallationInfo64.ManagedAssembly?.FullName + @" (GAC)"; + } + else if (!string.IsNullOrEmpty(ExtensionEntry.InstallationInfo64?.ServerPath)) + { + textBox64BitServerInstallation.Text = ExtensionEntry.InstallationInfo64.ServerPath + @" (Native)"; + } + } + + // Set the registration info. + if (ExtensionEntry.RegistrationInfo32?.Associations.Any() == true) + { + textBox32BitServerRegistration.Text = ExtensionEntry.RegistrationInfo32.IsApproved + ? @"Registered and Approved" + : @"Registered"; + } + + // Set the registration info. + if (ExtensionEntry.RegistrationInfo64?.Associations.Any() == true) + { + textBox64BitServerRegistration.Text = ExtensionEntry.RegistrationInfo64.IsApproved + ? @"Registered and Approved" + : @"Registered"; + } + } + } + } +} diff --git a/SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.resx b/SharpShell/Tools/ServerManager/Views/ServerDetailsView.resx similarity index 100% rename from SharpShell/Tools/ServerManager/ServerDetails/ServerDetailsView.resx rename to SharpShell/Tools/ServerManager/Views/ServerDetailsView.resx diff --git a/SharpShell/Tools/ServerManager/Views/ServerListViewItem.cs b/SharpShell/Tools/ServerManager/Views/ServerListViewItem.cs new file mode 100644 index 00000000..466e031f --- /dev/null +++ b/SharpShell/Tools/ServerManager/Views/ServerListViewItem.cs @@ -0,0 +1,121 @@ +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using SharpShell; +using SharpShell.ServerRegistration; + +namespace ServerManager.Views +{ + internal class ServerListViewItem : ListViewItem + { + private ShellExtensionEntry _extensionEntry; + + public ServerListViewItem(ShellExtensionEntry extensionEntry) + { + ExtensionEntry = extensionEntry; + } + + public ServerListViewItem() + { + } + + public ShellExtensionEntry ExtensionEntry + { + get => _extensionEntry; + set + { + if (!ReferenceEquals(_extensionEntry, value)) + { + if (_extensionEntry != null) + { + _extensionEntry.PropertyChanged -= ExtensionEntryOnPropertyChanged; + } + + _extensionEntry = value; + + if (_extensionEntry != null) + { + _extensionEntry.PropertyChanged += ExtensionEntryOnPropertyChanged; + } + } + + UpdateUI(); + } + } + + private void ExtensionEntryOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) + { + UpdateUI(); + } + + private void UpdateUI() + { + SubItems.Clear(); + + if (ExtensionEntry != null) + { + Text = ExtensionEntry.ServerDisplayName; + SubItems.Add(string.Join(", ", ExtensionEntry.ShellExtensionTypes.Select(type => type.ToString()))); + SubItems.Add(ExtensionEntry.ServerClassId.ToString("B")); + + if (ExtensionEntry.ShellExtensionTypes.Contains(ShellExtensionType.ShellContextMenu)) + { + ImageIndex = 0; + } + else if (ExtensionEntry.ShellExtensionTypes.Contains(ShellExtensionType.ShellIconHandler)) + { + ImageIndex = 1; + } + else if (ExtensionEntry.ShellExtensionTypes.Contains(ShellExtensionType.ShellPropertySheet)) + { + ImageIndex = 2; + } + else if (ExtensionEntry.ShellExtensionTypes.Contains(ShellExtensionType.ShellInfoTipHandler)) + { + ImageIndex = 3; + } + else if (ExtensionEntry.SharpShellServerInfo?.ServerType == ServerType.ShellIconOverlayHandler) + { + ImageIndex = 4; + } + else + { + ImageIndex = 0; + } + + if (ExtensionEntry.SharpShellServerInfo != null) + { + BackColor = Color.FromArgb(221, 242, 255); + } + else + { + BackColor = Color.White; + } + + if (ExtensionEntry.InstallationInfo32 == null && + ExtensionEntry.InstallationInfo64 == null && + ExtensionEntry.RegistrationInfo32 == null && + ExtensionEntry.RegistrationInfo64 == null) + { + ForeColor = Color.FromArgb(217, 0, 0); + } + else if (ExtensionEntry.InstallationInfo32 == null && ExtensionEntry.InstallationInfo64 == null || + ExtensionEntry.RegistrationInfo32 == null && ExtensionEntry.RegistrationInfo64 == null) + { + ForeColor = Color.FromArgb(116, 91, 0); + } + else + { + ForeColor = Color.Black; + } + } + else + { + Text = @"[N/A]"; + SubItems.Add(@"[N/A]"); + SubItems.Add(@"[N/A]"); + } + } + } +} \ No newline at end of file diff --git a/SharpShell/Tools/ServerManager/app.config b/SharpShell/Tools/ServerManager/app.config new file mode 100644 index 00000000..2a0024f7 --- /dev/null +++ b/SharpShell/Tools/ServerManager/app.config @@ -0,0 +1,3 @@ + + + diff --git a/SharpShell/Tools/ServerRegistrationManager/Application.cs b/SharpShell/Tools/ServerRegistrationManager/Application.cs index e613dc36..0dda87e7 100644 --- a/SharpShell/Tools/ServerRegistrationManager/Application.cs +++ b/SharpShell/Tools/ServerRegistrationManager/Application.cs @@ -48,7 +48,7 @@ public void Run(string[] args) } // Get the architecture. - var registrationType = Environment.Is64BitOperatingSystem ? RegistrationType.OS64Bit : RegistrationType.OS32Bit; + var registrationType = Environment.Is64BitOperatingSystem ? RegistrationScope.OS64Bit : RegistrationScope.OS32Bit; // Get the verb, target and parameters. var verb = args[0]; @@ -58,11 +58,11 @@ public void Run(string[] args) //Allow user to override registrationType with -os32 or -os64 if (parameters.Any(p => p.Equals(ParameterOS32, StringComparison.InvariantCultureIgnoreCase))) { - registrationType = RegistrationType.OS32Bit; + registrationType = RegistrationScope.OS32Bit; } else if (parameters.Any(p => p.Equals(ParameterOS64, StringComparison.InvariantCultureIgnoreCase))) { - registrationType = RegistrationType.OS64Bit; + registrationType = RegistrationScope.OS64Bit; } var viaRegAsm = parameters.Any(p => p.Equals(ParameterRegAsm, StringComparison.InvariantCultureIgnoreCase)); @@ -91,9 +91,9 @@ public void Run(string[] args) /// Installs a SharpShell server at the specified path. /// /// The path to the SharpShell server. - /// Type of the registration. + /// Type of the registration. /// if set to true install from codebase rather than GAC. - private void InstallServer(string path, RegistrationType registrationType, bool codeBase) + private void InstallServer(string path, RegistrationScope registrationScope, bool codeBase) { // Validate the path. if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) @@ -106,22 +106,20 @@ private void InstallServer(string path, RegistrationType registrationType, bool try { // Load any servers from the assembly. - var servers = SharpShell.ServerRegistration.ServerRegistrationManager.EnumerateFromFile(path); + var servers = SharpShellServerInfo.FromExternalAssemblyFile(path); foreach (var server in servers) { - var name = server.GetType().Name; try { - name = server.DisplayName; - SharpShell.ServerRegistration.ServerRegistrationManager.InstallServer(server, registrationType, codeBase); - SharpShell.ServerRegistration.ServerRegistrationManager.RegisterServer(server, registrationType); + SharpShell.ServerRegistration.ServerRegistrationManager.InstallServer(server, registrationScope, codeBase); + SharpShell.ServerRegistration.ServerRegistrationManager.RegisterAndApproveServer(server, registrationScope); } catch (Exception e) { success = false; outputService.WriteError(e.ToString()); - outputService.WriteError($"Failed to install and register a server. [{name}]", true); + outputService.WriteError($"Failed to install and register a server. [{server.DisplayName}]", true); } } } @@ -145,9 +143,9 @@ private void InstallServer(string path, RegistrationType registrationType, bool /// Installs a SharpShell server at the specified path via RegAsm. /// /// The path to the SharpShell server. - /// Type of the registration. + /// Type of the registration. /// if set to true install from codebase rather than GAC. - private void InstallServerViaRegAsm(string path, RegistrationType registrationType, bool codeBase) + private void InstallServerViaRegAsm(string path, RegistrationScope registrationScope, bool codeBase) { // Validate the path. if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) @@ -159,7 +157,7 @@ private void InstallServerViaRegAsm(string path, RegistrationType registrationTy var regAsm = new RegAsm(); var success = - registrationType == RegistrationType.OS32Bit + registrationScope == RegistrationScope.OS32Bit ? regAsm.Register32(path, codeBase) : regAsm.Register64(path, codeBase); @@ -179,8 +177,8 @@ private void InstallServerViaRegAsm(string path, RegistrationType registrationTy /// Uninstalls a SharpShell server located at 'path'. /// /// The path to the SharpShell server. - /// Type of the registration. - private void UninstallServer(string path, RegistrationType registrationType) + /// Type of the registration. + private void UninstallServer(string path, RegistrationScope registrationScope) { // Validate the path. if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) @@ -193,22 +191,20 @@ private void UninstallServer(string path, RegistrationType registrationType) try { // Load any servers from the assembly. - var servers = SharpShell.ServerRegistration.ServerRegistrationManager.EnumerateFromFile(path); + var servers = SharpShellServerInfo.FromExternalAssemblyFile(path); foreach (var server in servers) { - var name = server.GetType().Name; try { - name = server.DisplayName; - SharpShell.ServerRegistration.ServerRegistrationManager.UninstallServer(server, registrationType); - SharpShell.ServerRegistration.ServerRegistrationManager.UnregisterServer(server, registrationType); + SharpShell.ServerRegistration.ServerRegistrationManager.UninstallServer(server, registrationScope); + SharpShell.ServerRegistration.ServerRegistrationManager.UnregisterAndUnApproveServer(server, registrationScope); } catch (Exception e) { success = false; outputService.WriteError(e.ToString()); - outputService.WriteError($"Failed to uninstall and unregister a server. [{name}]", true); + outputService.WriteError($"Failed to uninstall and unregister a server. [{server.DisplayName}]", true); } } } @@ -232,8 +228,8 @@ private void UninstallServer(string path, RegistrationType registrationType) /// Uninstalls a SharpShell server located at 'path' vis RegAsm. /// /// The path to the SharpShell server. - /// Type of the registration. - private void UninstallServerViaRegAsm(string path, RegistrationType registrationType) + /// Type of the registration. + private void UninstallServerViaRegAsm(string path, RegistrationScope registrationScope) { // Validate the path. if (string.IsNullOrWhiteSpace(path) || File.Exists(path) == false) @@ -245,7 +241,7 @@ private void UninstallServerViaRegAsm(string path, RegistrationType registration var regAsm = new RegAsm(); var success = - registrationType == RegistrationType.OS32Bit + registrationScope == RegistrationScope.OS32Bit ? regAsm.Unregister32(path) : regAsm.Unregister64(path); diff --git a/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ExtensionViewModel.cs b/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ExtensionViewModel.cs index fa902ca6..5f1cb7ab 100644 --- a/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ExtensionViewModel.cs +++ b/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ExtensionViewModel.cs @@ -49,14 +49,14 @@ public ShellExtensionType ShellExtensionType /// /// The ClassRegistrations observable collection. /// - private readonly ObservableCollection ClassRegistrationsProperty = - new ObservableCollection(); + private readonly ObservableCollection ClassRegistrationsProperty = + new ObservableCollection(); /// /// Gets the ClassRegistrations observable collection. /// /// The ClassRegistrations observable collection. - public ObservableCollection ClassRegistrations + public ObservableCollection ClassRegistrations { get { return ClassRegistrationsProperty; } } diff --git a/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs b/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs index bcd104a1..29391de5 100644 --- a/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs +++ b/SharpShell/Tools/ShellExtensionManager/ShellExtensions/ShellExtensionsViewModel.cs @@ -22,15 +22,23 @@ public ShellExtensionsViewModel() private void DoRefreshExtensionsCommand(object parameter) { // Get all servers. - var servers = ServerRegistrationManager.EnumerateExtensions(RegistrationType.OS64Bit); + var servers = ServerRegistrationManager.EnumerateRegisteredExtensions(RegistrationScope.OS64Bit); foreach (var server in servers) { - var extensionViewModel = new ExtensionViewModel(); - extensionViewModel.DisplayName = server.DisplayName; - extensionViewModel.ShellExtensionType = server.ShellExtensionType; - foreach (var classReg in server.ClassRegistrations) - extensionViewModel.ClassRegistrations.Add(classReg); - RefreshExtensionsCommand.ReportProgress(() => Extensions.Add(extensionViewModel)); + var installation = + ServerRegistrationManager.GetExtensionInstallationInfo(server.ServerClassId, + RegistrationScope.OS64Bit); + var sharpServer = installation?.GetSharpShellServerInformation(); + + if (sharpServer != null) + { + var extensionViewModel = new ExtensionViewModel(); + extensionViewModel.DisplayName = sharpServer.DisplayName; + extensionViewModel.ShellExtensionType = sharpServer.ShellExtensionType; + foreach (var classReg in server.Associations) + extensionViewModel.ClassRegistrations.Add(classReg); + RefreshExtensionsCommand.ReportProgress(() => Extensions.Add(extensionViewModel)); + } } } From dae5d08423981cd6a2c27177d02b4393f48595aa Mon Sep 17 00:00:00 2001 From: s_falahati Date: Wed, 9 Jan 2019 04:07:07 +0330 Subject: [PATCH 12/12] SRM default installation provider changed back to RegAsm and a new "-experimental" argument added to use the build in installation process --- .../ServerRegistrationManager/Application.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SharpShell/Tools/ServerRegistrationManager/Application.cs b/SharpShell/Tools/ServerRegistrationManager/Application.cs index 0dda87e7..e218a172 100644 --- a/SharpShell/Tools/ServerRegistrationManager/Application.cs +++ b/SharpShell/Tools/ServerRegistrationManager/Application.cs @@ -65,20 +65,20 @@ public void Run(string[] args) registrationType = RegistrationScope.OS64Bit; } - var viaRegAsm = parameters.Any(p => p.Equals(ParameterRegAsm, StringComparison.InvariantCultureIgnoreCase)); + var isExperimental = parameters.Any(p => p.Equals(ParameterExperimental, StringComparison.InvariantCultureIgnoreCase)); var codebase = parameters.Any(p => p.Equals(ParameterCodebase, StringComparison.InvariantCultureIgnoreCase)); // Based on the verb, perform the action. if (verb == VerbInstall) - if (viaRegAsm) - InstallServerViaRegAsm(target, registrationType, codebase); - else + if (isExperimental) InstallServer(target, registrationType, codebase); - else if (verb == VerbUninstall) - if (viaRegAsm) - UninstallServerViaRegAsm(target, registrationType); else + InstallServerViaRegAsm(target, registrationType, codebase); + else if (verb == VerbUninstall) + if (isExperimental) UninstallServer(target, registrationType); + else + UninstallServerViaRegAsm(target, registrationType); else if (verb == VerbConfig) ConfigAction.Execute(outputService, parameters); else if (verb == VerbEnableEventLog) @@ -280,6 +280,6 @@ private void ShowWelcome() private const string ParameterOS32 = @"-os32"; private const string ParameterOS64 = @"-os64"; - private const string ParameterRegAsm = @"-regasm"; + private const string ParameterExperimental = @"-experimental"; } }