I have read through many Stack Overflow questions as well all related Microsoft documentation I could find, however, I couldn't discover an exact answer.
I'm registering my program as a default application for a specific extension in Windows 10. I added the following entries to the registry:
HKCU\Software\Classes\my-program.ext
HKCU\Software\Classes\.ext\(Default) = my-program.ext
HKCU\Software\Classes\.ext\OpenWithProgIds\my-program.ext
Everything works fine, the association is successfully created.
However, I don't understand the purpose of the OpenWithProgIds. I thought it represents the list of alternative applications for this extension, however, even without adding my-program.ext to OpenWithProgIds my program is still present in the "Open With" list as well as all the previous applications registered through .ext\(Default).
Seems that there is some kind of cache containing all the previously associated programs for a specific extension. But if so, why do we need OpenWithProgIds at all? Probably this behavior was introduced in Windows 10, and the OpenWithProgIds is considered obsolete.
I would be grateful for any thoughts or clarifications.
According to the documentation, the purpose of the OpenWithProgIDs subkey is to provide a better experience for the user.
Excerpt:
You can register different applications that are able to open a particular file extension by adding versioned ProgIDs as values to the HKEY_CLASSES_ROOT<extension>\OpenWithProgids key. This registry key contains a list of alternate ProgIDs associated with the file extension. The applications associated with the listed ProgIDs appear in the Open With Product Name submenu. If the same application is specified in both the OpenWithList and OpenWithProgids keys, the operating system merges the duplicates.
Related
I'm trying to set up a test application on Windows to launch via a "myapp://website.com"-style URI. Mostly, I'm basing myself off of tutorials like this:
http://msdn.microsoft.com/en-us/library/ie/aa767914(v=vs.85).aspx
While I got the initial setup working inside HKEY_CLASSES_ROOT, a new constraint is for the installation to happen without requiring administrator access. So, I deleted all changes in CLASSES_ROOT, and decided to retry the registry additions, instead using the HKEY_CURRENT_USER branch, at HKEY_CURRENT_USER/Software/Classes/myapp.
This appears to be detected by the browsers, and they display their confirmation dialog. However, they never actually run the app. Internet Explorer gives the most helpful error message, with a dialog saying "Unable to open this helper application for {uri}. The protocol specified in this address is not valid. Make sure the address is correct, and try again.
Is there some part of the registry I'm missing for a non-administrator setup? This is an export of my changes as a .reg. (Dashes censoring my username). EditFlags was added as a guess, but didn't work without it either.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\myapp]
"URL Protocol"=""
#="URL:David Protocol"
"EditFlags"=dword:02000000
[HKEY_CURRENT_USER\Software\Classes\myapp\DefaultIcon]
#="C:\\Users\\------\\AppData\\Roaming\\-----s Stuffs\\URISchemeTest.exe,1"
[HKEY_CURRENT_USER\Software\Classes\myapp\shell]
[HKEY_CURRENT_USER\Software\Classes\myapp\shell\open]
[HKEY_CURRENT_USER\Software\Classes\myapp\shell\open\command]
#="\"C:\\Users\\-------\\AppData\\Roaming\\------s Stuffs\\URISchemeText.exe\" \"%1\""
Now that I have this working, I can't be perfectly certain of what it was that was causing problems, but I can at least give an account of what I tried to do differently in the hopes this helps future researchers.
%-sign directory accessors might not be supported by the path declaration. If they are, they may need to be encoded a certain way. Lower down In the article linked in the question, it mentions how Internet Explorer may decode certain URL parameters, but other browsers may not. Either way, if you've been specifying the command line as "%APPDATA%/MyProgram.exe", it may be more reliable starting from "C:/" until you can work through that issue.
EDIT: One other thing I just noticed, if the Paste from my question is correct: My working version of the registry changes set the default key of the root to "URI :David Protocol". Note "URI", not "URL". It's possible that mis-naming that (easy since another value is declared as "URL Protocol") could break the resulting effects.
While you might not have to specify a DefaultIcon, you may want to be careful that you're not referring to an invalid one. For safety, I set up mine to point specifically to a .ico file, rather than ".exe,1"
As some other commenters mentioned, I don't think EditFlags is really necessary, and might not be related.
A cautionary rebuttal to the highly-voted answer near this one, though: This. Works. No UAC access necessary. From the outset of my research, I personally would have believed an explanation that it's too risky to allow without a UAC admin prompt, etc. However, I took the time to test it, and could write a simple program with a button that sets itself up under HKCU/Software/Classes, and is accessible to the browser. I then tested it from the computer of a developer who had never taken part in any of my research (clean environment), and without any admin prompts, it worked fine. (Obviously, this program will only be accessible to the current user)
(For easy reading, a reminder: HKCU = HKEY_CURRENT_USER. HKCR = HKEY_CLASSES_ROOT. HKLM = HKEY_LOCAL_MACHINE)
Anything that could write to the user's HKCU registry already has non-admin binary access. Furthermore, all browsers will show a warning message about launching the program before opening it (perfectly understandable, given that it's local code). Several of them even give the full folder path of the executable you'll be launching.
I know the tutorial said to put the key in HKCR; and that this is known to come from HKLM/Software. However, it's worth reading up the whole story here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
This key is partially derived from the HKCU hive - and in fact, the user's settings will override the local machine settings. There is nothing specifically indicating that HKLM will override HKCU when displaying this type of key inside of HKCR.
You cannot ignore what the MSDN article tells you, registering the protocol handler in a HKCR key is a hard requirement.
There's a good reason for that, also fairly explicitly stated in the article, protocol handlers are dangerous. They allow an arbitrary web page to start a program on your machine. They even work inside a Store app, another example of a heavily secured runtime environment that runs code inside a sandbox that stops dangerous operations.
Documenting HKCR doesn't help much unravel this, it was meant for appcompat with 16-bit code and today is an alias. Shows a merged view of both HKCU and HKLM keys. The HKLM keys are different from HKCU keys, writing key values require elevation. Only a program that can acquire a elevated security token can create new values or alter them, normally obtained by going through the UAC prompt. The problem with HKCU keys is that any program can write keys there without elevation. Which would open up a security hole if protocol handlers could be registered in a HKCU key. So this cannot work, urlmon simply doesn't look at the HKCU keys to find the protocol handler.
Windows Shell Scripting (vbs) has the following method:
object.GetObject(strPathname [,strProgID], [strPrefix])
Now suppose I have the following code:
set myval = getObject("myObjectRef:myObjectArgs")
This works on one machine - and not on another.
What I want to do is find the definitive list where all the myObjectRef/progIds are maintained.
My question is:How are the GetObject progids maintained?
Assumptions:
I'm looking for an answer more sophisticated that "do a search in the registry"
I'm looking to find a particular place where I can go looking for my progid to see if it exists or not.
I'm looking for an answer more sophisticated that "do a search in the registry"
Well, that's a bit difficult because that is really all it takes. You don't exactly have to "search", just look at where you expect it to find. Which is right underneath the HKEY_CLASSES_ROOT hive in regedit.exe, the keys are sorted alphabetically so just type the "m" key on your keyboard and you are already close the progid you are looking for. If you don't see the "myObjectRef.myObjectArgs" key then you can count on a kaboom at runtime when COM cannot find it either.
There is no "definite list" and no entity that maintains progids to ensure that they are unique. The list is specific to each machine, whatever was installed on that machine determines what you find back with Regedit.exe. They are simply a human-friendly version of the GUID, the value that really matters to locate a COM component. A Globally Unique ID that unambiguously identifies the server. The CLSID subkey of the progid key provides that GUID. It is a big number, not very human-friendly.
The progid key is written to the registry when the component installs itself. So a missing key simply means that it isn't installed.
A not uncommon problem on machines that boot a 64-bit version of Windows is that the COM server is only available as a 32-bit component but the client is a 64-bit process. This is resolved in the registry as well, the CLSID key is only present in HKLM\Software\Wow6432Node\Classes. The Wow6432Node section is what a 32-bit client sees. So a 64-bit client looks in HKLM\Software\Classes and won't find the key. Looks just like a "not-installed" problem, even though it is actually present. Just not the 64-bit version of it. SysInternals' Process Monitor is a great tool to diagnose problems like this. You see the failing client program searching through the registry.
I have been trying to find a way to "defragment" the registry on my Windows machine. Firstly, does this make sense? Any benefits in doing this? (Not much love on superuser.com) Secondly, I am looking for a way to rewrite the registry using C/C++ with Windows API. Is there a way to read the registry and write it to a new file getting rid of unused bytes along the way? (I might have to write the new file and then boot into another OS/disk before I can overwrite the original... but I am willing to take that risk.)
Microsoft's PageDefrag does exactly this, as it states on its page "PageDefrag uses the standard file defragmentation APIs to defragment the files."
(A copy of the linked article is here because in typical MSDN style their link is dead.)
http://www.larshederer.homepage.t-online.de/erunt/ - NTREGOPT NT Registry Optimizer
Similar to Windows 9x/Me, the registry files in an NT-based system
can become fragmented over time, occupying more space on your hard
disk than necessary and decreasing overall performance. You should
use the NTREGOPT utility regularly, but especially after installing
or uninstalling a program, to minimize the size of the registry files
and optimize registry access.
The program works by recreating each registry hive "from scratch",
thus removing any slack space that may be left from previously
modified or deleted keys.
http://reboot.pro/index.php?showtopic=11212 - Offreg.dll MS WDK Offline Registry Library
The offline registry library (Offreg.dll) is used to modify a registry hive outside the active system registry. This library is intended for registry update scenarios such as servicing an operating system image. The library supports registry hive formats starting with Windows XP.
Developer Audience
http://reboot.pro/topic/11312-offline-registry/ - Offline Registry MS WDK Command-Line Tool
A command line tool that will allow one to read and write to an offline registry hive.
Reading the values should be possible.
But I've never seen any spec for how the registry files are written to disk, and unless you could find one you'd have to reverse engineer those files in your OS (might be differences between XP and 7 etc). Then you have to remember that the registry isn't just one file, it's multiple files and some of them belongs to certain users and I think they use SIDs rather than user names so even if you move them to a new computer, you have to be sure it's the same OS version with the same users with the same SIDs set up on it.
All this for little or no gain so I'd agree with the superuser users that it wouldn't make sense.
To me its a no-brainer. The settings for my program go into the Windows Registry. After all, that's what it's for, isn't it?
But some programmers are still hesitant in using the Registry. They state that as it grows it slows down your computer. Or they state that it gets corrupted and causes your computer to malfunction.
So they write their own configuration files, or may use the INI files that Microsoft has depreciated since a few OS's ago.
From what I hear, the problems with the registry that occurred in early Windows OS's were mostly fixed as of Windows XP. It may be the plethora of companies that make Registry Cleaners that are keeping up the rumors that "registry bloat" and "orphaned entries" are still bad.
So I ask, is there any reason today not to use the Windows Registry to store my program configuration settings?
If the user does not allow registry access, you're screwed.
If the user reinstalls Windows and he wants to migrate his settings, it's much more complicated than with a simple file
Working with a config file means your app is portable
Much simpler for the user to change a setting manually
When you'll want to port your app to other OS, what are you gonna do with your registry settings ?
Windows Registry is bloated. Do you really want to contribute to this chaos?
For me, quickly installing, migrating and moving applications is a key point to productivity. I can't if I need to care of hundreds of possible registry keys. If there's a simple .ini or .cfg or .xml file somewhere in my user folder (or even the application directory if it is a portable app), migration is easy.
Often-heard argument pro registry: easy to write and read (assuming you're using plain WinAPI). Really? I consider the RegXXXfamily of functions pretty verbose ... too many function calls and typing work for storing just a few bits of information. So you always end up wrapping the registry away .. and now compare this effort with a simple text configuration file, maybe just key=value-like.
It depends, when you have small entries that need to read by multiple programs registry is ok, as database have locking issues, and config files are application based.
The problem happens when the user does not allow registry access, that are lots of software in the market that will show a pop up when anyone tries to modify registry and the user can cancel or allow the users. These programs are too common with the anti virus programs.
Putting your settings into the Registry means that if your user wants to move your program and its settings to another computer, he can't. Backup, ditto. Those settings are in a mysterious invisible place. I find this to be a hostile approach to one's users.
I've written numerous small-to-medium programs, and always used a .ini file. A tech-savy user can edit this file using an editor, he can check the settings in it, he can email it to a tech supporter, he can do a large variety of things that are significantly harder to do with registry entries.
And my programs don't contribute to slowing the computer down.
Personally speaking, I just don't like binary configuration of any type. I much prefer text file format which can be easily copied, edited, diffed & merged, and put under change control complete with history.
The last of these is the biggest reason not to use the registry - I can stick configuration files into SVN (or similar) with the full support given to text files, instead of having to treat it as a blob.
I don't really have much of an opinion for or against using the registry, but I'd like to note something... Many answers here indicate that registry access may be restricted for a certain user. I'd say the exact same thing goes for config files.
With registry you need to write to the "current user" to be fairly certain about having access (and should do so anyway, in many cases). Config files should be put in a user based area as well (e.g. AppData/Local) if you want "guaranteed" access without questions asked. As far as I know putting config files in "global" areas are as likely to yield access problems as the registry is.
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 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).
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:
[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)
if the exe is running 64 bit, its off by default
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.)
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.
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?
I had a similar problem and the introduction of a manifest solved it.
I was relying on the registry security to prevent the (Win32) application from creating keys in the HKLM/Software/Wow6432Node when running as standard user, and was quite surprised to see that it was succeceding regardless, but no key was present and it was created instead under this new VirtualStore area.
The registry virtualization is switched off when the PE manifest is found to contain information related to the security. To not require elevation of privileges my manifest contains the following node:
<trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker">
</requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
For the executable to be compatible with Vista and XP, apparently each node in the TrustInfo section must contain the namespace:
<ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
<ms_asmv2:security>
<ms_asmv2:requestedPrivileges>
<ms_asmv2:requestedExecutionLevel level="asInvoker">
</ms_asmv2:requestedExecutionLevel>
</ms_asmv2:requestedPrivileges>
</ms_asmv2:security>
</ms_asmv2:trustInfo>
Once the manifest was correctly embedded in my .exe (it took me a couple of attempts by modifying the appropriate properties of the project), the program was at last failing as I was expecting.
For managed code, the manifest can be included as a post-build step by running the mt.exe tool. For instance, as reported in the MSDN article
mt.exe –manifest YourFile.manifest –outputresource:YourApp.exe;#1
I prefer using the manifest approach rather than modifying the flags of the registry nodes using reg.exe as explained in this article as this makes the behaviour consistent on all machines.
Hope that helps (even if, after having read the date of the original posting, I'm pretty sure the problem has been solved long ago!!)
Alberto