views:

1099

answers:

3

I have a set of C# (v2) apps and I am struggling with registry virtualization in Win7 (and to a lesser extent Vista).

I have a shared registry configuration area that my applications need to access in HKLM\Software\Company... Prior to Vista, everything was just written to and read from that location as needed.

The code appropriately detected failures to write to that registry key and would fall back appropriately (writing to HKCU instead and notifying the user that the settings they had applied would only affect the current user).

In Vista, registry virtualization broke all of this because the access check we were using for the HKLM write would "succeed" silently and virtualize to HKCR\VirtualStore\Machine... instead. In this case, the user would think that they had saved machine-wide configuration, but had instead only written to the virtual store.

Sadly, even attempting to enumerate the permissions on the HKLM reg key explicitly returns results indicating that the user has access whether they do or not.

When we added Vista support, the workaround we used was to perform a probe write to HKLM... and then check in HKCR\VirtualStore\Machine... for the same value and note that virtualization had occurred if the value was found.

Win7 seems to have broken this (again) because queries against the explicit virtual location (HKCR) now show merged results from the HKLM location even if the write was not virtualized.

Does anyone have any suggestions for working around this?

Constraints: - I need a solution that works without requiring elevation (when I don't have administrator level permissions I will fallback to a per-user configuration in HKCU but I need to be able to detect this case reliably).

  • It needs to work with a v2 C# app (One option I have seen for C++ code is to embed a manifest which disables virtualization for the .exe but I haven't been able to do that in C# V2 see http://stackoverflow.com/questions/873676/disable-folder-virtualization-in-windows).

  • It needs to work without an "installer" (this precludes the ability to disable virtualization on the registry key that we need ala the REG FLAGS... command).

A: 

You can enable / disable virtualization on a per key basis, according to this, but it tells you to use a command line tool. But there must be a way to do it programmatically.

It might be easiest just to turn off virtualization in your app completely by setting requestedExecutionLevel in your manifest. You can try highestAvailable, but that might mean your app always runs as Administrator. It seems to imply just setting it to asInvoker will turn off virtualization. See also.

jeffamaphone
Unfortunately I can't disable virtualization on the key, because I would have to be elevated to do that.I also can't use the manifest approach, because that is only respected for the entry .exe, and not when I'm hosted in another application. (it is also not supported by the 2.0 C# compiler)
A: 

Note that HKCR is a virtualized store itself, a combination of HKLM\Software\Classes and HKCU\Software\Classes.

The best approach would be to not even let the registry virtualization take place. Firstly check to see the user is is elevated at runtime and then you can notify the user that changes will only be applied to the current user before they even start making changes.

By detecting if you are an elevated administrator in the first place you can simply avoid writing to HKLM when it's going to be virtualized.

Example:

private bool IsAdministrator
{
    get
    {
        WindowsIdentity wi = WindowsIdentity.GetCurrent();
        WindowsPrincipal wp = new WindowsPrincipal(wi);

        return wp.IsInRole(WindowsBuiltInRole.Administrator);
    }
}

Note: I don't code in C#, example is lifted from question How can I detect if my process is running UAC-elevated or not?

sascha
+1  A: 

This is an excellently put question, +1 (Why is it community wiki, it deserves points!)

In general, there are a set of rules (which [as you've run into] will vary over time) which control whether UAC [and thus implicitly Registry] virtualization are in play.

Some salient parts of the Registry Virtualization rulesets documentation in MSDN are:

  1. [as jeffamaphone says] if the manifest has a requestedPrivileges/requestedExecutionLevel set, it's turned off. You dont seem to have ruled out adding a manifest, so can you please indicate why this won't work for you? (You say "I haven't been able to do that in C# V2" - there is an Add Item option to add an application manifest file, and that's available in VS2005)
  2. if the exe is running 64 bit, its off by default
  3. if it's not an interactive process (such as a service, or hosted in IIS etc.), it's off

If you're not in a position to influence any of the above, which is the ideal, and you thus want to detect whether UAC virtualisation applies in the current context, use this answer to a what might at first not appeat to be a related question. (Obviously you'd still need to decide whether it applies to the specific key you're operating on, which is a moving target which you obviously wouldnt want to implement code that needs to track changes if it can at all be avoided - but in most cases it should be relatively clear.)

Ruben Bartelink