On my system, the string "Microsoft.Windows.ActCtx" cannot be found anywhere in the registry.
The class string is resolved by passing it to CLSIDFromString. AutoHotkey is not responsible for any part of this process; it just passes the string to CLSIDFromString and receives a CLSID or an error, and passes the CLSID to CoCreateInstance. You can replicate the error with
Guid_FromStr:
Code: Select all
Guid_FromStr("Scripting.Dictionary", clsid)
MsgBox % Guid_ToStr(clsid) ; Shows the CLSID.
Guid_FromStr("Microsoft.Windows.ActCtx", clsid) ; Throws an exception.
MsgBox % Guid_ToStr(clsid)
Using Process Monitor while calling CreateObject showed different results for this and some other class that doesn't exist, so CreateObject is evidently identifying ActCtx before doing anything Process Monitor can detect, which means it does so without reading the registry. In other words...
CreateObject must be instantiating ActCtx through the use of
registration-free activation, which I assume is what you want the ActCtx object for in the first place.
Process Monitor did show failed attempts to open a
CLSID\{056EC0EB-79F7-4EBD-9B99-042EAE267CA0} reg subkey from different places. I could not find this CLSID in the SDK or by searching the Internet or my system (.dll and .manifest) files, but if I pass it to ComObjCreate,
I get an ActCtx object.
Code: Select all
; Shows ActCtx.
MsgBox % ComObjType(ComObjCreate("{056EC0EB-79F7-4EBD-9B99-042EAE267CA0}"), "Class")
After further searching I eventually found
CLSIDFromProgID (again). The documentation for this and
CLSIDFromString is quite sparse. You may compare:
CLSIDFromString: Converts a string generated by the StringFromCLSID function back into the original CLSID.
CLSIDFromProgID: Looks up a CLSID in the registry, given a ProgID.
It might appear that CLSIDFromString only needs to handle GUID strings, since StringFromCLSID only ever returns strings in that format (because "StringFromCLSID calls the StringFromGUID2 function"). However, there's a clue that it handles ProgIDs in the list of error codes:
REGDB_E_CLASSNOTREG: The CLSID corresponding to the class string was not found in the registry.
By contrast, CLSIDFromProgID
only handles ProgIDs. If we used it exclusively, we would be unable to instantiate classes that are registered only by CLSID... just like VBScript.
It appears that CLSIDFromProgID can resolve "Microsoft.Windows.ActCtx":
Code: Select all
VarSetCapacity(clsid, 16, 0)
r := DllCall("ole32\CLSIDFromProgID", "wstr", "Microsoft.Windows.ActCtx"
, "ptr", &clsid)
MsgBox % r < 0 ? Format("Error {:x}", r & 0xFFFFFFFF) : Guid_ToStr(&clsid)
The documentation clearly indicates that it looks up the ProgID in the registry, but that is evidently not the only way it resolves a ProgID.
I will change ComObjCreate to use CLSIDFromProgID for non-GUID strings.