AssocProgidElement

Instances of the ProgID type of assocation element are created by passing the corresponding CLSID to the AssocCreateElement function:

CLSID_AssocProgidElement {9016D0DD-7C41-46CC-A664-BF22F7CB186A}

As with all assocation elements, the ProgID element implements the IAssociationElement, IObjectWithQuerySource and IPersistString2 interfaces. A ProgID element is a significant elaboration of the basic shell element.

Initialisation String

When a ProgID element is initialised through its SetString method, the registry key that is used as the query source is:

Key: HKEY_CLASSES_ROOT\MappedProgID

where MappedProgID is generated from the initialisation string and from potentially many consultations of the registry. The first step is to obtain the basic ProgID. The algorithm for this has two distinct cases to it. In each, a list of candidate ProgIDs is found from various places in the registry and one more registry setting chooses from the list. SHELL32 presently provides for as many as 16 candidates.

File Associations

If the initialisation string is a file extension (meaning simply that it begins with a period), then the candidate ProgIDs are drawn from three sources. A ProgID may be specified as the default value of the given extension’s own subkey of HKEY_CLASSES_ROOT:

Key: HKEY_CLASSES_ROOT\.ext
Value: default
Type: REG_SZ or REG_EXPAND_SZ

where .ext is the initialisation string. More ProgIDs may be listed in a subkey:

Key: HKEY_CLASSES_ROOT\.ext\OpenWithProgIds

Each value in this key names a candidate ProgID. Data for the value is immaterial. All that matters is the name of the value. Yet more ProgIDs may be specified in the key:

Key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ext\OpenWithProgIds

Each value in this key names a candidate ProgID provided that it is a readable subkey of HKEY_CLASSES_ROOT. Again, whether the value even has data is immaterial.

The chosen ProgID is the data from the following registry value:

Key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ext\UserChoice
Value: Progid
Type: REG_SZ or REG_EXPAND_SZ

If this value has no string data, then the first candidate is chosen by default. If there are no candidates, the ultimate default is Unknown.

Note that the string data for this value is ordinarily chosen as the ProgID even if it is not among the candidate ProgIDs. The way this happens in the code is that the UserChoice ProgID is added to the list and therefore is among the candidates (given that the list does not overflow). But if it is always to be in the list, then why build the list? This code is new for Windows Vista and is plainly not complete: its analysis may need to be revisited to see how the code settles in later versions.

URL Associations

If the initialisation string does not begin with a period, then the initialisation string is itself the first candidate ProgID. More may be named as values in the key:

Key: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Shell\RegisteredApplications\UrlAssocations\InitString\OpenWithProgIds

The chosen ProgID is the data from the following registry value:

Key: HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\InitString\UserChoice
Value: Progid
Type: REG_SZ or REG_EXPAND_SZ

If this value has no string data, then the first candidate is chosen by default. If there are no candidates, the ultimate default is Unknown. (As for file associations, the string data for this value is ordinarily chosen as the ProgID even if it is not among the candidate ProgIDs.)

ProgID Key

The chosen ProgID must yet be mapped to a subkey of HKEY_CLASSES_ROOT. The ProgID key, which serves as the query source for the ProgID element, is

Key: HKEY_CLASSES_ROOT\MappedProgID

in which MappedProgID is in general the string data from the following registry value:

Key: HKEY_CLASSES_ROOT\ChosenProgID\CurVer
Value: default
Type: REG_SZ or REG_EXPAND_SZ

If this value cannot be read or is empty, then the mapped ProgID is just the chosen ProgID. This trivial mapping is also applied, regardless of any CurVer subkey, if the ProgID is Excel.Sheet.8. (This special case appears first in the SHELL32 version 6.00 from Windows XP SP1.) A more general case of trivial mapping expresses a preference that the ProgID key should have a shell subkey that can be opened for reading. If this preference is not met when using the mapped ProgID but would be without the mapping, then the mapping is abandoned and the ProgID key uses the chosen ProgID instead.

Queries

For most queries, a ProgID element is just a basic shell element with a different query source. However, two queries are defined just for ProgID elements and three others behave differently.

When the initialisation string for a ProgID element is a file extension, the element has a secondary query source which is used for any query whose ASSOCQUERY value has the 0x80000000 bit set, if put to the QueryString or QueryGuid methods. At present, just two queries are defined for this handling:

Query Key Value
0x80070002 HKEY_CLASSES_ROOT\.ext Content Type
0x81470002 HKEY_CLASSES_ROOT\MappedProgID\ShellEx\extra
HKEY_CLASSES_ROOT\.ext\ShellEx\extra
default

where extra is provided as the second argument to the query method. Query 0x80070002 is valid only for ProgID elements and can be answered only from the extension key. For query 0x81470002, the special handling is a fall-back. If the query cannot be answered from the ProgID key it is answered instead from the extension key.

Query 0x00020014 is defined for ProgID elements such that QueryExists succeeds if a ProgID element has a file-extension key as a secondary source.

Two other queries have fall-backs when put to a ProgID element through QueryString. If query 0x00170000 cannot be answered from the FriendlyTypeName value in the ProgID key, as usual for other association elements, it is answered instead from the default value in the ProgID key. If query 0x00070004 cannot be answered from the Progid subkey of the ProgID key, it is answered instead with the (unmapped) ProgID as determined above from the initialisation string.