/// <summary> /// 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. /// </summary> /// <param name="type">The type of object to unregister, this must be a SharpShellServer derived class.</param> /// <param name="registrationType">Type of the registration to unregister.</param> 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 <COMServerAssociationAttribute>().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"); }
/// <summary> /// 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. /// </summary> /// <param name="type">The type of object to register, this must be a SharpShellServer derived class.</param> /// <param name="registrationType">Type of the registration.</param> 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 <COMServerAssociationAttribute>().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"); }
internal static void CustomUnregisterFunction(Type serverType, RegistrationType registrationType) { var keyName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(serverType); Logging.Log($"IconOverlayHandler: Preparing to unregister {registrationType} Icon Overlay Handler for type '{serverType.Name}' with key name '{keyName}'"); // Open the local machine. using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { // Open the ShellIconOverlayIdentifiers. using (var overlayIdentifiers = localMachineBaseKey .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.Delete | RegistryRights.EnumerateSubKeys | RegistryRights.ReadKey)) { // If we don't have the key, we've got a problem. if (overlayIdentifiers == null) { throw new InvalidOperationException("Cannot open the ShellIconOverlayIdentifiers key."); } // Delete the overlay key. if (overlayIdentifiers.GetSubKeyNames().Any(skn => skn == keyName)) { overlayIdentifiers.DeleteSubKey(keyName); } } } }
internal static void CustomRegisterFunction(Type serverType, RegistrationType registrationType) { var keyName = RegistrationNameAttribute.GetRegistrationNameOrTypeName(serverType); Logging.Log($"IconOverlayHandler: Preparing to register {registrationType} Icon Overlay Handler for type '{serverType.Name}' with key name '{keyName}'"); // Open the local machine. using (var localMachineBaseKey = registrationType == RegistrationType.OS64Bit ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { // Open the ShellIconOverlayIdentifiers. using (var overlayIdentifiers = localMachineBaseKey .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.EnumerateSubKeys | RegistryRights.QueryValues | RegistryRights.CreateSubKey | RegistryRights.CreateSubKey)) { // If we don't have the key, we've got a problem. if (overlayIdentifiers == null) { throw new InvalidOperationException("Cannot open the ShellIconOverlayIdentifiers key."); } // How many shell icon overlay identifiers do we have? var overlayHandlersCount = overlayIdentifiers.GetSubKeyNames().Count(); if (overlayHandlersCount >= MaximumOverlayIdentifiers) { Logging.Error("There are already the maximum number of overlay " + "handlers registered for the system. Although " + serverType.Name + " is " + "being registered, it will not be used by Windows Explorer."); } // Create the overlay key. using (var overlayKey = overlayIdentifiers.CreateSubKey(keyName)) { // If we don't have the overlay key, we've got a problem. if (overlayKey == null) { throw new InvalidOperationException("Cannot create the key for the overlay server."); } // Set the server CLSID. overlayKey.SetValue(null, serverType.GUID.ToRegistryString()); } } } }
/// <summary> /// 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. /// </summary> /// <param name="type">The type of object to register, this must be a SharpShellServer derived class.</param> /// <param name="registrationType">Type of the registration.</param> 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 <COMServerAssociationAttribute>().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); } // If we are a *file* thumbnail handler, we must disable process isolation. // See: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/cc144118(v%3Dvs.85)#thumbnail-processes if (serverType == ServerType.ShellItemThumbnailHandler) { Logging.Log($"Disabling process isolation for SharpFileThumbnailHandler named '{type.Name}'."); ServerRegistrationManager.SetDisableProcessIsolationValue(type.GUID, registrationType, 1 /* i.e. disabled */); } // 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"); }
public LspHandlerTypeDescriptor(Type handlerType) : base(handlerType) { if (HasParamsType) { PartialItemsType = ParamsType !.GetInterfaces() .FirstOrDefault(z => z.IsGenericType && typeof(IPartialItems <>).IsAssignableFrom(z.GetGenericTypeDefinition())) ?.GetGenericArguments()[0]; PartialItemType = ParamsType.GetInterfaces() .FirstOrDefault(z => z.IsGenericType && typeof(IPartialItem <>).IsAssignableFrom(z.GetGenericTypeDefinition())) ?.GetGenericArguments()[0]; } HasPartialItems = PartialItemsType != null; HasPartialItem = PartialItemType != null; RegistrationType = HandlerTypeDescriptorHelper.UnwrapGenericType(typeof(IRegistration <>), handlerType) ?? HandlerTypeDescriptorHelper.UnwrapGenericType(typeof(IRegistration <,>), handlerType, 0); HasRegistration = RegistrationType != null && RegistrationType != typeof(object); RegistrationMethod = RegistrationNameAttribute.AllFrom(RegistrationType).FirstOrDefault()?.Method ?? Method; if (!HasRegistration) { RegistrationType = null; } CapabilityType = HandlerTypeDescriptorHelper.UnwrapGenericType(typeof(ICapability <>), handlerType) ?? HandlerTypeDescriptorHelper.UnwrapGenericType(typeof(IRegistration <,>), handlerType, 1); HasCapability = CapabilityType != null; if (!HasCapability) { CapabilityType = null; } if (HasCapability) { IsDynamicCapability = typeof(IDynamicCapability).GetTypeInfo().IsAssignableFrom(CapabilityType); } }
internal static IDisposable DynamicallyRegisterHandlers( IClientLanguageServer client, IObservable <Unit> initializeComplete, IServerWorkDoneManager serverWorkDoneManager, ISupportedCapabilities supportedCapabilities, IReadOnlyList <ILspHandlerDescriptor> descriptors ) { if (descriptors.Count == 0) { return(Disposable.Empty); // No dynamic registrations supported by client. } var disposable = new CompositeDisposable(); var result = initializeComplete .LastOrDefaultAsync() .Select( _ => { var registrations = new HashSet <Registration>(); foreach (var descriptor in descriptors) { if (descriptor.HasCapability && supportedCapabilities.AllowsDynamicRegistration(descriptor.CapabilityType !)) { if (descriptor.RegistrationOptions is IWorkDoneProgressOptions wdpo) { wdpo.WorkDoneProgress = serverWorkDoneManager.IsSupported; } registrations.Add( new Registration { Id = descriptor.Id.ToString(), Method = RegistrationNameAttribute.From(descriptor.RegistrationType)?.Method ?? descriptor.Method, RegisterOptions = descriptor.RegistrationOptions } ); } } return(registrations.Distinct(new Registration.TextDocumentComparer()).ToArray()); } ) .SelectMany( registrations => Observable.FromAsync(ct => client.RegisterCapability(new RegistrationParams { Registrations = registrations.ToArray() }, ct)), (a, b) => a ) .Aggregate((z, b) => z) .Subscribe( registrations => { disposable.Add( Disposable.Create( () => { client.UnregisterCapability( new UnregistrationParams { Unregisterations = registrations.ToArray() } ).ToObservable().Subscribe(); } ) ); } ); disposable.Add(result); return(disposable); }