When used with a 'modern' explorer file list (DirectUIHWND) it returns something recognized as an object by AHK, but I found no way to access this object. ComObjValue() and also ComObjType() return empty strings and ComObjQuery() throws the exeption 'No valid COM object!'.
The following test script will get this result if select a single item and press Ctrl+Shift+s while the mouse cursor is over an an empty area of the explorer file list. Can anyone tell me how to access this object?
Code: Select all
#NoEnv
SetBatchLines, -1
^+s::
Acc := Acc_ObjectFromPoint()
MsgBox, % Acc_GetRoleText(Acc_Role(Acc))
Selection := Acc_Selection(Acc)
If !Selection.Length()
MsgBox, 0, Selection, Not Found!
Else {
Msg := ""
For Each, Selected In Selection {
If IsObject(Selected)
Msg .= Acc_Name(Selected) . " - " . Acc_GetRoleText(Acc_Role(Selected)) . "`n"
Else
Msg .= Acc_Name(Acc, Selected) . " - " . Acc_GetRoleText(Acc_Role(Acc, Selected)) . "`n"
}
MsgBox, 0, Selection, %Msg%
}
Return
; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves the address of the IAccessible interface pointer for the object displayed at a specified point on the screen.
; msdn.microsoft.com/en-us/library/windows/desktop/dd317977(v=vs.85).aspx
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_ObjectFromPoint(ByRef ChildID := "", X := "", Y := "") {
If (X = "") || (Y = "")
DllCall("GetCursorPos", "Int64P", PT)
Else
PT := (X & 0xFFFFFFFF) | ((Y & 0xFFFFFFFF) << 32)
VarSetCapacity(CID, 24, 0)
RC := DllCall("Oleacc.dll\AccessibleObjectFromPoint", "Int64", PT, "PtrP", pAcc, "Ptr", &CID)
ChildID := NumGet(CID, 8, "Ptr")
Return (RC = 0 ? ComObj(9, pAcc, 1) : RC)
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves the localized string that describes the object's role for the specified role value.
; msdn.microsoft.com/en-us/library/windows/desktop/dd318089(v=vs.85).aspx
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_GetRoleText(Role) {
If (Size := DllCall("Oleacc.dll\GetRoleText", "UInt", Role, "Ptr", 0, "UInt", 0)) {
VarSetCapacity(RoleText, Size * 2, 0)
DllCall("Oleacc.dll\GetRoleText", "UInt", Role, "Str", RoleText, "UInt", Size + 1)
Return RoleText
}
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves the name of the object. All objects support this property.
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Name(Acc, ChildID := 0) {
Try
Name := Acc.accName(ChildID)
Catch E
Return Acc_Error(A_ThisFunc, E)
Return Name
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves information that describes the role of the specified object. All objects support this property.
; Role constants: msdn.microsoft.com/en-us/library/dd373608(v=vs.85).aspx
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Role(Acc, ChildID := 0) {
Try
Role := Acc.accRole(ChildID)
Catch E
Return Acc_Error(A_ThisFunc, E)
Return Role
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves the selected children of this object. All objects that support selection must support this property
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Selection(Acc) {
Selection := []
Try
Selected := Acc.accSelection
Catch E
Return Acc_Error(A_ThisFunc, E)
If IsObject(Selected) {
MsgBox, % "Object type: " . ComObjType(Selected)
If !(ComObjType(Selected, "Name") = "IUnknown")
Selection := Acc_EnumVariant(Selected)
Else If (ComObjType(Selected, "Name") = "IAccessible")
Selection.Push(Selected)
Else
Selection.Push(Acc_Query(Selected))
}
Else If (Selected <> "")
Selection.Push(Selected)
Return (Selection.Length() > 0 ? Selection : "")
}
; ==================================================================================================================================
; Auxiliary Functions - Do not call!
; ==================================================================================================================================
; ----------------------------------------------------------------------------------------------------------------------------------
; Loads the Oleacc.dll on start-up
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Load() {
Static AccMod := DllCall("LoadLibrary", "Str", "Oleacc.dll", "UPtr")
Return AccMod
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Enumerates children using the IEnumVariant interface.
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_EnumVariant(pUnk) {
Static Next := A_PtrSize * 3
Try
pEnumVariant := ComObjQuery(pUnk, "{00020404-0000-0000-C000-000000000046}") ; IEnumVariant
Catch E
Return Acc_Error(A_ThisFunc, E)
pVTBL := NumGet(pEnumVariant + 0, "UPtr")
Selection := []
MsgBox, Bingo!
Loop {
VarSetCapacity(V, 24, 0) ; VARIANT structure
Fetched := 0
DllCall(NumGet(pVTBL + Next, "UInt"), 1, "Ptr", &V, "UIntP", Fetched)
If (Fetched = 0)
Break
VarType := NumGet(V, 0, "UShort")
Selected := NumGet(V, 8, VarType = 9 ? "UPtr" : "Int")
If (VarType = 9) {
If (ComObjType(Child, "Name") = "IAccessible")
Selection.Push(Selected)
Else
Selection.Push(Acc_Query(Selected))
}
Else
Selection.Push(Selected)
}
Return Selection.Length() ? Selection : ""
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Reports COM errors, if wanted.
; Set ReportAccError to True for testing.
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Error(Func, E, RetVal := "") {
Static ReportAccError := 1
If (ReportAccError) {
If IsObject(E)
ErrorMsg := "Exception thrown!`n`nWhat: " . E.What . "`nFile: " . E.File . "`nLine: " . E.Line
. "`n`nMessage: " . E.Message . "`n`nExtra: " . E.Extra
Else
ErrorMsg := E
MsgBox, 20, Error in %Func%(), %ErrorMsg%`n`n`Do you want to continue?
IfMsgBox, No
ExitApp
}
Return RetVal
}
; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves the IAccessible interface from an IDispatch interface, if any, and releases the IDispatch interface on success.
; Thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Query(Acc) {
Try
IA := ComObjQuery(Acc, "{618736e0-3c3d-11cf-810c-00aa00389b71}")
Catch E
Return Acc_Error(A_ThisFunc, E)
ObjRelease(Acc)
Return ComObj(9, IA, 1)
}