// Setup the registry entries required when an extension is given our handler public void SetupHandlerForExtension(Profile selectedProfile, bool createMergedProfile) { if (!IsElevated) { throw new AssocMgrException { Description = LocalizedMessages.AdminPrivilegesNeeded, Exception = null, ErrorCode = WindowsErrorCodes.ERROR_ACCESS_DENIED } } ; if (PropertyHandlerState != HandlerState.None && PropertyHandlerState != HandlerState.Foreign) { throw new AssocMgrException { Description = String.Format(LocalizedMessages.ExtensionAlreadyHasHandler, Name), Exception = null, ErrorCode = WindowsErrorCodes.ERROR_INVALID_PARAMETER } } ; Profile profile; // Work out what profile to set up if (PropertyHandlerState == HandlerState.None || !createMergedProfile) { profile = selectedProfile; } else { // We use a custom profile with the same name as the extension profile = State.CustomProfiles.FirstOrDefault(p => p.Name == Name); // If it doesn't already exist, create it if (profile == null) { profile = new Profile { Name = this.Name, State = this.State }; State.CustomProfiles.Add(profile); } // If we're recycling the profile, clone it to preserve its original values else if (profile == selectedProfile) { selectedProfile = selectedProfile.CreateClone(); } } // Find the key for the extension in HKEY_CLASSES_ROOT using (RegistryKey target = GetHKCRProfileKey(true)) { // We used to place entries on this key, but no longer do, because such keys can be shared, // and we only want to affect a specific extension // We still have to hide any existing entries, because otherwise they would take priority, but fortunately they do not often occur // If there are entries, and we are merging, we read them into the new profile, in case this is the only place they occur if (PropertyHandlerState == HandlerState.Foreign) { GetAndHidePreExistingProgidRegistryEntries(target, createMergedProfile ? profile : null); } } // Now we only update the extension specific area using (RegistryKey target = GetSystemFileAssociationsProfileKey(true)) { if (PropertyHandlerState == HandlerState.Foreign) { if (createMergedProfile) { GetAndHidePreExistingProgidRegistryEntries(target, profile); // Merge the selected profile into any entries that came with the foreign handler profile.MergeFrom(selectedProfile); } else { GetAndHidePreExistingProgidRegistryEntries(target, null); } } SetupProgidRegistryEntries(target, profile); } if (PropertyHandlerState == HandlerState.Foreign) { // Write the updated custom profile information back to the store State.StoreUpdatedProfile(profile); } #if x64 // On 64-bit machines, set up the 32-bit property handler, so that 32-bit applications can also access our properties using (RegistryKey handlers = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X86). OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers", true)) { using (RegistryKey handler = handlers.CreateSubKey(Name)) { if (PropertyHandlerState == HandlerState.None) { var temp = handler.GetValue(null); // In the case where there is no 64-bit handler, but there is a 32-bit handler, leave it alone if (temp == null) { handler.SetValue(null, OurPropertyHandlerGuid32); } } else // Foreign { var temp = handler.GetValue(null); handler.SetValue(null, OurPropertyHandlerGuid32); handler.SetValue(ChainedValueName, temp); } } } #endif // Now, add the main handler extension key, which is 32- or 64-bit, depending on how we were built // The 32-bit and 64-bit values of these are separate and isolated on 64-bit Windows, // the 32-bit value being under SOFTWARE\Wow6432Node. Thus a 64-bit manager is needed to set up a 64-bit handler using (RegistryKey handlers = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers", true)) { using (RegistryKey handler = handlers.CreateSubKey(Name)) { if (PropertyHandlerState == HandlerState.None) { handler.SetValue(null, OurPropertyHandlerGuid); this.RecordPropertyHandler(HandlerState.Ours, null, null); } else // Foreign { handler.SetValue(null, OurPropertyHandlerGuid); handler.SetValue(ChainedValueName, PropertyHandlerGuid); this.RecordPropertyHandler(HandlerState.Chained, PropertyHandlerGuid, PropertyHandlerTitle); } } } this.Profile = profile; State.HasChanged = true; }