dspace-group/dscom

Component Category Registation

Closed this issue · 4 comments

I think this section need some more explanation as I have my doubts about this:

using var componentCategoryKey = Registry.ClassesRoot.CreateSubKey(RegistryKeys.ComponentCategories);
using var managedCategoryKey = componentCategoryKey.CreateSubKey(RegistryKeys.ManagedCategoryGuid);
var key0 = Convert.ToString(0, CultureInfo.InvariantCulture);
var value = managedCategoryKey.GetValue(key0);
if (value is not null && value.GetType() != typeof(string))
{
managedCategoryKey.DeleteValue(key0, false);
managedCategoryKey.SetValue(key0, RegistryValues.ManagedCategoryDescription);
}
else if (value is not null)
{
var keyValue = (string)value;
if (!StringComparer.InvariantCulture.Equals(keyValue, RegistryValues.ManagedCategoryDescription))
{
managedCategoryKey.SetValue(key0, RegistryValues.ManagedCategoryDescription);
}
}
else
{
managedCategoryKey.SetValue(key0, RegistryValues.ManagedCategoryDescription);
}

My concerns are as follows:

  • This is a registry key that's not ours to write because that is Microsoft's responsibility to write the component category key as part of the .NET installation. I would think it's more appropriate to check if the key exists and if it doesn't, to exit with an error.

This method can only be called by the owner of a category, usually as part of the installation or de-installation of the operating system or application.
Reference

  • This is adding a locale of 0 (e.g. LOCALE_NEUTRAL). When I look at all other component categories within the HKCR\Component Categories\, I do not see any other categories with a neutral locale. In fact, on my computer, all have the same locale of 409 (e.g. en-us locale). I'm not sure how that looks on other computers. I would expect that as part of the .NET installation, it will use the appropriate locales and thus it isn't our responsibility to add it.

From my testing, ICatRegister::RegisterCategory will not register the category unless running in an elevated context, which fits the expectation because those are described in HKLM exclusively, never in HKCU, and the ICatRegister will write to the HKLM only. Indeed, when running non-elevated, it won't even throw an error but silently gives S_OK even though no registry keys were written. I cannot find any documentation suggesting whether a component category can be registered non-elevated and even though HCKR will reflect HKCU (which normally does not have the Component Categories key and must be manually added), I don't think anyone has used components on a per-user level, only at per-machine level. That makes sense because the component categories are normally used to support tasks such as displaying an dialog to select from a list of controls that can be inserted into a container.

Can you provide a counterexample as to why this code is necessary? The code to register a component as implementing a certain category certainly is appropriate but I'm not so sure we ought to be registering category that aren't ours.

Addendum:

After posting above, I found this article which does list component categories as one of elements that's merged in the HKCR which mirror my manual test even though I did not have any per-user categories registered. The only problem is that for older software that's incorrectly using HKLM rather than HKCR; those will not work correctly if the data is in HKCU even though it will also appear in HKCR. If you are aware of such examples where HKLM is essential we ought to consider this. In the example of registering a neutral locale key, that could be written to HKCU instead of HKCR which would then remove the need to elevate the privileges for registering the assembly.

I think @carstencodes has implemented this similar to what Microsoft has done.
See: https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/registrationservices.cs

LOCALE_NEUTRAL is currently a limiation
See: https://github.com/dspace-group/dscom#limitations

Ok, from this section, it appears that it's a precaution in the unusual case where the managed category key was deleted which makes more sense. It is not always creating the key but only if it didn't exist. The difference between this and the one in dscom is that dscom always creates the key and thus adds the LOCALE_NEUTRAL whereas Microsoft's version would only do that if it didn't exist already.

To be sure, the locale for the category is a separate thing from the locale for the type library and is totally unrelated so the limitation of dscom for generating a localized type library is not relevant, I think.

Therefore, I suggest that the changes be made as following:

  1. Wrap dscom's section above in a existence check for the category within the Component Categories folder; so that we only create the keys using LOCALE_NEUTRAL if we do not have it already.
  2. If it exists, at least do an additional check if the locale subkey also exists. If it exists, then we don't need to worry about it. If for some reasons there are no subkeys under that category ID, we would also add it. This is an additional step that Microsoft's source code does not do, but appropriate in the spirit of taking precautions to ensure that it is exist.
  3. Currently both dscom and Microsoft mandate the use of HKCR (implicitly writing to HKLM), and therefore requires elevated privileges to perform the action. That is a limitation with both sources. Research will be needed whether we want to attempt writing into HKCU which as the link in the addendum seem to indicate is possible if registering on a per-user basis rather than per-machine basis. I'm inclined to simply bail out with an error if the category doesn't exist and we are not running elevated.

Sounds good!
I think we should change it so.