Related
I want to write a script in autohotkey so that every time I open my dictionary application on PC, keys Windows+LeftArrow being pressed at the same time and as the result, it snaps the windows on the left side of monitor.
I tried this:
#IfWinActive Oxford Advanced Learner's Dictionary
Send, #{Left}
return
Also this one:
#IfWinActive Oxford Advanced Learner's Dictionary
Send, {LWinDown}{Left}{LWinup}
return
But for either of them noting happened when I opened the application.
EDIT:
As suggested by #Charlie Armstrong the real question is: How do I make a block of code run every time I start a certain program? So #IfWinActive might not be useful for.
One way is periodically check if new process/window is created and to check if that is a process/window we want to interact with.
This first example is based on COM notifications when a process has been created/destroyed.
; help for question: https://stackoverflow.com/q/66394326/883015
; by joedf (16:04 2021/02/28)
MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
NewProcess_CheckInterval := 1 ; in seconds
SetTitleMatchMode, 2 ;this might not be needed, makes the check for "contains" instead of "same" winTitle
hWnds := []
gosub, initialize_NewProcessNotification
return
; Called when a new process is detected
On_NewProcess(proc) {
global hWnds
global MyWatchedWindowTitle
; get the window handle, if possible
if (hwnd:=WinExist("ahk_pid " proc.ProcessID)) {
WinGetTitle, wTitle, ahk_id %hwnd%
; check if there is a visible window
if (wTitle)
{
; if so, check if it's a window we want to interact with
if (InStr(wTitle,MyWatchedWindowTitle))
{
; check if we've interacted with this specific window before
if (!ArrayContains(hWnds, hwnd)) {
; we havent, so we do something with it
hWnds.push(hwnd) ; keep in memory that we have interacted with this window ID before.
DoSomething(hwnd) ; the keys we want to send to it
}
}
}
}
}
DoSomething(hwnd) {
; size and move window to the left
SysGet, MonitorWorkArea, MonitorWorkArea
posY := 0
posX := 0
width := A_ScreenWidth // 2
height := MonitorWorkAreaBottom
WinMove, ahk_id %hwnd% ,,%posX%,%posY%,%width%,%height%
; multi-montitor support, more examples, and more complete snapping functions can be found here:
; https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc
}
ArrayContains(haystack, needle) {
for k, v in haystack
{
if (v == needle)
return true
}
return false
}
initialize_NewProcessNotification:
;////////////////////////////// New Process notificaton ////////////////////////
; from Lexikos' example
; https://autohotkey.com/board/topic/56984-new-process-notifier/#entry358038
; Get WMI service object.
winmgmts := ComObjGet("winmgmts:")
; Create sink objects for receiving event noficiations.
ComObjConnect(createSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessCreate_")
ComObjConnect(deleteSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessDelete_")
; Set event polling interval, in seconds.
interval := NewProcess_CheckInterval
; Register for process creation notifications:
winmgmts.ExecNotificationQueryAsync(createSink
, "Select * from __InstanceCreationEvent"
. " within " interval
. " where TargetInstance isa 'Win32_Process'")
; Register for process deletion notifications:
winmgmts.ExecNotificationQueryAsync(deleteSink
, "Select * from __InstanceDeletionEvent"
. " within " interval
. " where TargetInstance isa 'Win32_Process'")
; Don't exit automatically.
#Persistent
return
; Called when a new process is detected:
ProcessCreate_OnObjectReady(obj) {
proc := obj.TargetInstance
/*
TrayTip New Process Detected, % "
(LTrim
ID:`t" proc.ProcessID "
Parent:`t" proc.ParentProcessID "
Name:`t" proc.Name "
Path:`t" proc.ExecutablePath "
Command line (requires XP or later):
" proc.CommandLine
)
*/
On_NewProcess(proc)
}
; Called when a process terminates:
ProcessDelete_OnObjectReady(prm) {
/*
obj := COM_DispGetParam(prm, 0, 9)
proc := COM_Invoke(obj, "TargetInstance")
COM_Release(obj)
TrayTip Process Terminated, % "
(LTrim
ID:`t" COM_Invoke(proc, "Handle") "
Name:`t" COM_Invoke(proc, "Name")
)
COM_Release(proc)
*/
}
This second example, which is perhaps a bit simpler, checks periodically for new windows that match the searched WinTitle.
; help for question: https://stackoverflow.com/q/66394326/883015
; by joedf (16:17 2021/02/28)
#Persistent
MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
SetTitleMatchMode, 2 ;this might not be needed, makes the check for "contains" instead of "same" winTitle
SetTimer, checkForNewWindow, 1000 ;ms
hWnds := []
return
checkForNewWindow() {
global hWnds
global MyWatchedWindowTitle
; first check if there is at least one window that matches our winTitle
if (hwnd:=WinExist(MyWatchedWindowTitle)) {
; get all window matches
WinGet, wArray, List , %MyWatchedWindowTitle%
; loop through all windows that matched
loop % wArray
{
hWnd := wArray%A_Index%
; check if we've interacted with this specific window before
if (!ArrayContains(hWnds, hwnd)) {
; we havent, so we do something with it
hWnds.push(hwnd) ; keep in memory that we have interacted with this window ID before.
DoSomething(hwnd) ; the keys we want to send to it
}
}
}
}
DoSomething(hwnd) {
; size and move window to the left
SysGet, MonitorWorkArea, MonitorWorkArea
posY := 0
posX := 0
width := A_ScreenWidth // 2
height := MonitorWorkAreaBottom
WinMove, ahk_id %hwnd% ,,%posX%,%posY%,%width%,%height%
; multi-montitor support, more examples, and more complete snapping functions can be found here:
; https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc
}
ArrayContains(haystack, needle) {
for k, v in haystack
{
if (v == needle)
return true
}
return false
}
I think your biggest issue is that AHK doesn't seem to work well for snapping windows (according to my quick research and testing). What does work well, though, is WinMove.
I assume you're launching the program from a shortcut icon, but I would suggest using a keyboard shortcut that launches the program and then positions the window from the script. Here is some sample code that opens Notepad2.exe, waits for 200 milliseconds, and then moves the window and resizes it:
^+!n:: ; Control+Shift+Alt+N to Open Notepad
Run C:\Program Files\Notepad2\Notepad2.exe
sleep, 200
WinMove, Notepad2,, 10, 20, 800, 600
return
When pressing "Ctr+C" while selecting some files in the explorer, their paths are saved in the clipboard and when later pressing "Ctr+V" the files are pasted. For an AutoHotkey script I need to edit these paths in the clipboard, so the explorer pastes other files in the location of the "Ctr+V" press. So for example I want to select the file "A.txt" in "C:\Folder1" with "Ctr+C", then activate the AutoHotkey script to change the stored information in the clipboard of "A.txt" to the information about another file "B.txt", so when pressing "Ctr+V" in "C:\Folder2" the explorer copies "B.txt" instead of "A.txt".
But I have no idea how the paths of "Ctr+C" are exactly stored in the clipboard and I found no useful documentation. Different programms to access the content of the clipboard give one of the three results: 1) [Absolute nothing] 2) "C://A.txt" 3) "file:///C:/A.txt". But when editing the clipboard to "C://B.txt" or "file:///C:/B.txt" I got no reaction of the file explorer when using "Ctr+V".
So how are the paths of copied files exactly stored in the clipboard and with which programm I could edit them?
Edit: Following expamle to explain exactly what my goal is: Suppose I have a file "A.txt" in path 1, which I want to move to path 2 and another file "B.txt" in path 3, which I want to move to path 4. The normal procedure would be:
1) Copy "A.txt" with "Ctr+C" in path 1.
2) Paste "A.txt" with "Ctr+V" in path 2.
3) Copy "B.txt" with "Ctr+C" in path 3.
4) Paste "B.txt" with "Ctr+V" in path 4.
The goal of my AutoHotkey script is to allow the following alternative:
1) Copy "A.txt" with "Ctr+C+1" in path 1.
2) Copy "B.txt" with "Ctr+C+2" in path 2.
3) Paste "A.txt" with "Ctr+V+1" in path 1.
4) Paste "B.txt" wiht "Ctr+V+2" in path 2.
At first glance it might seem unnecessary, but when organising a lot of files in more complex system, it would be really convenient for me. Ideally, it should also work when I add "C.txt", "D.txt", ... to be saved in the third/fourth/... clipboard slot and even when instead of "A.txt" I want to store multiple files in one clipboard slot; later I also want to implement "Ctr+X+[n]" to cut files.
I experimented a lot and was able to save the different paths of the files from the clipboard to AutoHotkey variables. But now I have to load the paths, which are stored in the AutoHotkey variables back to the clipboard, so the corresponding files are pasted with the explorer.
So just for an example: My AutoHotkey script detects the keyboard input "Ctr+C+1" while I select A.txt in the file explorer, then sends the computer the shorcut "Ctr+C" to store the path of A.txt in the clipboard and finally saves this path as "C:/A.txt" in the AutoHotkey varibale "clip1". Then I select B.txt in the file explorer, press "Ctr+C+2", so the AutoHotkey script presses "Ctr+C" to get the file paths into the Windows clipboard and then saves ít as "C:/B.txt" in "clip2". Now I press "Ctr+V+1", so the AutoHotkey script should write the path from the variable "clip1" back in the Windows, then press "Ctr+V" to paste the file in the explorer. But the really problem is now, that it is not enough to just edit the Windows clipboard to "C:/A.txt". Then so the explorer doesnt react to the input "Ctr+V", for which he should paste the file. So, the Windows clipboard has to be edited in another format, like for example "#explorer_file:///C:/A.txt" (just a complete stupid guess, since I have no idea how it looks). I need to find this format, so my AutoHotkey script can edit the currently saved paths to another paths.
I hope that explains all confusion about this confusing problem.
I'd use something like this:
#NoEnv
#SingleInstance Force
; Create a GUI with checkboxes to save the path of the last copied files and
; copy/move selected items to another directory opened in explorer:
OnClipboardChange("files_copied")
return
files_copied(type){
global
If (type == 1) ; the Clipboard contains text or files copied
{
; https://autohotkey.com/board/topic/150291-detect-clipboard-contents-as-text-file-etc/#entry735751
If (DllCall("IsClipboardFormatAvailable", "uint", 15)) ; the Clipboard contains files
{
ToolTip, file(s) copied
Gui, destroy
Gui, Color, ControlColor, Black
Gui, Font, CDefault, Lucida Console
Gui, Add, Button, x30 y5 w100 h26 gCopy ,Copy
Gui, Add, Button, x230 y5 w100 h26 gMove ,Move
Gui, Add, CheckBox, x20 y50 vCh200 gCheckAll cYellow, Select All
Gui, Add, CheckBox, x20 y75 vCh201 gUnCheckAll cYellow, De-Select All
Loop, Parse, Clipboard, `n, `r
{
y_pos := 100 + (A_Index * 25)
Gui, Add, CheckBox, x20 y%y_pos% vCh%A_Index% cYellow, %A_LoopField%
I := A_Index ; number of copied files
}
Gui_height := 125+I*25
Gui, Show, x100 y5 w400 h%Gui_height%, Files copied ; comment out this line if you want to only show the Gui after pressing F1
Sleep 1000
ToolTip
}
}
}
; Press F1 to show the Gui if it's hidden
F1:: Gui, Show
; or If the command in the above function is commented out
; F1:: Gui, Show, x100 y5 w400 h%Gui_height%, Files copied
CheckAll:
Loop, %I%
GuiControl,, Ch%A_Index%, 1
GuiControl,, Ch200, 1
GuiControl,, Ch201, 0
return
UnCheckAll:
Loop, %I%
GuiControl,, Ch%A_Index%, 0
GuiControl,, Ch200, 0
GuiControl,, Ch201, 1
return
Copy:
Gui, submit, nohide
If !WinExist("ahk_class CabinetWClass") ; explorer
{
MsgBox, No explorer window exists
return
}
WinActivate, ahk_class CabinetWClass
WinWaitActive, ahk_class CabinetWClass, ,2
If (ErrorLevel)
{
MsgBox, explorer could not be activated
return
}
ExplorerPath := GetActiveExplorerPath()
Loop %I%
{
GuiControlGet, checked,, Ch%A_Index%, Value
If (checked = 1) ; if the control is checked
{
GuiControlGet, file,, Ch%A_Index%, Text
FileCopy, %file%, %ExplorerPath%\, 1 ; overwrite existing files
}
}
return
Move:
Gui, submit, nohide
If !WinExist("ahk_class CabinetWClass") ; explorer
{
MsgBox, No explorer window exists
return
}
WinActivate, ahk_class CabinetWClass
WinWaitActive, ahk_class CabinetWClass, ,2
If (ErrorLevel)
{
MsgBox, explorer could not be activated
return
}
ExplorerPath := GetActiveExplorerPath()
MsgBox, 262180, Move Files, Are you sure you want to move the selected files to`n`n%ExplorerPath%?
IfMsgBox No
return
New_Clipboard := ""
Loop %I%
{
GuiControlGet, checked,, Ch%A_Index%, Value
If (checked = 1) ; if the control is checked
{
GuiControlGet, file,, Ch%A_Index%, Text
FileMove, %file%, %ExplorerPath%\, 1 ; overwrite existing files
}
else
{
GuiControlGet, file,, Ch%A_Index%, Text
New_Clipboard .= file . "`n" ; concatenate the outputs
}
}
If (New_Clipboard = "")
Gui, destroy
else
ClipboardSetFiles(New_Clipboard, DropEffect := "Copy")
return
GuiClose:
Gui, Hide
return
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=69925
GetActiveExplorerPath()
{
explorerHwnd := WinActive("ahk_class CabinetWClass")
if (explorerHwnd)
{
for window in ComObjCreate("Shell.Application").Windows
{
if (window.hwnd==explorerHwnd)
{
return window.Document.Folder.Self.Path
}
}
}
}
; https://autohotkey.com/boards/viewtopic.php?p=63914#p63914
ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {
; FilesToSet - list of fully qualified file pathes separated by "`n" or "`r`n"
; DropEffect - preferred drop effect, either "Copy", "Move" or "" (empty string)
Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
; Count files and total string length
TotalLength := 0
FileArray := []
Loop, Parse, FilesToSet, `n, `r
{
If (Length := StrLen(A_LoopField))
FileArray.Push({Path: A_LoopField, Len: Length + 1})
TotalLength += Length
}
FileCount := FileArray.Length()
If !(FileCount && TotalLength)
Return False
; Add files to the clipboard
If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
; HDROP format
; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
Offset := 20
NumPut(Offset, pDrop + 0, "UInt") ; DROPFILES.pFiles = offset of file list
NumPut(!!A_IsUnicode, pDrop + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
For Each, File In FileArray
Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
DllCall("GlobalUnlock", "Ptr", hDrop)
DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop) ; 0x0F = CF_HDROP
; Preferred DropEffect format
If (DropEffect := DropEffects[DropEffect]) {
; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
pMem := DllCall("GlobalLock", "Ptr", hMem)
NumPut(DropEffect, pMem + 0, "UChar")
DllCall("GlobalUnlock", "Ptr", hMem)
DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
}
DllCall("CloseClipboard")
Return True
}
Return False
}
I use below script to get Imagepath from IrfanView and go to Excel cell that contains Imagepath.
;Excel Column name that contains imagename
ImageColumn=A
;handle to running application
try XL := ComObjActive("Excel.Application")
; Create COM If no Excel is running
Catch {
MsgBox % "no existing Excl object: Need to create one"
XL := ComObjCreate("Excel.Application")
}
;Get ImagePath from Free image viewer Irfanview image properties dialog
ControlGetText, ImagePath, Edit3, IrfanView - Image properties
;And close the dialog
PostMessage, 0x112, 0xF060,,, IrfanView - Image properties
;Loop until Excel activate to workaround for excel randomly not get active state
Loop
{
WinActivate, ahk_exe EXCEL.EXE
IfWinActive, ahk_exe EXCEL.EXE
Break
Sleep 200
}
;Get Excel activecell
DataColNum:=XL.Activecell.Column
;Make COM obj visible to ensure visibility
XL.Application.ActiveWindow.Visible := 1
;Find ImageName in the column
XL.Application.ActiveSheet.Range(XL.Cells(Floor(XL.Application.WorkSheetFunction.Match(ImagePath,XL.Application.ActiveSheet.Range(ImageColumn . ":" . ImageColumn),0)),DataColNum).Address).Activate
But this script randomly misses to make the Excel window visible to our eyes i.e. Activecell still receives input from keyboard but the window is invisible.
I use autohotkey version: 1.0.48.05 (because I stick with activeaid).
The script to read the current path is as follows (and worked until Win 7).
; Get full path from open Explorer window
WinGetText, FullPath, A
; Clean up result
StringReplace, FullPath, FullPath, `r, , all
FullPath := RegExReplace(FullPath, "^.*`nAddress: ([^`n]+)`n.*$", "$1")
How I suspect that while switching to Win10 it seems that I also switched the language.
If I MsgBox out the %FullPath% before cleaning with
WinGetText, FullPath, A
MsgBox %FullPath%
I see amongst other strings (obvoíously separated by CR):
Adresse: V:\Vertrieb\Prospects\MyFile
so how do I need to adjust the regexp to extract that very string!
Best regards
Hannes
#IfWinActive, ahk_class CabinetWClass ; explorer
F1:: MsgBox, % GetActiveExplorerPath()
; or
F2::
ActiveExplorerPath := GetActiveExplorerPath()
MsgBox, % ActiveExplorerPath
return
#IfWinActive
GetActiveExplorerPath() {
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=69925
explorerHwnd := WinActive("ahk_class CabinetWClass")
if (explorerHwnd)
{
for window in ComObjCreate("Shell.Application").Windows
{
if (window.hwnd==explorerHwnd)
return window.Document.Folder.Self.Path
}
}
}
Try:
f1::MsgBox % Explorer_GetSelection()
Explorer_GetSelection(hwnd="") {
WinGet, process, processName, % "ahk_id" hwnd := hwnd? hwnd:WinExist("A")
WinGetClass class, ahk_id %hwnd%
if (process = "explorer.exe")
if (class ~= "(Cabinet|Explore)WClass") {
for window in ComObjCreate("Shell.Application").Windows
if (window.hwnd==hwnd)
path := window.Document.FocusedItem.path
SplitPath, path,,dir
}
return dir
}
It takes me so much time to find the best solution (for me).
Maybe it will work for you as well.
ControlClick, ToolbarWindow323, A
ControlGetText, path, Edit1, A
Msgbox, %path%
I'm using Firefox and I was looking for an autohotkey script which would enable me to skip the whole series of clicks when I bookmark a page in a specific folder and replace it with a single keyboard shortcut.
Although I've read forum threads on Autohotkey forum and here I still don't know how to make a working script that would reduce bookmarking a page to hitting a keyboard shortcut and the initial letter of the folder where I want to store that page. Using KeyWait command I've made it work for a single folder and don't know how to make it work for any letter or a number that I could possibly use as a name for a bookmark folder. Say I have a folder named XXXX, this script does send the webpage to the XXXX folder after hitting the assigned shortcut and the letter x (MouseClick command is needed to focus the window with folder in the Bookmark Dialog pane):
!+^w::
Send,^d
Sleep,400
MouseClick,Left,864,304
Sleep,400
KeyWait, x ,D
Sleep, 400
Send,^{Enter}
return
I don't know how to make this script work for any letter or number, not only for a single one. Also a big problem with this script is that it blocks the keyboard until I hit X key. If I have that page bookmarked already, hitting escape to remove the bookmark pane will block the keyboard and I can unblock it only if I rerun the autohotkey script.
I've also tried using Input command as the contributors the Autohotkey forum pages suggested, but it didn't work either, because I don't understand how the Input command works. I did make it work for a single letter as the above script with KeyWait, but that's the best I could do. This script also blocks the keyboard until the letter is hit:
!+^w::
Send,^d
MouseClick,Left,864,304
Sleep,400
Input, Character, L1
If Character = t
Send, t
Sleep,400
Send,^{Enter}
return
Hope someone can help me with this, it would be convenient simplifying the bookmarking process in Firefox this way.
I have a nice idea. This will open the add bookmark dialog and navigate you into the folder selection part and expand all folders.
All you need to do is enter the folders name (or a part of it) and it will get selected automatically. When you're done, just hit enter.
!+^w:: ;Hotkey: Ctrl+Alt+Shift+w
Send, ^d ;send Ctrl+d to open the add-bookmark dialog
Sleep, 500 ;wait for the dialog to open
Send, {Tab}{Tab}{Enter} ;navigate into the folder selection
Sleep, 300 ;wait to make sure we are there
Send,{Home} ;select the first item in the list
;The following line should expand all the folders so that you can just type the folders name to search for it
Loop, 100 { ;Increase the number if it doesn't expand all folders
SendInput, {Right}{Down} ;expand folders
}
Send, {Home} ;navigate to the first item in the list again
Input, L, V L1 T2 ;wait until you start typing a folder name (if you just wait 2 seconds, the bookmark won't be created)
If (ErrorLevel = "Timeout") {
Send, {Tab 5} ;press tab 5 times to navigate to the cancel button
Send, {Enter} ;cancel the bookmark
Return ;end of the hotkey
}
Loop { ;wait until you haven't typed a new letter for 0.4 seconds
Input, L, V L1 T0.4
If (ErrorLevel = "Timeout")
Break
}
Send, {Tab 4} ;press tab 4 times to navigate to the enter button
Send, {Enter} ;save the bookmark
Return
My variant.
Press f1 to create bookmark in folder test1.
Press f2 to create bookmark in folder test2.
SetBatchLines, -1
Folders := {F1: "test1", F2: "test2"}
#IfWinActive, ahk_class MozillaWindowClass
F1::
F2::
Folder := Folders[A_ThisHotkey]
Send, ^d
AccFirefox := Acc_ObjectFromWindow(WinExist("ahk_class MozillaWindowClass"))
AccElem := SearchElement(AccFirefox, ROLE_SYSTEM_LISTITEM := 0x22, Folder, "")
AccElem.accDoDefaultAction(0)
sleep 100
Send {Enter}
msgbox done
return
#IfWinActive
SearchElement(ParentElement, params*)
{
found := 1
for k, v in params {
(k = 1 && ParentElement.accRole(0) != v && found := "")
(k = 2 && ParentElement.accName(0) != v && found := "")
(k = 3 && ParentElement.accValue(0) != v && found := "")
}
if found
Return ParentElement
for k, v in Acc_Children(ParentElement)
if obj := SearchElement(v, params*)
Return obj
}
Acc_Init()
{
Static h
If Not h
h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromWindow(hWnd, idObject = 0)
{
Acc_Init()
If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
Return ComObjEnwrap(9,pacc,1)
}
Acc_Query(Acc) { ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
static setting:=0
return p=""?setting:setting:=p
}
Acc_Children(Acc) {
if ComObjType(Acc,"Name") != "IAccessible"
ErrorLevel := "Invalid IAccessible Object"
else {
Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
Loop %cChildren%
i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
return Children.MaxIndex()?Children:
} else
ErrorLevel := "AccessibleChildren DllCall Failed"
}
if Acc_Error()
throw Exception(ErrorLevel,-1)
}