Geoff Chappell - Software Analyst
CURRENT WORK ITEM - PREVIEW ONLY
The IAssociationElement methods of an association element all query the element about an association setting. The IAssociationArray methods of a QueryAssociations object do the same but for an ordered list of elements. In both interfaces, each method has as its first argument a value from the ASSOCQUERY enumeration. This value describes the setting that is sought. For some ASSOCQUERY values, the description must be completed by a string which is given as the method’s second argument. For consistency with Microsoft’s documentation of the IQueryAssociations methods, this second argument is here called pszExtra.
Every association element has a query source, which is in general a registry key. Most ASSOCQUERY values map simply to a value on some relative path (subkey) with respect to the key that acts as the element’s query source. The result of such a query is the data from the value. The path may be absent, to indicate that the value is in the key represented by the query source itself rather than in any subkey. The value may be absent to stand for the default value of whatever key is represented by the path.
The ASSOCQUERY values have some interpretation in bit fields, to specify general behaviour, the nature of the pszExtra argument, and the formatting of any data produced by the query:
|0x00010000||responds to QueryString method|
|0x00020000||responds to QueryExists method|
|0x00040000||responds to QueryDirect method|
|0x00080000||responds to QueryDword method|
|0x00100000||obtains resource string when data from QueryString is indirect string|
|0x00200000||responds to QueryObject method|
|0x00400000||responds to QueryGuid method|
|0x01000000||expects pszExtra for path or value|
|0x02000000||expects pszExtra for verb|
|0x80000000||fall-back to secondary query source|
The meaning of bits for responsiveness to various methods is more complicated than suggested by the brief descriptions above. As actually implemented, most queries cannot respond successfully to QueryString, QueryDword, QueryGuid or QueryExists unless the bit for responding to QueryDirect is also set.
By indirect string is here meant the standard form supported by the SHLWAPI function SHLoadIndirectString for naming a string resource in an executable. Briefly, the form is an @ sign, a pathname for the executable, a comma, a minus sign and a resource number. If the 0x00100000 bit is set for the query and the string data for the queried association is an indirect string, then the data produced by the QueryString method is the string resource, not the indirect string. SHELL32 is presently limited to 1024 characters for loading the string resource.
All association elements, of whatever type, can be queried for any value in the element’s query source. The pszExtra argument to the method names the value.
|extra||if failed with extra as value, but extra is DocObject or BrowseInPlace|
|0x01170001||extra||obtains resource string when data from QueryString is indirect string|
The only bit field that matters in the numerical values for these queries is 0x00100000. Both queries therefore respond to all of QueryString, QueryDword, QueryGuid, QueryExists and QueryDirect.
Note that the 0x010F0000 query allows that two particular values may instead be present as subkeys. In these cases, the data is from the default value of the subkey. It is not enough that DocObject or BrowseInPlace exists as a subkey: it must have a default value.
Most shell elements can be queried for all the following. All respond to QueryString, QueryExists and QueryDirect.
|0x00170000||FriendlyTypeName||obtains resource string when data from QueryString is indirect string|
|0x81470002||ShellEx\extra||also responds to QueryGuid|
|0x00470003||Clsid||also responds to QueryGuid|
Some types of shell element are more particular.
TO BE DONE
All shell elements recognise the following queries in which the pszExtra argument supplies a verb. All these queries respond to QueryString, QueryExists and QueryDirect except where otherwise noted.
|0x02070003||shell\verb\ddeexec\application||has fall back for QueryString (see notes after table)|
|0x02070004||shell\verb\ddeexec\topic||has fall back for QueryString (see notes after table)|
|0x02060005||shell\verb\ddeexec||NoActivateHandler||responds to QueryExists and QueryDirect only|
|0x02060006||shell\verb\command||command||responds to QueryExists and QueryDirect only|
|0x02010007||responds to QueryString only;
obtains pathname of executable (see notes after table)
|0x02170008||shell\verb||FriendlyAppName||translates when data from QueryString is indirect
has fallback for QueryString (see notes after table)
|0x0207000B||responds to QueryString only;
|0x0247000C||shell\verb\DropTarget||Clsid||also responds to QueryGuid|
|0x0247000D||shell\verb\command||DelegateExecute||also responds to QueryGuid|
|0x0220000E||responds to QueryObject only;
creates verb delegate (see notes after table)
|0x0220000F||responds to QueryObject only;
creates application delegate (see notes after table)
|0x02200010||responds to QueryObject only;
creates execution association (see notes after table)
|0x02020011||shell\verb||Elevate||responds only to QueryExists;
actually checks for whether verb is “runas” (see notes after table)
|0x02070012||shell\verb\command||IsolatedCommand||has fallback for QueryString (see notes after table)|
In general, query 0x02010007 extracts an executable’s pathname from the result of query 0x02070000 (meaning typically the default value of the command subkey). However, if the verb is “runas”, the data obtained is the whole of the default value. The latter behaviour is plausibly a coding error (a missing break in a switch), but may be deliberate.
When query 0x0207000B is directed at a shell element, it has some small merit in testing whether the given verb is well-defined for the element, i.e., that its query source has a usable shell\verb subkey. The query is arguably more useful when directed at a verb delegate, to discover which verb was specified when creating the verb delegate.
Query 0x0220000E creates a shell verb element, called the verb delegate, from the queried element and the given verb. The query source for the verb delegate is the shell\verb subkey. All the other shell verb queries can be put to this verb delegate, with the shell\verb part of the path taken as granted. When multiple shell verb queries for the same verb are to be put to the one shell element, it is much more efficient to create a verb delegate and put the queries to the verb delegate rather than the orginal element.
Query 0x0220000F creates an application element, called the application delegate, from the queried element and the given verb. The initialisation string for this application element is the result of query 0x02010007, i.e., is the executable’s pathname as extracted from the default value of the shell\verb\command subkey.
Query 0x02200010 creates an ExecuteAssociation object. Details are presently beyond the scope of this work.
Although tables map query 0x02020011 to the Elevate value in the query source, the query never actually can check this value. This is perhaps a coding error which may eventually be corrected. Without the 0x00400000 bit set, query 0x02020011 is always failed (returning E_INVALIDARG) by the code for interpreting the bits that determine responsiveness to the IAssociationElement methods. One case is allowed for correcting this result: if the verb is “runas”, then QueryExists succeeds independently of whether an Elevate value exists.
For several queries, the QueryString method has a fall back if string data cannot be obtained from the designated registry value:
|0x02070003||extract executable’s filename, i.e., with no path or extension, from the result of query 0x02010007|
|0x02070004||answer with the hard-coded string System|
|0x02170008||answer from the application delegate unless the queried element is already an application element|
|0x02070012||if the verb is “runas”, redo as query 0x02070000|
In ordinary practice, association elements are accessed through a QueryAssociations object, also called an association array. Such objects can be created, initialised and queried using documented functions and methods. Many, but nowhere near all, lower-level queries with an ASSOCQUERY value can be put to an association array as one or another case of an IQueryAssociations method:
|0x010F0000 specialised for EditFlags value||GetData||ASSOCDATA_EDITFLAGS|
|0x01170001 specialised for NoOpen value||GetString||ASSOCSTR_NOOPEN|
|0x01170001 specialised for InfoTip value||GetString||ASSOCSTR_INFOTIP|
|0x01170001 specialised for QuickTip value||GetString||ASSOCSTR_QUICKTIP|
|0x01170001 specialised for TileInfo value||GetString||ASSOCSTR_TILEINFO|
For query 0x0220000F, which obtains an interface to an object, the corresponding case with the GetKey method is not truly equivalent but merely obtains the registry key that the object uses as its query source.